【问题标题】:Proper parenting of QWidgets generated from a QThread to be inserted into a QTreeWidget从 QThread 生成的 QWidgets 的正确父级以插入到 QTreeWidget
【发布时间】:2012-06-17 16:02:26
【问题描述】:

我有一个需要填充大量信息的 QTreeWidget。所以我可以设计它并按照我真正想要的方式设置它,我决定创建一个 QWidget,它的风格和穿着都很漂亮。然后,我将使用通用 TreeWidgetItems 填充 TreeWidget,然后使用 setItemWidget 将自定义 QWidgets 粘贴在树中。这在主 PyQt 线程中调用 QWidgets 时有效,但由于信息量很大,我想在线程中创建和填充 QWidgets,然后稍后发出它们以添加到主线程中一旦他们都填写完毕。但是,当我这样做时,QWidgets 似乎没有正确设置它们的父母,因为它们都在自己的小窗口中打开。以下是重现此问题的一些示例代码:

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_())

如您所见,在 MyMainWindow 中执行此操作很好,但是一旦在线程中处理并返回,事情就会出错。这可能吗?如果是这样,我如何正确地将 QTreeWidgetItem 中的 ItemWidget 类作为父级?提前致谢。

【问题讨论】:

    标签: python multithreading pyqt widget


    【解决方案1】:

    AFAICT Qt 不支持在实例化 QApplication 对象的线程(即通常是 main() 线程)之外的线程中创建 QWidget。以下是一些关于该主题的帖子以及 Qt 开发人员的回复:

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

    http://www.archivum.info/qt-interest@trolltech.com/2009-07/00506/Re-(Qt-interest)-QObject-moveToThread-Widgets-cannot-be-moved-to-a-new-thread.html

    http://www.archivum.info/qt-interest@trolltech.com/2009-07/00055/Re-(Qt-interest)-QObject-moveToThread-Widgets-cannot-be-moved-to-a-new-thread.html

    http://www.archivum.info/qt-interest@trolltech.com/2009-07/00712/Re-(Qt-interest)-QObject-moveToThread-Widgets-cannot-be-moved-toa-new-thread.html

    (如果可能的话,这样做的方法是从主线程中调用 QWidgets 上的 moveToThread() 以将它们移动到主线程 - 但显然该技术不能可靠地工作, QtCore 对尝试这样做的人进行检查的程度,会向标准输出打印警告,告诉他们不要这样做)

    【讨论】:

    • 将小部件添加到主线程中的树中是否安全,然后将它们中的每一个传递给线程以确保人口安全?我想到的唯一另一种方法是查询线程中的字典等所有信息,然后发出这些信息并使用它来填充小部件数据。
    • 我认为从不同的线程中更新 GUI 是不安全的......所以你的代码可以在 QWidget 子类中设置 Qt 不知道的数据,但是任何从线程调用到 Qt 自己的 GUI/widget 代码可能会让您感到悲伤。我喜欢你在另一个线程中准备数据的第二个想法,然后将数据传送回主线程以将数据移动到 GUI 中;这应该会更好。
    • 是的,同意了。谢谢杰里米!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-13
    相关资源
    最近更新 更多