PyQt |信号不在 QThread 中处理,而是在主线程中处理

2024-01-01

在这个简单的 PyQt 演示程序中,我从主线程发出信号。在工作线程中,我连接到它们,但信号处理程序在主线程中运行:

from PyQt4 import QtGui, QtCore
import threading
from time import sleep
import sys


class Data():
    def __init__(self, a, b):
        self.a = a
        self.b = b

    def __str__(self):
        return "Data having %d and %d" % (self.a, self.b)

class Worker(QtCore.QThread):
    def __init__(self, parent):
        QtCore.QThread.__init__(self)
        self.p = parent

    def run(self):
        self.connect(self.p, QtCore.SIGNAL("newTask"), self.task)
        print "[%s] running exec_()" % threading.currentThread()
        self.exec_()

    def task(self, dataobj):
        print "[%s] Processing" % threading.currentThread(), dataobj
        sleep(3)
        print "Done with", dataobj
        self.emit(QtCore.SIGNAL("taskDone"), str(dataobj))

class App(QtCore.QObject):
    def __init__(self):
        QtCore.QObject.__init__(self)
        self.w = Worker(self)
        self.connect(self.w, QtCore.SIGNAL("taskDone"), self.on_task_done)
        self.w.start()

    def assign_tasks(self):
        self.emit(QtCore.SIGNAL("newTask"), Data(3, 4))
        self.emit(QtCore.SIGNAL("newTask"), Data(5, 6))
        print "[%s] Tasks sent" % threading.currentThread()

    @staticmethod
    def on_task_done(objstr):
        print "[%s] App: Worker finished with" % threading.currentThread(), objstr

if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    a = App()
    sleep(1)
    a.assign_tasks()
    sleep(20)
    sys.exit(app.exec_())

但结果显示回调是在主线程中运行的:

[<_DummyThread(Dummy-1, started daemon 105564)>] running exec_()
[<_MainThread(MainThread, started 105612)>] Processing Data having 3 and 4
Done with Data having 3 and 4
[<_MainThread(MainThread, started 105612)>] App: Worker finished with Data having 3 and 4
[<_MainThread(MainThread, started 105612)>] Processing Data having 5 and 6
Done with Data having 5 and 6
[<_MainThread(MainThread, started 105612)>] App: Worker finished with Data having 5 and 6
[<_MainThread(MainThread, started 105612)>] Tasks sent

我究竟做错了什么?不幸的是,PyQt 文档对此非常不完整且相互矛盾。

如果我使用,我会得到类似的结果moveToThread技术:

from PyQt4 import QtGui, QtCore
import threading
from time import sleep
import sys

class Data():
    def __init__(self, a, b):
        self.a = a
        self.b = b

    def __str__(self):
        return "Data having %d and %d" % (self.a, self.b)

class Worker(QtCore.QObject):
    def __init__(self, parent):
        QtCore.QObject.__init__(self)
        self.connect(parent, QtCore.SIGNAL("newTask"), self.task)

    def task(self, dataobj):
        print "[%s] Processing" % threading.currentThread(), dataobj
        sleep(3)
        print "Done with", dataobj
        self.emit(QtCore.SIGNAL("taskDone"), str(dataobj))

    def start(self):
        print "[%s] start()" % threading.currentThread()

class App(QtCore.QObject):
    def __init__(self):
        QtCore.QObject.__init__(self)

        self.w = Worker(self)
        self.t = QtCore.QThread(self)
        self.w.moveToThread(self.t)
        self.connect(self.w, QtCore.SIGNAL("taskDone"), self.on_task_done)
        self.connect(self.t, QtCore.SIGNAL("started()"), self.w.start)
        self.t.start()

    def assign_tasks(self):
        self.emit(QtCore.SIGNAL("newTask"), Data(3, 4))
        self.emit(QtCore.SIGNAL("newTask"), Data(5, 6))
        print "[%s] Tasks sent" % threading.currentThread()

    @staticmethod
    def on_task_done(objstr):
        print "[%s] App: Worker finished with" % threading.currentThread(), objstr

