Class inheritance for PyQt

1,173 views
Skip to first unread message

Benjam901

unread,
Mar 5, 2015, 3:14:22 AM3/5/15
to python_in...@googlegroups.com
Hello all,

I am having a few issues with my class inheritance in PyQt.

I am writing an application that has a rather large dialog with lots of different panels that perform different operations and require different setups. To keep it as clean as I could I decided I should create separate classes for the separate panels.

The issue I am having is passing a class instance across classes.

In my MainWindowSetup class I create an instance of the PyQt window and set it up, this shows the dialog and all the panels etc. I then create an instance of my ModelWindow inside my MainWindowSetup but I cannot seem to access the functionality from within the PyQt window from my ModelWindow class.

The error I get is:
AttributeError: 'ModelWindow' object has no attribute 'uiMainWindow'

I am rather confused, as by creating the instance of my MainWindowSetup class shouldn't the ModelWindow class become a child of the MainWindowSetup and by doing so I should be able to access the PyQt window properties?

Or is it that I am missing some fundamental class inheritance knowledge? I can keep coding as I can setup my panels for the moment inside my MainWindowSetup class but further down the line it will get messy to keep everything to one class

Here is my code thus far:

class MainWindowSetup(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
 
self.uiMainWindow = Ui_MainWindow()
self.uiMainWindow.setupUi(self)
self.uiModelWindow = ModelWindow()
class ModelWindow(QtGui.QTreeWidget):
def __init__(self):
print "!! Initialised model window"
QtGui.QTreeWidget.__init__(self)

self.modelTree = self.uiMainWindow.uiModelTree # This is where I get the error

Thanks for any help!

Cheers,

Ben

Marcus Ottosson

unread,
Mar 5, 2015, 3:29:23 AM3/5/15
to python_in...@googlegroups.com
self.modelTree = self.uiMainWindow.uiModelTree # This is where I get the error

self is referring to your instance of ModelWindow, but you store uiMainWindow in the instance of MainWindowSetup.

If you want to access that, you’ll need to pass a handle to it. It’s typically done using a parent, but you aren’t including the parent in your __init__ method.

Try something like this.

class MainWindowSetup(QtGui.QMainWindow):
    def __init__(self):
        QtGui.QMainWindow.__init__(self)

        self.uiMainWindow = Ui_MainWindow()
        self.uiMainWindow.setupUi(self)
        self.uiModelWindow = ModelWindow(self)

class ModelWindow(QtGui.QTreeWidget):
    def __init__(self, parent):

        print "!! Initialised model window"

        QtGui.QTreeWidget.__init__(self, parent)

        self.modelTree = parent.uiMainWindow.uiModelTree # This is where I get the error

Benjam901

unread,
Mar 5, 2015, 3:36:06 AM3/5/15
to python_in...@googlegroups.com
Hello Marcus,

Thank you for the speedy response it worked like an absolute charm! 

Cheers,

Ben
Message has been deleted

Justin Israel

unread,
Mar 5, 2015, 5:08:53 AM3/5/15
to python_in...@googlegroups.com
Generally I would say it is a questionable design if you have child classes that make assumptions about the members of the parent. It means that your child class can only be used with that specific parent class that will have the expected attributes. If your child class needs to trigger behavior in the parent, a better design would be to have your child class emit signals. This should give you a cleaner separation between the two widgets. It then becomes the responsibility of your parent window to connect to the signals of interest, and perform the required actions as it is notified. 


On Thu, Mar 5, 2015 at 10:27 PM Benjam901 <benandr...@gmail.com> wrote:
Hello again Marcus,

I was wondering why intellisense does not pick up on the internal variables and buttons etc. do I need to add another handle?

Cheers,

Ben

On Thursday, 5 March 2015 09:29:23 UTC+1, Marcus Ottosson wrote:
--
You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/python_inside_maya/065722da-82df-4108-92d5-6c76844d0696%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Benjam901

unread,
Mar 5, 2015, 1:22:12 PM3/5/15
to python_in...@googlegroups.com
Hello Justin,

I am having some solid trouble with my recursive function trying to add QTreeWidgetItems to the tree hierarchy. The loop continues on and then gets to a certain point and this error pops up when I try to access a recursedItem in the list.

RuntimeError: underlying C/C++ object has been deleted

Could this have something to do with the design issues you were talking about? I have done some digging and read that python wrappers are left behind or I havent called my init function somewhere?

Here is my function:

def setupModelTree(self):
import UnitManager.scripts.read_model_file as readModel
treeObjects = readModel.testRead()
addedToList = []
recurseRoots = []
recurseInnerRoots = []
recurseNo = -1
 
# Iterate through the dictionary returned by the read model file function
for name in treeObjects:
 
# Get the root point and add it to the root of the tree
if name.startswith("rp_"):
rootName = name
rootItem = QtGui.QTreeWidgetItem([name])
recurseRoots.append(rootItem)
self.modelTree.addTopLevelItem(rootItem)
del treeObjects[name] # Remove the RP from the dictionary
addedToList.append(name)
break
 
def recurseAddChildren(dict, iterList, recursiveItems):
newlyAdded = []
recurseInnerRoots = []
 
# Iterating through through last added items layer
for recursedItem in recursiveItems:
addChildren = []
toDelete = []
""" @type recursedItem: QtGui.QTreeWidget.QTreeWidget """
if iterList[0] != rootName:
for d in dict:
if dict.get(d) == recursedItem.text(0): # Error line
toDelete.append(d)
addChildren.append(QtGui.QTreeWidgetItem([d]))
 
self.deleteDictElements(dict, toDelete)
 
for toBeAdded in addChildren:
childItem = QtGui.QTreeWidgetItem(toBeAdded)
recursedItem.addChild(childItem)
 
newlyAdded.append(toBeAdded.text(0))
recurseInnerRoots.append(childItem)
self.deleteDictElements(dict, toBeAdded.text(0))
 
if len(iterList) < 1:
print "errored"
break
else:
print "Adding first layer"
for name in dict:
parent = [item for item in iterList if item == dict.get(name)]
 
# If the parent exists
if parent:
childToAdd = QtGui.QTreeWidgetItem([name])
 
recursedItem.addChild(childToAdd)
newlyAdded.append(name)
recurseInnerRoots.append(childToAdd)
 
dict = self.deleteDictElements(dict, newlyAdded)
 
# KEEP OUTSIDE MAIN LOOP
if len(dict) > 0:
recurseAddChildren(dict, newlyAdded,recurseInnerRoots)
 
recurseAddChildren(treeObjects, addedToList, recurseRoots)
print "Model panel set up"
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_maya+unsub...@googlegroups.com.

Justin Israel

unread,
Mar 5, 2015, 2:15:23 PM3/5/15
to python_in...@googlegroups.com

This would be an unrelated problem to the previously mentioned design issue. What it looks like to me is that you are a deleting recursedItem (TreeWidgetItem) but leaving a reference to it in your container and then calling text() again on it at a later recursion. Probably need to make sure that whatever you are deleting is no longer in the dict.

Also, I am not sure why this part doesn’t give you errors, but it seems like you are changing a dictionary size while looping over it:

# Iterate through the dictionary returned by the read model file function
for name in treeObjects:
    # Get the root point and add it to the root of the tree
    if name.startswith("rp_"
):
        ...
        
del treeObjects[name] # Remove the RP from the dictionary

Normally I would expect that to be an error, since if you plan to add and remove to a dict while looping over it, you should loop over a copy.

To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/python_inside_maya/bb4a178c-06a0-4f08-9aba-6e028573ebd0%40googlegroups.com.

Ben Hearn

unread,
Mar 5, 2015, 3:46:58 PM3/5/15
to python_in...@googlegroups.com
Ahh. The reason I don't get an error is because of the break. As soon at the master root is found the loop is stopped and the rest of the function is carried on. I will take a look into where I have deleted the object by kept the reference and will post my results if all goes well (or not so well). If I have indeed deleted the item but left the reference could this be the function parameter referencing it and the actual list being reset?
You received this message because you are subscribed to a topic in the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/python_inside_maya/_aEnlsC_60Q/unsubscribe.
To unsubscribe from this group and all its topics, send an email to python_inside_m...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/python_inside_maya/CAPGFgA2c_fHfxS4bhbdGwggRq8P5rfDzkSE9-%2Be8L%2BeRY2Phzg%40mail.gmail.com.

For more options, visit https://groups.google.com/d/optout.


--

Tel - +46 76245 92 90 (Sweden)

Justin Israel

unread,
Mar 5, 2015, 4:31:22 PM3/5/15
to python_in...@googlegroups.com

Right ya I missed the break. It would only error if it did another loop.

I'm not sure what is really going on here but  it is accessing an item in your list that Qt has cleaned up for whatever reason. Could even be a child of an item that was deleted.


Ben Hearn

unread,
Mar 5, 2015, 5:17:40 PM3/5/15
to python_in...@googlegroups.com
Ok I'll take a good look at the function tomorrow and will post up how I get on. Thanks for the help again it's much appreciated
To view this discussion on the web visit https://groups.google.com/d/msgid/python_inside_maya/CAPGFgA1ZzsFxuM4dABc-1rHeofCfcdQtGnKiJTEbj5oa-0C91Q%40mail.gmail.com.

For more options, visit https://groups.google.com/d/optout.

Ben Hearn

unread,
Mar 6, 2015, 5:07:29 AM3/6/15
to python_in...@googlegroups.com
Hello,

So I had another look at it this morning and I have found out where I have gone wrong. Inside my inner loop on the second run round I was creating an addChildren list of QTreeWidgetItems to iterate over. 
I was then creating a childItem QTreeWidgetItem out of the item being iterated over in the list which was already a TreeItem so in turn creating a QtreeWidgetItem and passing in a QTreeWidgetItem instead of a list string. 

I am not sure on the specifics as to why I got the error but I fixed the line and the function works as intended.

Here is the newly revised lines: The ones commented out with childItem as the parameter are the ones that caused me the errors.

for recursedItem in recursiveItems:
addChildren = []
toDelete = []
addMultiple = 0
if iterList[0] != rootName:
print "In inner loop", recursedItem.text(0)
 
for d in dict:
if dict.get(d) == recursedItem.text(0):
print "We have a parent: ", recursedItem.text(0)
toDelete.append(d)
addChildren.append(QtGui.QTreeWidgetItem([d]))
 
self.deleteDictElements(dict, toDelete)
 
for toBeAdded in addChildren:
 
print "Adding child item", toBeAdded.text(0), recursedItem.text(0)
#childItem = QtGui.QTreeWidgetItem(toBeAdded)
#recursedItem.addChild(childItem)
recursedItem.addChild(toBeAdded)
 
newlyAdded.append(toBeAdded.text(0))
#recurseInnerRoots.append(childItem)
recurseInnerRoots.append(toBeAdded)
self.deleteDictElements(dict, toBeAdded.text(0))

Thanks for the help, an epic Google group

Justin Israel

unread,
Mar 6, 2015, 5:42:01 AM3/6/15
to python_in...@googlegroups.com

I'm not totally certain, but it may specifically be related to creating that temporary item, and then creating a child by passing it to the constructor of the new item, but then passing that as a child of the recursive item. Something was deleting it from that faulty parent child logic. But I am glad you solved it!


Reply all
Reply to author
Forward
0 new messages