Her*_*nan 9 python multithreading pyqt signals-slots qthread
我有以下代码scan_value在更新ui(progress)中的进度条时执行后台操作().scan_value迭代某个值obj,value_changed每次更改值时发出signal().由于这里不相关的原因,我必须将它包装Scanner在另一个线程的object()中.当一个按钮扫描仪被称为scan是clicked.这是我的问题...以下代码工作正常(即进度条按时更新).
# I am copying only the relevant code here.
def update_progress_bar(new, old):
fraction = (new - start) / (stop - start)
progress.setValue(fraction * 100)
obj.value_changed.connect(update_progress_bar)
class Scanner(QObject):
def scan(self):
scan_value(start, stop, step)
progress.setValue(100)
thread = QThread()
scanner = Scanner()
scanner.moveToThread(thread)
thread.start()
scan.clicked.connect(scanner.scan)
Run Code Online (Sandbox Code Playgroud)
但如果我将最后一部分更改为:
thread = QThread()
scanner = Scanner()
scan.clicked.connect(scanner.scan) # This was at the end!
scanner.moveToThread(thread)
thread.start()
Run Code Online (Sandbox Code Playgroud)
进度条仅在最后更新(我的猜测是所有内容都在同一个线程上运行).如果在将对象接收对象移动到线程之前将信号连接到插槽,是否应该无关紧要.
ekh*_*oro 12
无论是在将worker对象移动到另一个线程之前还是之后进行连接都无关紧要.引用Qt文档:
Qt :: AutoConnection - 如果信号是从与接收对象不同的线程发出的,则信号排队,表现为 Qt :: QueuedConnection.否则,直接调用插槽,表现为Qt :: DirectConnection.发射信号时确定连接类型.[强调补充]
因此,只要type参数connect设置为QtCore.Qt.AutoConnection(默认值),Qt应确保以适当的方式发出信号.
示例代码的问题更可能是使用插槽而不是信号.信号连接的python方法可能需要使用pyqtSlot装饰器标记为Qt插槽:
from QtCore import pyqtSlot
class Scanner(QObject):
@pyqtSlot()
def scan(self):
scan_value(start, stop, step)
progress.setValue(100)
Run Code Online (Sandbox Code Playgroud)
编辑:
应该澄清的是,只有在相当新版本的Qt中,才会在发出信号时确定连接类型.在4.4版本中引入了此行为(以及Qt的多线程支持中的其他一些更改).
此外,可能值得进一步扩展PyQt特定问题.在PyQt中,信号可以连接到Qt插槽,另一个信号或任何python可调用.对于后一种情况,在内部创建一个代理对象,它包装python可调用并提供Qt信号/插槽机制所需的插槽.
正是这个代理对象才是问题的原因.一旦创建了代理,PyQt就会这样做:
if (rx_qobj)
proxy->moveToThread(rx_qobj->thread());
Run Code Online (Sandbox Code Playgroud)
如果在将接收对象移动到其线程之后建立连接,那么这很好; 但如果是之前的代理,代理将保留在主线程中.
使用lambda装饰器可以完全避免这个问题,因为它可以更直接地创建Qt插槽,并且根本不使用代理对象.
最后,还应该注意到这个问题目前不会影响PySide.
| 归档时间: |
|
| 查看次数: |
6999 次 |
| 最近记录: |