if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    a = App()
    sleep(1)
    a.assign_tasks()
    sleep(20)
    sys.exit(app.exec_())

结果是:

[<_DummyThread(Dummy-1, started daemon 108992)>] start()
[<_MainThread(MainThread, started 107004)>] Processing Data having 3 and 4
Done with Data having 3 and 4
[<_MainThread(MainThread, started 107004)>] App: Worker finished with Data having 3 and 4
[<_MainThread(MainThread, started 107004)>] Processing Data having 5 and 6
Done with Data having 5 and 6
[<_MainThread(MainThread, started 107004)>] App: Worker finished with Data having 5 and 6
[<_MainThread(MainThread, started 107004)>] Tasks sent

Your Worker对象“活动”在主线程中,这意味着它们的所有信号将由主线程的事件循环处理。事实上,这些物体是QThreads 并没有改变这一点。

如果您希望信号由不同的线程处理,您首先需要使用它的方法将工作对象移动到该线程moveToThread http://pyqt.sourceforge.net/Docs/PyQt4/qobject.html#moveToThread method.

所以在你的情况下,只有run方法实际上是在不同的线程中执行的,task方法仍然在主线程中执行。改变这种情况的一种方法是:

  • 做你的Worker一个常规的QObject, not a QThread
  • 创建一个QThread在你的App,启动它并将工作线程移至该线程
  • 然后向工作进程发送信号,使其开始处理

您应该查看这些参考资料:

  • QObject线程亲和性 http://qt-project.org/doc/qt-5/qobject.html#thread-affinity
  • Qt 线程基础知识 http://qt-project.org/doc/qt-5/thread-basics.html
  • Qt 中的多线程技术 http://qt-project.org/doc/qt-5/threads-technologies.html

edit:

我在您的代码中注意到的其他一些事情:

  • 你正在混合 python 线程和 qt 线程。threading.currentThread will not正确反映当前的qt线程。使用QThread.currentThread()为了那个原因。
  • 装饰你正在调用的插槽pyqtSlots,不这样做可能会导致此类问题。
  • use 新风格信号 http://pyqt.sourceforge.net/Docs/PyQt4/new_style_signals_slots.html。 PyQt5 不再支持旧样式信号,新样式信号使用起来更容易、更好。

因此,这是您应该可以使用的代码版本:

from PyQt4 import QtGui, QtCore
import threading
from time import sleep
import sys

class Data():
    def __init__(self, a, b):
        self.a = a
        self.b = b

    def __str__(self):
        return "Data having %d and %d" % (self.a, self.b)

class Worker(QtCore.QObject):

    taskDone = QtCore.pyqtSignal(str)

    def __init__(self, parent):
        QtCore.QObject.__init__(self)
        parent.newTask.connect(self.task)

    @QtCore.pyqtSlot(object)
    def task(self, dataobj):
        print "[%s] Processing" % QtCore.QThread.currentThread().objectName(), dataobj
        sleep(3)
        print "Done with", dataobj
        self.taskDone.emit(str(dataobj))

    @QtCore.pyqtSlot()
    def start(self):
        print "[%s] start()" % QtCore.QThread.currentThread().objectName()

class App(QtCore.QObject):

    newTask = QtCore.pyqtSignal(object)

    def __init__(self):
        QtCore.QObject.__init__(self)
        self.w = Worker(self)
        self.t = QtCore.QThread(self, objectName='workerThread')
        self.w.moveToThread(self.t)
        self.w.taskDone.connect(self.on_task_done)
        self.t.started.connect(self.w.start)
        self.t.start()

    def assign_tasks(self):
        self.newTask.emit(Data(3, 4))
        self.newTask.emit(Data(5, 6))
        print "[%s] Tasks sent" % QtCore.QThread.currentThread().objectName()

    @staticmethod
    def on_task_done(objstr):
        print "[%s] App: Worker finished with" % QtCore.QThread.currentThread().objectName(), objstr

if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    QtCore.QThread.currentThread().setObjectName('main')
    a = App()
    sleep(1)
    a.assign_tasks()
    from utils import sigint
    sys.exit(app.exec_())

