Cryptite
Cryptite

Reputation: 1466

Proper parenting of QWidgets generated from a QThread to be inserted into a QTreeWidget

I have a QTreeWidget which needs to be populated with a large sum of information. So that I can style it and set it up the way I really wanted, I decided I'd create a QWidget which was styled and dressed all pretty-like. I would then populate the TreeWidget with generic TreeWidgetItems and then use setItemWidget to stick the custom QWidgets in the tree. This works when the QWidgets are called inside the main PyQt thread, but since there is a vast sum of information, I'd like to create and populate the QWidgets in the thread, and then emit them later on to be added in the main thread once they're all filled out. However, when I do this, the QWidgets appear not to be getting their parents set properly as they all open in their own little window. Below is some sample code recreating this issue:

from PyQt4.QtGui import *
from PyQt4.QtCore import *

class ItemWidget(QWidget):
    def __init__(self, parent=None):
        QWidget.__init__(self, parent)

        btn = QPushButton(self)

class populateWidgets(QThread):
    def __init__(self):
        QThread.__init__(self)

    def run(self):
        widget = ItemWidget()
        for x in range(5):
            self.emit(SIGNAL("widget"), widget)

class MyMainWindow(QMainWindow):
    def __init__(self, parent=None):
        QMainWindow.__init__(self, parent)

        self.tree = QTreeWidget(self)
        self.tree.setColumnCount(2)
        self.setCentralWidget(self.tree)

        self.pop = populateWidgets()
        self.connect(self.pop, SIGNAL("widget"), self.addItems)
        self.pop.start()

        itemWidget = QTreeWidgetItem()
        itemWidget.setText(0, "This Works")
        self.tree.addTopLevelItem(itemWidget)
        self.tree.setItemWidget(itemWidget, 1, ItemWidget(self))        

    def addItems(self, widget):
        itemWidget = QTreeWidgetItem()
        itemWidget.setText(0, "These Do Not")
        self.tree.addTopLevelItem(itemWidget)
        self.tree.setItemWidget(itemWidget, 1, widget)

if __name__ == "__main__":
    import sys
    app = QApplication(sys.argv)
    ui = MyMainWindow()
    ui.show()
    sys.exit(app.exec_())

As you can see, doing it inside MyMainWindow is fine, but somehow things go awry once it gets processed in the thread and returns. Is this possible to do? If so, how do I properly parent the ItemWidget class inside the QTreeWidgetItem? Thanks in advance.

Upvotes: 1

Views: 735

Answers (1)

Jeremy Friesner
Jeremy Friesner

Reputation: 73051

AFAICT Qt doesn't support the creation of QWidgets in a thread other than the thread where the QApplication object was instantiated (i.e. usually the main() thread). Here are some posts on the subject with responses from Qt developers:

http://www.qtcentre.org/archive/index.php/t-27012.html

http://www.archivum.info/[email protected]/2009-07/00506/Re-(Qt-interest)-QObject-moveToThread-Widgets-cannot-be-moved-to-a-new-thread.html

http://www.archivum.info/[email protected]/2009-07/00055/Re-(Qt-interest)-QObject-moveToThread-Widgets-cannot-be-moved-to-a-new-thread.html

http://www.archivum.info/[email protected]/2009-07/00712/Re-(Qt-interest)-QObject-moveToThread-Widgets-cannot-be-moved-toa-new-thread.html

(if it were possible, the way to do it would be to call moveToThread() on the QWidgets from within the main thread to move them to the main thread -- but apparently that technique doesn't work reliably, to the extent that QtCore has a check for people trying to do that prints a warning to stdout to tell them not to do it)

Upvotes: 1

Related Questions