如果通过lambda调用method,则PySide:方法不会在线程上下文中执行

时间:2017-05-12 12:33:38

标签: 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().__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()

我做了过多的测试(请参阅代码段中的代码),但我绝对不知道发生了什么。

所以我的问题是:

为什么work在主线程中执行,而不是在lambda调用它的对象所在的线程?最重要的是,如果我想调用一个Worker需要参数的方法,而我无法使用lambda,我该怎么办?

&#13;
&#13;
from PySide.QtCore import *
from PySide.QtGui import *
from time import sleep
import functools
import sys


class Worker(QObject):
    def __init__(self):
        super().__init__()

    def work(self, name='Nothing'):
        print('Thread ID: {1} - {0} start'.format(name, QThread.currentThreadId()))
        sleep(1)
        print('##### End {0}'.format(name))


class HackPushButton(QPushButton):
    clicked_with_arg = Signal(str)
    def __init__(self, *args):
        super().__init__(*args)
        self.argument = None
        self.clicked.connect(lambda: self.clicked_with_arg.emit(self.argument))


class Example(QWidget):
    def __init__(self):
        super().__init__()
        self.buttonWithoutLambda = QPushButton('[Works] Call work() without arguments and without lambda')
        self.buttonWithLambda = QPushButton('[Blocks] Call work() with arguments and with lambda')
        self.buttonWithFunctools = QPushButton('[Blocks] Call work() with arguments and with functools')
        self.buttonWithHelperFunctionWithArgument = QPushButton('[Blocks] Call work() with arguments and with helper function')
        self.buttonWithHelperFunctionWithoutArgument = QPushButton('[Blocks] Call work() without arguments and with helper function')
        self.buttonWithHack = HackPushButton('[Works] Call work() with arguments via dirty hack')
        layout = QVBoxLayout()
        layout.addWidget(self.buttonWithoutLambda)
        layout.addWidget(self.buttonWithLambda)
        layout.addWidget(self.buttonWithFunctools)
        layout.addWidget(self.buttonWithHelperFunctionWithArgument)
        layout.addWidget(self.buttonWithHelperFunctionWithoutArgument)
        layout.addWidget(self.buttonWithHack)
        self.setLayout(layout)

        self.Worker = Worker()
        self.Thread = QThread()
        self.Worker.moveToThread(self.Thread)
        self.Thread.start()

        # Doesn't block GUI
        self.buttonWithoutLambda.clicked.connect(self.Worker.work)

        # Blocks GUI
        self.buttonWithLambda.clicked.connect(lambda: self.Worker.work('Lambda'))

        # Blocks GUI
        self.buttonWithFunctools.clicked.connect(functools.partial(self.Worker.work, 'Functools'))

        # Blocks GUI
        self.helperFunctionArgument = 'Helper function without arguments'
        self.buttonWithHelperFunctionWithArgument.clicked.connect(self.helperFunctionWithArgument)

        # Blocks GUI
        self.buttonWithHelperFunctionWithoutArgument.clicked.connect(self.helperFunctionWithoutArgument)

        # Doesn't block GUI
        self.buttonWithHack.argument = 'Hack'
        self.buttonWithHack.clicked_with_arg.connect(self.Worker.work)

        print('Thread ID: {0}'.format(QThread.currentThreadId()))
        self.show()

    def helperFunctionWithArgument(self):
        self.Worker.work(self.helperFunctionArgument)

    def helperFunctionWithoutArgument(self):
        self.Worker.work()


app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
&#13;
&#13;
&#13;

0 个答案:

没有答案