我已经设置了线程objectNames 使输出更具可读性:



[workerThread] start()
[main] Tasks sent
[workerThread] Processing Data having 3 and 4
Done with Data having 3 and 4
[workerThread] Processing Data having 5 and 6
[main] App: Worker finished with Data having 3 and 4
Done with Data having 5 and 6
[main] App: Worker finished with Data having 5 and 6
  
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

PyQt |信号不在 QThread 中处理,而是在主线程中处理 的相关文章

  • pyqtgraph ImageView 在多线程时冻结

    我有多个通过 WiFi 无线连接的摄像头 我正在尝试将数据流式传输到客户端 客户端在 GUI 上显示流 我的问题是 pyqtgraph ImageItems 似乎在大约 30 秒后停止重新绘制 或者如果我单击窗口外 或者如果我调整其中一张图
  • 从 Qthread 更新 Python GUI 元素

    所以我知道有很多关于使用 Qthread 更新 GUI 中的元素的帖子 我尽了最大努力去检查这些 但仍然有一个问题 我正在尝试创建一个 GUI 该 GUI 在单击按钮时运行一个方法 然后该方法启动一个新线程 然后该线程向 GUI 发出信号以
  • Pyqt5 中的 QThreads:这是官方 QThread 文档的正确 C++ 到 Python 翻译吗?

    关于如何实例化和使用的官方文档QThread可以在这里找到 http doc qt io qt 5 qthread html http doc qt io qt 5 qthread html 该文档描述了两种基本方法 1 工作对象方法和 2
  • QFileDialog 作为 TableView 的编辑器:如何获取结果?

    我正在使用一个QFileDialog作为某些专栏的编辑QTableView 这基本上有效 对一些焦点问题取模 请参阅here https stackoverflow com questions 22854242 qfiledialog as
  • 我如何告诉 QTableWidget 结束编辑单元格?

    我正在显示一个弹出菜单来选择 QTableWidget 中的某些值 最下面的项目是 修改列表 条目 当我选择它时 应自动出现一个新窗口 并且 QComboBox 应消失 并且单元格返回到 Qt DisplayRole 状态 现在 Qt 拥有
  • 错误:permission_manager_qt.cpp(82) 不支持的权限类型:13

    我正在开发具有内置浏览器功能的 python 代码 PyQt 5 13 import sys from PyQt5 QtCore import from PyQt5 QtGui import from PyQt5 QtWidgets imp
  • 带 Qt 的菜单栏/系统托盘应用程序

    我是 Qt PyQt 的新手 我正在尝试制作一个应用程序 其功能将从菜单栏 系统托盘执行 这里展示了一个完美的例子 我找不到关于如何做到这一点的好资源 有人可以建议吗 Thanks 我认为您正在寻找与QMenu and QMainWindo
  • QSortFilterProxyModel + QAbstractItemModel modelIndex.internalPointer() 导致崩溃

    我在 PyQt 4 8 Python 2 7 中实现了自己的 QAbstractItemModel class FriendListModel QtCore QAbstractItemModel def init self groups c
  • PyQt - 如何从给定的小部件获取顶级父级?

    给定的小部件如何访问它最旧的父级 即顶级小部件 我需要 showMinimized it 现在我正在使用 self parent parent parent showMinimized 但这似乎不是最好的方法 如果它移动了 我需要手动更改父
  • 在 Maya 中正确使用 PySide QThread 以避免硬崩溃

    我正在尝试使用 QThreads 更新 Maya 内自定义工具基于 Qt 的 UI 我有一个线程执行任意方法并通过发出的信号返回结果 然后用它来更新我的 UI 这是我的自定义 QThread 类 from PySide import QtC
  • 如何在 QGraphicsView 中制作 2 层?

    在下面的程序中 加载背景图像并在其上绘制 但是 我遇到了一个问题 在这个程序中 当我使用 橡皮擦 工具时 背景图像也被删除了 其实我只是想把我画的东西擦掉 除了背景图片 然后 我想仅将绘制的图层 图层 保存为图像 在这种情况下 我该怎么办
  • 如何在pyqt5中创建小部件来显示谷歌地图

    如何从用户那里获取纬度和经度并在 pyqt5 小部件的地图上显示该位置 我的操作系统是Windows 我找到了这个链接 https github com eyllanesc qMap https github com eyllanesc q
  • 清除pyqt中布局中的所有小部件

    有没有办法清除 删除 布局中的所有小部件 self plot layout QtGui QGridLayout self plot layout setGeometry QtCore QRect 200 200 200 200 self r
  • 在标准 python 线程中发出信号

    我有一个线程应用程序 其中有一个网络线程 UI 部分通过callback到这个线程 线程是一个normalpython 线程 它是NO QThread 是否可以在该线程内发出 PyQT Slot 不 不可能像这样从 python 线程发出
  • 如何向 PyQt5 GUI 添加线程?

    所以我使用 QT Designer 创建了一个 GUI 它工作得很好 但在更复杂的调用中 它不会更新主窗口并锁定 我想运行我的CustomComplexFunction 在根据不断变化的后端信息更新主窗口中的文本编辑时 我希望它每 2 秒运
  • 从另一个类向主类发出信号

    当它处于Worker 类 def run self 方法 一切运行良好 while 循环能够循环并每 1 秒发出一个信号 那么标签在收到信号后就会更新 我决定尝试将 while 循环放置在另一个名为循环 methodA 的类中 这是为了尝试
  • 通过 connect 传递额外的参数

    是否可以通过槽传递变量以便我可以打印出某些文本 尝试将另一个函数中定义的变量 DiffP 传递给插槽 DiffP 根据选择的文件而变化 def addLineEdit self try self clearLayout self FileB
  • 在 PyQt 布局之间添加间隔线

    我想在两个布局之间添加一条分隔线 Separador QFrame Separador Shape QFrame HLine Separador setSizePolicy QSizePolicy Minimum QSizePolicy E
  • 从外部函数访问 QLCDNumber 对象

    每次线程 t1 每秒调用函数 wait thread v1 时 我的 python 脚本都需要更改一个对象 lcd p1 但是如何做到这一点呢 我不知道如何在函数内访问这个对象 有人可以帮忙吗 vazao1 12 global pulses
  • PyQt5-5.8.2 无法在 Windows 10 上运行

    我需要安装qscintilla 我使用 pip 来实现 gt pip install qscintilla PyQt5自动升级到最新版本 5 8 2 并且sip升级到 4 19 2 我想这与 qscintilla 的需求有关 也许最新版本的

