pythonpyqt4qtreewidgetqtreewidgetitemqtxml

Calling a class to build a QTreeWidget within a Window: argument 1 has unexpected type 'Ui_MainWindow'


I'm using code that I got from ekhumoro to dynamically create a tree from an xml file for a GUI that I've created, however when attempting to call the class inside the _ui.py file generated from pyuic4 I'm getting the Ui_MainWindow class returned instead of the expected argument.

XmlHandler, which creates the tree items (from my understanding):

from PyQt4 import QtCore, QtGui, QtXml
from PyQt4.QtXml import *


class XmlHandler(QXmlDefaultHandler):
    def __init__(self, root):
        QtXml.QXmlDefaultHandler.__init__(self)
        self._root = root
        self._item = None
        self._text = ''
        self._error = ''

    def startElement(self, namespace, name, qname, attributes):
        if qname == 'Machine' or qname == 'Feature':
            if self._item is not None:
                self._item = QtGui.QTreeWidgetItem(self._item)
            else:
                self._item = QtGui.QTreeWidgetItem(self._root)
            self._item.setData(0, QtCore.Qt.UserRole, qname)
            self._item.setText(0, 'Unknown Machine')
            if qname == 'Machine':
                self._item.setExpanded(False)
                self._item.setCheckState(0, QtCore.Qt.Unchecked)
                self._item.setFlags(QtCore.Qt.ItemIsSelectable|QtCore.Qt.ItemIsDragEnabled|QtCore.Qt.ItemIsUserCheckable|QtCore.Qt.ItemIsEnabled|QtCore.Qt.ItemIsTristate)
            elif qname == 'FeatureName':
                self._item.setText(1, self._text)
        self._text = ''
        return True

    def endElement(self, namespace, name, qname):
        if qname == 'FeatureName' or qname == 'MachineName':
            if self._item is not None:
                self._item.setText(0, self._text)
                self._item.setCheckState(0, QtCore.Qt.Unchecked)
        elif qname == 'Feature' or qname == 'Machine':
            self._item = self._item.parent()
        return True

    def characters(self, text):
        self._text += text
        return True

    def fatalError(self, exception):
        print('Parse Error: line %d, column %d:\n  %s' % (
              exception.lineNumber(),
              exception.columnNumber(),
              exception.message(),
              ))
        return False

The Class that uses XmlHandler to make the widget:

class MakeWidget(QtGui.QTreeWidget):
    def __init__(self):
        QtGui.QTreeWidget.__init__(self)
        self.header().setResizeMode(QtGui.QHeaderView.Stretch)
        self.setHeaderLabels(['Servers and Services'])
        source = QtXml.QXmlInputSource()
        source.setData(xml)
        handler = XmlHandler(self)
        reader = QtXml.QXmlSimpleReader()
        reader.setContentHandler(handler)
        reader.setErrorHandler(handler)
        reader.parse(source)

Me fumbling around and attempting to use it in my GUI:

class Ui_MainWindow(object):

    def setupUi(self, MainWindow):
        MainWindow.setObjectName(_fromUtf8("MainWindow"))
        MainWindow.resize(950, 500)
        sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(MainWindow.sizePolicy().hasHeightForWidth())
        MainWindow.setSizePolicy(sizePolicy)
        MainWindow.setMaximumSize(QtCore.QSize(950, 500))
        self.centralwidget = QtGui.QWidget(MainWindow)
        self.centralwidget.setObjectName(_fromUtf8("centralwidget"))
        self.tabWidget = QtGui.QTabWidget(self.centralwidget)
        self.tabWidget.setGeometry(QtCore.QRect(0, 0, 960, 421))
        sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.tabWidget.sizePolicy().hasHeightForWidth())
        self.tabWidget.setSizePolicy(sizePolicy)
        self.tabWidget.setMaximumSize(QtCore.QSize(960, 430))
        self.tabWidget.setAutoFillBackground(True)
        self.tabWidget.setStyleSheet(_fromUtf8(""))
        self.tabWidget.setObjectName(_fromUtf8("tabWidget"))
        self.tabLogPuller = QtGui.QWidget()
        self.tabLogPuller.setObjectName(_fromUtf8("tabLogPuller"))
        self.groupBoxServiceSelection = QtGui.QGroupBox(self.tabLogPuller)
        self.groupBoxServiceSelection.setGeometry(QtCore.QRect(0, 0, 381, 351))
        font = QtGui.QFont()
        font.setBold(False)
        font.setWeight(50)
        self.groupBoxServiceSelection.setFont(font)
        self.groupBoxServiceSelection.setAutoFillBackground(True)
        self.groupBoxServiceSelection.setObjectName(_fromUtf8("groupBoxServiceSelection"))
        self.treeServiceSelection = MakeWidget()
        self.treeServiceSelection.setHeaderLabels(['Servers and Services'])
        self.treeServiceSelection.source = QtXml.QXmlInputSource()
        self.treeServiceSelection.source.setData(xml)
        self.treeServiceSelection.handler = XmlHandler(self)
        self.treeServiceSelection.reader = QtXml.QXmlSimpleReader()
        self.treeServiceSelection.reader.setContentHandler(self.treeServiceSelection.handler)
        self.treeServiceSelection.reader.setErrorHandler(self.treeServiceSelection.handler)
        self.treeServiceSelection.reader.parse(self.treeServiceSelection.source)
        self.treeServiceSelection.setGeometry(QtCore.QRect(10, 80, 161, 261))
        self.treeServiceSelection.setObjectName(_fromUtf8("treeServiceSelection"))

