PyQt 多线程,无法为父级创建子级

Posted

技术标签:

【中文标题】PyQt 多线程,无法为父级创建子级【英文标题】:PyQt Multi Threading, Cannot create children for a parent 【发布时间】:2016-01-15 22:06:16 【问题描述】:

我正在使用 python 2.7 我遇到了一些 pyqt 的多线程问题

我正在尝试读取一个 sqlite 文件,并将其内容导入应用程序的主 GUI。

所以我创建了一个 Thread 类

class Thread_OpenSqlite(QtCore.QThread):
    def __init__(self,parent=None):
        super(Thread_OpenSqlite,self).__init__(parent)
    
    def run(self):
        self.emit(QtCore.SIGNAL("open_sqlite()"))

当用户单击菜单栏打开 SQlite 文件时,会调用一个函数,创建该线程类的实例并调用该线程。

def selectSQLite(self):
    self.typeflag=4
    self.openpath=QFileDialog.getOpenFileName()
    if os.path.exists(str(self.openpath)):
        #Thread to Open Sqlite
        self.threadopenSqlite=Thread_OpenSqlite()
        self.connect(self.threadopenSqlite, QtCore.SIGNAL("open_sqlite()"), self.sqlOpen, QtCore.Qt.DirectConnection)
        self.threadopenSqlite.start()

在这个 sqlOpen() 方法中,我访问了 sqlite 的行并将数据放在几个 QLabels 中,self.ui 是我的 mainWindow GUI 的对象(其中包含、重新翻译、setupUi 等等功能)

def sqlOpen(self):
    conn = sqlite3.connect(str(self.openpath))
    print self.openpath
    cursor = conn.cursor()
    try:
        abc=cursor.execute('select some,rows,of,sqlite,to,read,from from general_info limit 0,1')
        for row in abc:
                self.ui.pushButton_2.show()
                self.ui.pushButton_2.setText(str(row[6]))
                self.ui.lineEdit.show()
                self.ui.pushButton_9.show()
                self.ui.label_2.setText(str(row[0]))
                self.ui.label_9.setText(str(row[1]))
                self.ui.label_10.setText(str(row[2]))
                self.ui.label_11.setText(str(row[3]))
                self.ui.label_12.setText(str(row[4]))
                self.ui.label_13.setText(str(row[5]))
                self.ui.label_14.setText(str(row[6]))
                self.ui.label_15.setText(str(row[7]))
                

        conn.close()
    except sqlite3.OperationalError:
        conn.close()

但在线程执行后,我的整个应用程序在回显此错误后崩溃。

QObject::setParent: 无法设置父级,新父级在不同的线程中

QObject::setParent: 无法设置父级,新父级在不同的线程中

QObject:无法为不同线程中的父级创建子级。

(父线程为QLabel(0x3315318),父线程为QThread(0x288fa78),当前线程为Thread_OpenSqlite(0x358e3a8)

QObject:无法为不同线程中的父级创建子级。 (父级为QTextDocument(0x367d728),父级线程为Thread_OpenSqlite(0x358e) 3a8),当前线程为QThread(0x288fa78)

我已经阅读了多个 pyqt 线程和以前的问题,他们有共同的说法

主线程中的 GUI 元素不能在 run 方法本身中修改,因此您必须使用信号和插槽机制来发出信号并将其连接到将完成工作的插槽。

注意 我也尝试过 QueuedConnection 代替 DirectConnection,虽然它解决了我的问题,但在退出应用程序时,它显示 python 的崩溃弹出窗口,我不想这样做

我还在同一个应用程序中完成了各种多线程操作,以从 GUI 元素中放置和获取数据,但这是唯一让我烦恼的。

谁能告诉我上面哪里出错了?

提前致谢。

【问题讨论】:

【参考方案1】:

看起来你的线程代码只是发出一个运行open_sqlite的信号,无论如何它只会在主线程中运行。此外,您似乎不需要对此进行线程处理。如果您只是填写标签(而不是表格之类的东西),那么您的数据不是很动态,因此您可能不需要在线程中运行它。只需在主线程中运行它作为程序初始化的一部分或响应事件。尽可能避免使用多线程;众所周知,破坏某些东西很容易(在任何语言或框架中)。

如果必须,请使用线程池(python 原生或基于 Qt),然后在事件循环中轮询池,直到工作完成。工作池更安全,更易于调试和推理。

【讨论】:

我稍后会填充表格,几乎像 40000 行,这就是为什么我需要线程以便我的主 gui 不会挂断。稍后我会看看线程池。 您可能想要查看QSqlTableModel(它具有对 sqlite 的本机支持)并使用 Mode-View-Controller 范例来解决这个问题。它只会根据需要从数据库中获取它需要的内容,并且不需要增加线程的复杂性。我仍然会在初始化或基于事件时填写标签。使用上面的内置类,您可以获得快速的实时性能,并且永远不需要处理令人头疼的线程(我可以保证,这会让您占用相当长的时间)。

以上是关于PyQt 多线程,无法为父级创建子级的主要内容,如果未能解决你的问题,请参考以下文章

无法为不同线程中的父级创建子级

线程关联性:无法为位于不同线程中的父级创建子级

QFuture 无法为位于不同线程中的父级创建子级

(QNativeSocketEngine)QObject:无法为不同线程中的父级创建子级

QTcpSocket Disconnected() 未发出信号

如何在 .NET Core 中使用默认依赖注入从父级创建子范围?