随机推荐

  • targetNamespace 和 xmlns 不带前缀,有什么区别?

    在 xml 架构文档中 如果我同时具有 targetNamespace 和 xmlns没有前缀
  • 我可以通过任务管理器处理 Windows 进程的终止吗?

    我有一个 Windows C 应用程序 app exe 当应用程序关闭时 我需要执行一些特定于我的应用程序的清理任务 通过任务管理器终止此进程 app exe 时会发生什么 假设应用程序仍然响应 我可以以某种方式在 app exe 中处理这
  • 如何在不重新加载图表的情况下更新选项(ng2-chart)

    我需要更新图表中的选项 并且需要使用新选项显示图表 我希望图表不重新加载 这是我的ts ViewChild BaseChartDirective chart any lineChartOptions any responsive true
  • 如何将R代码转换为字符串?

    我想转型c 1 2 text 转换为只有一个元素的字符向量c 1 2 text 我已经尝试过这个 gt quote c 1 2 text c 1 2 text but gt class quote c 1 2 text 1 call 和这个
  • 如何在启用调试的 Android 6.0 设备上更轻松地切换 MTP?

    在安卓6 0中 MTP 不再自动工作 http developer android com about versions marshmallow android 6 0 changes html behavior usb 通过 USB 端口
  • 如何获得isolatedStorage中所有文件的平面列表?

    我需要获取给定isolatedStorage文件夹中所有文件的列表 isolatedStorage 的根目录下有一些子文件夹 这些子文件夹需要包含在列表中 通常的 System IO 类不能与isolatedStorage 一起使用 这是我
  • Keras 预测不会返回 celery 任务

    以下 Keras 函数 预测 在同步调用时有效 pred model predict x 但当从异步任务队列 Celery 中调用时它不起作用 Keras 预测函数在异步调用时不会返回任何输出 堆栈是 Django Celery Redis
  • AngularJS 承诺返回空对象

    基本上我想做的是从解析承诺的函数调用中分配一些模型值 像这样 value someFun 这是我调用此函数的服务 app factory SomeService function q return someFun function var
  • pandas 系列的循环移位

    我正在对 pandas 中的数据系列使用移位方法 文档 http pandas pydata org pandas docs stable generated pandas Series shift html 是否可以一步进行循环移位 即第
  • 如何使用Delphi2007运行非提升的进程

    我有一个类似安装程序的应用程序 我必须在 Vista 上以提升的身份运行它 但从那里我必须开始一个非提升的新流程 有什么提示如何使用 Delphi2007 做到这一点吗 我找到了一个C 的优秀示例 http www codeproject
  • 如何更改 Visual Studio Code 中的解释器?

    我在我的系统上安装了几个 Python 解释器 2 x 和 3 x 版本 我正在尝试准备我的工作环境 以便可以在用两个 Python 版本编写的代码之间轻松切换 在 Visual Studio Code VSC 中拥有尽可能灵活的设置非常重
  • 如何更改 Font Awesome 5 中图标的颜色?

    我无法使用这些代码为 Font Awesome 5 图标着色 我试过fillcss 属性用于设置颜色 但它不起作用 HTML 代码 div class container mt200 icons div class col md 3 div
  • SQL Server 中的函数与存储过程

    在 SQL 中什么时候应该使用函数而不是存储过程 反之亦然 每个的目的是什么 函数是计算值 不能执行永久的环境更改SQL Server 即 没有INSERT or UPDATE允许声明 函数可以内联使用SQL如果它返回标量值 则可以使用语句
  • Google Play 游戏应用中未显示成就

    我们根据官方谷歌开发文档为我们的 Android 游戏实现了 Google Play 成就 但似乎有些不对劲 因为我们注意到 Google Play 游戏应用程序中存在以下奇怪的行为 成就不会显示在 Google Play 游戏应用中 在
  • 计算三个加密数字的平均值

    是否可以计算三个加密整数的平均值 对加密方法没有限制 这样做的目的只是隐藏三个数字并求平均值 你似乎正在寻找的东西叫做同态加密 http en wikipedia org wiki Homomorphic encryption 一种加密方案
  • LibGDX FreeType 字体模糊

    我正在使用屏幕高度百分比和设置百分比动态生成字体 显然将来会乘以密度 一些笔记 我正在读取 OTF 文件 使用最新版本的LibGDX 版本1 2 0 我有以下问题 字体有很大的断裂 看起来很模糊 但仅限于medium Large and s
  • 如何在android中滚动tableview

    我有一个要滚动的表格视图 因为数据未显示完整
  • ggplot2 轴标签分组

    我正在尝试使用 ggplot2 构建一个图 在 X 轴上我可以找到某种为变量组添加标签的方法 这是我的代码的最小版本 Bzero lt 100 matrix runif 100 ncol 10 nrow 10 B lt 99 LNtype
  • 横向压平两列,雪花中不重复

    我有一个查询 该查询按两个变量进行分组以获得另一个变量的总数 为了维护我的表结构以供以后计算 我列出了另外两个变量以保存查询的下一阶段 但是 当我尝试稍后对 listagg 列进行两次展平时 我的数据会重复多次 示例 my table id
  • PyQt |信号不在 QThread 中处理,而是在主线程中处理

    在这个简单的 PyQt 演示程序中 我从主线程发出信号 在工作线程中 我连接到它们 但信号处理程序在主线程中运行 from PyQt4 import QtGui QtCore import threading from time impor