And the errors that I get when attempting to run the file:

error triggered by consumer
    self._item = QtGui.QTreeWidgetItem(self._root)
TypeError: arguments did not match any overloaded call:
  QTreeWidgetItem(int type=QTreeWidgetItem.Type): argument 1 has unexpected type 'Ui_MainWindow'
  QTreeWidgetItem(list-of-str, int type=QTreeWidgetItem.Type): argument 1 has unexpected type 'Ui_MainWindow'
  QTreeWidgetItem(QTreeWidget, int type=QTreeWidgetItem.Type): argument 1 has unexpected type 'Ui_MainWindow'
  QTreeWidgetItem(QTreeWidget, list-of-str, int type=QTreeWidgetItem.Type): argument 1 has unexpected type 'Ui_MainWindow'
  QTreeWidgetItem(QTreeWidget, QTreeWidgetItem, int type=QTreeWidgetItem.Type): argument 1 has unexpected type 'Ui_MainWindow'
  QTreeWidgetItem(QTreeWidgetItem, int type=QTreeWidgetItem.Type): argument 1 has unexpected type 'Ui_MainWindow'
  QTreeWidgetItem(QTreeWidgetItem, list-of-str, int type=QTreeWidgetItem.Type): argument 1 has unexpected type 'Ui_MainWindow'
  QTreeWidgetItem(QTreeWidgetItem, QTreeWidgetItem, int type=QTreeWidgetItem.Type): argument 1 has unexpected type 'Ui_MainWindow'
  QTreeWidgetItem(QTreeWidgetItem): argument 1 has unexpected type 'Ui_MainWindow'

So I guess that my question is: How do I call this class and pass the correct arguments inside the UI_MainWindow class instead of calling what I'm assuming is the parent?


Solution

  • You create an instance of MakeWidget here:

        self.treeServiceSelection = MakeWidget()
    

    which then sets up the XmlReader and so forth in its __init__. But, mysteriously, you then attempt to repeat it all in the following lines:

        self.treeServiceSelection.setHeaderLabels(['Servers and Services'])
        self.treeServiceSelection.source = QtXml.QXmlInputSource()
        self.treeServiceSelection.source.setData(xml)
        ...
    

    What are you trying do here? If you need to adjust the initialization of the MakeWidget class, modify the code in its __init__.

    The actual error is caused by this line:

        self.treeServiceSelection.handler = XmlHandler(self)
    

    which passes an instance of Ui_MainWindow to the constructor for XmlHandler when it requires an instance of QTreeWidget. But as indicated previously, that is actually irrelevant, because all of the code that follows the first line is redundant anyway.

    It seems that the more fundamental problem is that you are attempting to directly edit the ui file generated by pyuic instead of importing into your application. The generated ui file should be treated as read-only. Never, ever, be tempted to edit it.

    Instead, you need to create a module containing a main window class that does something like this:

    from ui import Ui_MainWindow
    
    class MainWindow(QtGui.QMainWindow):
        def __init__(self):
            QtGui.QMainWindow.__init__(self)
            ui = Ui_MainWindow()
            ui.setupUi(self)
            # other setup code goes here
            ...
    

    I would also suggest that you modify the MakeWidget class to something like this:

    class MakeWidget(QtGui.QTreeWidget):
        def __init__(self, xml, parent=None):
            QtGui.QTreeWidget.__init__(self, parent)
    

    so that you can create an instance of it in MainWindow.__init__ like this:

            self.treeServiceSelection = MakeWidget(xml, self)
    

    or possibly factor the xml parsing code out into a method that takes the xml as an argument.