在线程之间进行通信时,pyside信号不会被pyinstaller触发

时间:2015-10-30 20:09:23

标签: multithreading macos pyside pyinstaller

我正在尝试为我的pyside gui构建一个.app,当我使用信号在主线程和另一个线程之间进行通信时,我遇到了问题。当我运行python代码时,一切正常。只有当我使用从pyinstaller构建的.app时才会出现此问题。

项目非常大,所以很难包含任何代码,所以我会尝试解释我在做什么。

我的第二个线程用于从控制我们设备的dylib调用某些函数。主线程使用回调告诉dylib停止它正在做的事情。 dylib在循环中调用回调函数,如果从主线程返回的值不是0,则停止。

正如我所提到的,当我运行Python代码(在Windows,Ubuntu,Mac下)时,它完美无缺。但是当使用使用pyinstaller构建的.app时,看起来信号不是从主线程发送的。在调试时,我打印了东西并最终看到dylib没有从回调中接收返回的值。 dylib确实使用了回调,我可以在主线程中看到预期的数据。

那么为什么信号不会被冻结的python代码触发? 有没有人遇到类似的问题? 如果你能给我一些调试建议,那真的很有帮助吗?

修改

我设法写了一个很小的代码来重现问题。当我运行python代码时,按“确定”,然后按“取消”,在窗口小部件中设置消息“DLL获取值”。使用Pyinstaller冻结代码时,在mac下,永远不会在窗口小部件上设置消息。在Windows 7上,一切都很好。

修改

实际上,共享库不需要导致问题。只有Python代码才会出现此问题。

enter image description here

enter image description here

enter image description here

这是Python代码:

import sys
from PySide import QtGui
from PySide.QtCore import QThread, Signal, QObject

def functionInDLL(callback):
    return_value = 0
    while (return_value == 0):
        return_value = callback(2)


class MyThread(QThread):
    str_signal = Signal(str)
    def __init__(self):
        QThread.__init__(self)
        self.return_value = 0

    def returnValueToDll(self, data=0):
        return self.return_value 

    def run(self):
        if functionInDLL(self.returnValueToDll) == 42:
            print"DLL got the value."
            self.str_signal.emit("DLL got the value.")
        else:
            print"DLL did not get the value."
            self.str_signal.emit("DLL did not get the value.")
        self.exec_()         

    def setValueSentToDll(self, data):
        self.return_value = data



class MainThreadClass(QObject):
    int_signal = Signal(int)
    def __init__(self):
        super(MainThreadClass, self).__init__()
        self.test_thread = MyThread()
        self.int_signal.connect(self.test_thread.setValueSentToDll)

    def startMyThread(self):
        self.test_thread.start()

    def sendStopValueToDLL(self):
        self.int_signal.emit(42)          



class MyGUI(QtGui.QWidget):
    def __init__(self):
        super(MyGUI, self).__init__()
        self.text_information = QtGui.QLabel(text="No started yet...")
        self.dll_information = QtGui.QLabel(text="")
        self.ok_button = QtGui.QPushButton("OK")
        self.cancel_button = QtGui.QPushButton("Cancel")
        self.close_button = QtGui.QPushButton("Close")
        label_hbox = QtGui.QHBoxLayout()
        hbox = QtGui.QHBoxLayout()
        hbox.addWidget(self.ok_button)
        hbox.addWidget(self.cancel_button)
        hbox.addWidget(self.close_button)
        vbox = QtGui.QVBoxLayout()
        label_hbox.addWidget(self.text_information)
        label_hbox.addWidget(self.dll_information)
        vbox.addLayout(label_hbox)
        vbox.addLayout(hbox)

        self.setLayout(vbox)
        self.ok_button.clicked.connect(self.onOk)
        self.cancel_button.clicked.connect(self.onCancel)
        self.close_button.clicked.connect(self.onClose)
        self.show()
        self.main_thread = MainThreadClass()
        self.main_thread.test_thread.str_signal.connect(lambda data: self.setDllStatusOnWidget(data))


    def onOk(self):
        self.main_thread.startMyThread()    
        self.text_information.setText("Started")
        self.dll_information.setText("")

    def onCancel(self):
        self.main_thread.sendStopValueToDLL()
        self.text_information.setText("Canceled")

    def onClose(self):
        self.main_thread.test_thread.exit()   
        self.close()

    def setDllStatusOnWidget(self, text=""):
        self.dll_information.setText(text)


if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    ex = MyGUI()
    sys.exit(app.exec_())

由于 使用Python2.7,Mac Pro Yosemite

1 个答案:

答案 0 :(得分:0)

感谢codewarrior,我的错误得到了解决。 当我更换线路时:

self.main_thread.test_thread.str_signal.connect(lambda data: self.setDllStatusOnWidget(data))

通过这一行,删除lambda:

self.main_thread.test_thread.str_signal.connect(self.setDllStatusOnWidget)

有关详细信息,请参阅链接。我希望这可以帮助其他人。 pyinstaller_issue