PythonPyQT:可以将QThread与非GUI程序一起使用吗?

PythonPyQT:可以将QThread与非GUI程序一起使用吗?,python,multithreading,pyqt,pyqt4,Python,Multithreading,Pyqt,Pyqt4,我有一个Python PyQt应用程序,它显示一个简单的UI。 当用户单击UI中的按钮时,会触发QThread。 使用线程可以防止UI在线程运行时“冻结”。 我发出信号,将运行线程的信息传递回UI进行状态更新,并指示完成。正如所描述的,一切都很好,我已经为我的UI创建了一个简单的类来调用它,它创建了线程并运行我的泛型处理 但是,我还想为我的程序创建一个命令行版本(没有GUI),并使用相同的处理QThread类。但是,当我尝试连接信号时,会出现以下错误。似乎QThread只适用于GUI程序 Att

我有一个Python PyQt应用程序,它显示一个简单的UI。 当用户单击UI中的按钮时,会触发QThread。 使用线程可以防止UI在线程运行时“冻结”。 我发出信号,将运行线程的信息传递回UI进行状态更新,并指示完成。正如所描述的,一切都很好,我已经为我的UI创建了一个简单的类来调用它,它创建了线程并运行我的泛型处理

但是,我还想为我的程序创建一个命令行版本(没有GUI),并使用相同的处理QThread类。但是,当我尝试连接信号时,会出现以下错误。似乎QThread只适用于GUI程序

AttributeError: MyClass instance has no attribute 'connect'
可以将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()

问题不是QThread,问题是您正在从一个没有它的类调用
connect
方法。您需要使
MyClass
继承自QObject

在GUI中,这是因为您使用的任何小部件(QDialog、QMainWindow、QWidget…)都(直接或间接)继承自QObject

要使
MyClass
QObject
继承,您只需:

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... 
我还建议您使用

除了调用了
processdone
信号外,其他一切都正常,但显然它从未触发对thread1done的调用。

我能发现的问题是您没有定义processdone信号。Qt不存在该信号。检查我留给你的链接,了解自定义信号。同时,您可以添加:

class MyProcess(QThread):
    processdone = QtCore.pyqtSignal("QString")
在课程开始时

还有最后一件事,但非常重要。您没有使用GUI,但仍在使用QObject和Qt信号机制,这取决于主Qt循环的工作情况。因此,尽管您的应用程序是非gui程序,但仍然需要一个
QApplication
对象

这是您的代码,正在运行:

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())

问题不是QThread,问题是您正在从一个没有它的类调用
connect
方法。您需要使
MyClass
继承自QObject

在GUI中,这是因为您使用的任何小部件(QDialog、QMainWindow、QWidget…)都(直接或间接)继承自QObject

要使
MyClass
QObject
继承,您只需:

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... 
我还建议您使用

除了调用了
processdone
信号外,其他一切都正常,但显然它从未触发对thread1done的调用。

我能发现的问题是您没有定义processdone信号。Qt不存在该信号。检查我留给你的链接,了解自定义信号。同时,您可以添加:

class MyProcess(QThread):
    processdone = QtCore.pyqtSignal("QString")
在课程开始时

还有最后一件事,但非常重要。您没有使用GUI,但仍在使用QObject和Qt信号机制,这取决于主Qt循环的工作情况。因此,尽管您的应用程序是非gui程序,但仍然需要一个
QApplication
对象

这是您的代码,正在运行:

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())

这听起来像是一种正确的方法是对代码进行反应的情况。与扩展QThread(或python标准库中的线程)不同的是,使用一个类来完成这项工作,并且可以用这两个类进行实例化。您可以在代码中显示gui版本和非UI版本之间的区别吗?这听起来像是一种正确的方法是对代码进行反应的情况。不是扩展QThread(或python标准库中的线程),而是使用一个类来完成这项工作,并且可以用这两个类进行实例化。您可以在代码中显示gui版本和非UI版本之间的区别吗?我知道它会像这样简单。。。我明天会试试,让你知道它是怎么回事,但我希望这个答案会得到验证。:)我在上面添加了代码。我应该做哪些更改来继承QObject?我的GUI版本可以工作,因为(正如你所说)我继承了QMainWindow,但我不能在非GUI逻辑中使用QMainWindow。你不是一个痛苦的人,但你必须公平。最初的提示(关于QThreads)和另一个关于如何继承的问题已经得到了回答。别以为如果你核对答案,我就不再帮你了,恰恰相反。关于您的上一条评论,python定义类时,
\uuuu init\uuu
方法可能出了问题。这确实有点难知道,因为我没有您的代码,因为我无法重现错误。我发现了上一条评论的语法错误。我已经更新了上面的完整工作代码。除了调用processdone信号外,其他一切都正常工作,但显然从未触发对thread1done的调用?您阅读了我关于新型信号和插槽支持的建议了吗?链接在答案的末尾。我发现的问题是您没有定义
processdone
信号。Qt不存在该信号。查看我留给你的链接,了解自定义信号。我知道它会像这样简单。。。我明天会试试,让你知道它是怎么回事,但我希望这个答案会得到验证。:)我在上面添加了代码。我应该做哪些更改来继承QObject?我的GUI版本可以工作,因为(正如你所说)我继承了QMainWindow,但我不能在非GUI逻辑中使用QMainWindow。你不是一个痛苦的人,但你必须公平。最初的提示(关于QThreads)和另一个关于如何继承的问题已经得到了回答。别以为如果你核对答案,我就不再帮你了,恰恰相反。关于您的上一条评论,python定义类时,
\uuuu init\uuu
方法可能出了问题。这确实有点难知道,因为我没有您的代码,因为我无法重现错误。我发现了上一条评论的语法错误。我已经更新了上面的完整工作代码。