Python PySide:若通过lambda调用该方法,则不会在线程上下文中执行该方法
我有一个Python PySide:若通过lambda调用该方法,则不会在线程上下文中执行该方法,python,lambda,pyside,qthread,Python,Lambda,Pyside,Qthread,我有一个Worker对象,并使用其方法moveToThread将其放入线程中 现在我把它的work方法称为: 如果我直接调用该方法,它将在其对象所在的线程中执行 如果使用lambda调用该方法,则该方法将在主线程中执行 例如: from PySide.QtCore import * from PySide.QtGui import * import sys class Worker(QObject): def __init__(self): super().__in
Worker
对象,并使用其方法moveToThread
将其放入线程中
现在我把它的work
方法称为:
- 如果我直接调用该方法,它将在其对象所在的线程中执行
- 如果使用lambda调用该方法,则该方法将在主线程中执行
from PySide.QtCore import *
from PySide.QtGui import *
import sys
class Worker(QObject):
def __init__(self):
super().__init__()
def work(self):
print(self.thread().currentThread())
class Example(QWidget):
def __init__(self):
super().__init__()
self.btnInThread = QPushButton('in thread')
self.btnNotInThread = QPushButton('not in thread')
layout = QVBoxLayout()
layout.addWidget(self.btnInThread)
layout.addWidget(self.btnNotInThread)
self.setLayout(layout)
self.worker = Worker()
self.Thread = QThread()
self.worker.moveToThread(self.Thread)
self.Thread.start()
self.btnInThread.clicked.connect(self.worker.work)
self.btnNotInThread.clicked.connect(lambda: self.worker.work())
self.show()
print('{0} <- Main Thread'.format(self.thread().currentThread()))
def main():
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
我想我有答案了 我尝试编写代码并更改了单击的
connect
方法以使用QtCore.Qt.QueuedConnection
和QtCore.Qt.DirectConnection
(connect(self.worker.work,Qt.QueuedConnection)
)。直接连接使两个函数以相同的方式工作(lambda的工作方式),它们都在主线程中运行。但是,排队连接使它们的工作方式不同。lambda函数仍在主线程中运行,而辅助函数调用在单独的线程中运行。注意:如果不在connect
中提供参数,您使用的是自动连接,它将使用QueuedConnection
我通读了文件
队列连接当控制返回到接收方线程的事件循环时,将调用插槽。插槽在接收器的线程中执行
所以我相信lambda正在主线程中运行,因为lambda正在创建一个新函数。新的lambda函数不是插槽,它存在于主线程中。lambda函数接收器的线程是主线程。同时,worker.work
方法是一个具有不同接收器线程的插槽。因此,信号知道在工作线程中调用self.worker.work
,而在主线程中调用lambda函数,然后在主线程中调用self.worker.work()
我知道这很不方便,因为lambda对于向函数传递参数很有用
使用信号映射器传递值
from PySide import QtCore
from PySide import QtGui
import sys
import time
def create_map(obj, func, args=None):
"""Create a signal mapper to associate a value with a function.
Args:
obj (QObject): Object to map the value to with the signal mapper
func (function): Function to run when the signal mapper.map function is called.
args (tuple)[None]: Arguments you want to pass to the function.
Returns:
map_callback (function): Map function to connect to a signal.
mapper (QSignalMapper): You may need to keep a reference of the signal mapper object.
"""
mapper = QtCore.QSignalMapper()
mapper.setMapping(obj, args)
mapper.mapped.connect(func)
return mapper.map, mapper
class Worker(QtCore.QObject):
def __init__(self):
super().__init__()
def work(self, value=0):
print(self.thread().currentThread())
time.sleep(2)
print("end", value)
class Example(QtGui.QWidget):
def __init__(self):
super().__init__()
self.btnInThread = QtGui.QPushButton('in thread')
self.btnNotInThread = QtGui.QPushButton('not in thread')
layout = QtGui.QVBoxLayout()
layout.addWidget(self.btnInThread)
layout.addWidget(self.btnNotInThread)
self.setLayout(layout)
self.worker = Worker()
self.Thread = QtCore.QThread()
self.worker.moveToThread(self.Thread)
self.Thread.start()
self.btnInThread.clicked.connect(self.worker.work)
# Use a signal mapper
# self.mapper = QtCore.QSignalMapper()
# self.mapper.setMapping(self.btnNotInThread, 1)
# self.mapper.mapped.connect(self.worker.work)
# self.btnNotInThread.clicked.connect(self.mapper.map)
# Alternative mapper method from above
callback, self.mapper = create_map(self.btnNotInThread, self.worker.work, 1)
self.btnNotInThread.clicked.connect(callback)
self.show()
print('{0} <- Main Thread'.format(self.thread().currentThread()))
def main():
app = QtGui.QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
从PySide导入QtCore
从PySide导入QtGui
导入系统
导入时间
def create_映射(对象、函数、参数=无):
“”“创建信号映射器以将值与函数关联。
Args:
obj(QObject):使用信号映射器将值映射到的对象
func(function):调用signal mapper.map函数时运行的函数。
args(tuple)[None]:要传递给函数的参数。
返回:
map_回调(函数):连接到信号的map函数。
映射器(QSignalMapper):您可能需要保留信号映射器对象的引用。
"""
mapper=QtCore.QSignalMapper()
mapper.setMapping(对象,参数)
mapper.mapped.connect(func)
返回mapper.map,mapper
类工作者(QtCore.QObject):
定义初始化(自):
super()。\uuuu init\uuuuu()
def功(自身,值=0):
打印(self.thread().currentThread())
时间。睡眠(2)
打印(“结束”,值)
类示例(QtGui.QWidget):
定义初始化(自):
super()。\uuuu init\uuuuu()
self.btnInThread=QtGui.QPushButton('在线程中')
self.btnnointhread=QtGui.QPushButton('不在线程中')
layout=QtGui.QVBoxLayout()
layout.addWidget(self.btnInThread)
layout.addWidget(self.btnnointhread)
self.setLayout(布局)
self.worker=worker()
self.Thread=QtCore.QThread()
self.worker.moveToThread(self.Thread)
self.Thread.start()
self.btnInThread.clicked.connect(self.worker.work)
#使用信号映射器
#self.mapper=QtCore.QSignalMapper()
#self.mapper.setMapping(self.btnNotInThread,1)
#self.mapper.mapped.connect(self.worker.work)
#self.btnnointhread.clicked.connect(self.mapper.map)
#从上面选择映射器方法
回调,self.mapper=create_map(self.btnnointhread,self.worker.work,1)
self.btnnointhread.clicked.connect(回调)
self.show()
打印({0}我对线程的印象是,代码必须在run方法中才能在线程中运行。否则,我觉得代码应该始终在main中,特别是当您从信号触发work
时。我认为信号总是在主线程中运行代码,除非您将信号设置为使用直接连接。我在使用Python 3.4 PySide 1.2.2的Windows上,您的代码刚刚崩溃,所以我帮不了什么忙。我更新了我的代码。在Windows下不再崩溃可能的重复