简体   繁体   English

Python PyQt:是否可以将QThread与非GUI程序一起使用?

[英]Python PyQt: Is it possible to use QThread with a non-GUI program?

I have a Python PyQt application that displays a simple UI. 我有一个显示简单UI的Python PyQt应用程序。 When the user clicks a button in the UI it triggers a QThread. 当用户单击UI中的按钮时,它将触发QThread。 The use of a thread prevents the UI from "freezing" while the thread runs. 线程的使用可防止UI在线程运行时“冻结”。 I emit signals to pass information from the run thread back to the UI for status updates and to indicate completion. 我发出信号以将信息从运行线程传递回UI,以进行状态更新并指示完成。 Everything works fine as described and I've created a simple class for my UI to call which creates the thread and runs my generic processing. 一切都按说明工作正常,我为UI调用创建了一个简单的类,该类创建线程并运行我的通用处理。

However, I would also like to create a command line version (No GUI) of my program and use the same processing QThread class. 但是,我也想创建程序的命令行版本(无GUI)并使用相同的处理QThread类。 However, I get the following error when I try to connect my signals. 但是,尝试连接信号时出现以下错误。 It would seem that QThread was only meant for GUI programs? 似乎QThread仅用于GUI程序?

AttributeError: MyClass instance has no attribute 'connect'

Is it possible to use QThread with a non-GUI program? 是否可以将QThread与非GUI程序一起使用?

from PyQt4 import QtCore
from PyQt4.QtCore import * 

#======================================

class MyProcess(QThread):

    def __init__(self):
        QThread.__init__(self)

    def __del__(self):
        self.quit()
        self.wait()  

    def run(self):
        print "do time intensive process here"  
        self.emit( SIGNAL('processdone'), "emitting signal processdone") 
        return       

#====================================== 

class MyClass(QObject):

    def __init__(self, parent=None):            # All QObjects receive a parent argument (default to None)
        super(MyClass, self).__init__(parent)   # Call parent initializer.

        thread1 = MyProcess()  # uses QThread and emits signal 'processdone' 
        self.connect( thread1, SIGNAL("processdone"), self.thread1done)    
        thread1.start()  

    def thread1done(self):
        print "done"      

#======================================

if __name__ == "__main__": 

    MyClass()

The problem isn't QThread, the problem is that you're calling the connect method from a class which doesn't have it. 问题不是QThread,而是您正在从没有它的类中调用connect方法。 You need to make MyClass inherits from QObject. 您需要使MyClass从QObject继承。

In the GUI this works because whatever widget you're working with (QDialog, QMainWindow, QWidget ...) it inherits (directly or indirectly) from QObject. 在GUI中这是可行的,因为您正在使用的任何小部件(QDialog,QMainWindow,QWidget ...)都(直接或间接)继承自QObject。

To make MyClass inherit from QObject you only have to: 要使MyClassQObject继承,您只需:

class MyClass(QObject):                         # Specify the class your are specializing.
    def __init__(self, parent=None):            # All QObjects receive a parent argument (default to None)
        super(MyClass, self).__init__(parent)   # Call parent initializer.

        # And countinue your code here... 

I also recommend you to use the New-style Signal and Slot Support . 我还建议您使用新型信号和插槽支持

Everything works except the processdone signal is called but apparently it never triggers call to thread1done. 一切正常,除了processdone信号称为,但显然它永远不会触发来电thread1done。

The problem I can spot is you don't have defined a processdone signal. 我能发现的问题是您尚未定义一个processdone信号。 That signal does not exist for Qt. Qt不存在该信号。 Check the link I left you to learn about custom signals. 检查我留下的链接以了解自定义信号。 Meanwhile you can add: 同时,您可以添加:

class MyProcess(QThread):
    processdone = QtCore.pyqtSignal("QString")

at the beginning of the class. 在课程开始时。

And one last thing, but very important. 最后一件事,但非常重要。 You aren't working with GUI, but you are still using QObjects and the Qt singal mechanisms, which depends on the main Qt loop to work. 您没有使用GUI,但仍在使用QObjects和Qt信号机制,这取决于要运行的主要Qt循环。 Hence, you still need a QApplication object despite of your application is a non-gui program. 因此,尽管您的应用程序是非GUI程序,但仍然需要QApplication对象。

Here is your code, now working: 这是您的代码,现在可以使用:

from PyQt4 import QtCore
from PyQt4 import QtGui
from PyQt4.QtCore import * 

class MyProcess(QThread):
    processdone = QtCore.pyqtSignal("QString") # Define custom signal.
    def __init__(self, parent = None):
        QThread.__init__(self, parent)
    def run(self):
        print("do time intensive process here")
        self.emit( SIGNAL('processdone'), "emitting signal processdone")
        return       

class MyClass(QObject):

    def __init__(self, parent=None):            # All QObjects receive a parent argument (default to None)
        super(MyClass, self).__init__(parent)   # Call parent initializer.

        thread1 = MyProcess(self) 
        self.connect( thread1, SIGNAL("processdone"), self.thread1done)    
        thread1.start()  

    @QtCore.pyqtSlot("QString")         # Tell Python this is a QTSLOT an receives a string
    def thread1done(self, text):
        print(text)                     # Print the text from the signal.

if __name__ == "__main__":
    import sys
    app = QtGui.QApplication(sys.argv)  # You still need a QApplication object.
    a = MyClass()
    sys.exit(app.exec())

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM