我目前正在尝试使用Python asyncore和pyqt4学习网络。
我编写了一个小型服务器,它基本上监听某个端口,并将收到的所有邮件重新发送给发件人。
由于qts QApplication.exec_()
和asyncore.loop()
都是永不返回的函数,因此我无法在一个线程中启动它们,所以我在一个单独的守护程序线程中查看asyncore.loop()
。
每当我的服务器类(派生自asyncore.dispatcher
)建立或删除连接,或发送/接收消息时,它都会调用我的窗口类(派生自QtGui.QMainWindow
)的方法,该方法显示信息在QPlainTextEdit
。
但是文本不可见,除非您用鼠标标记文本。
Python控制台显示以下错误消息:
QObject::connect: Cannot queue arguments of type 'QTextBlock'
(Make sure 'QTextBlock' is registered using qRegisterMetaType().)
QObject::connect: Cannot queue arguments of type 'QTextCursor'
(Make sure 'QTextCursor' is registered using qRegisterMetaType().)
我在一些论坛上看到,这可能是由于从另一个线程调用qt-functions,以及使用信号&插槽而不是普通函数调用可以解决问题,但我也试过信号,我仍然得到这个错误。
所以,(如果那确实是我的问题的原因)是什么从另一个线程调用qt对象的方法的正确方法?
编辑更多信息: asyncore.loop()调用位于子线程中,它不是真正的阻塞,但只有在asyncore.loop()的运行时,我的Server类(asyncore.dispatcher)才能进行网络连接。 因此,在asyncore.loop()的运行时期间,我的Server类的方法由asyncore.loop()(=子线程)调用,并且在这些i中 试图向主线程中运行的窗口类发出信号
编辑:好像我现在正在使用它,我的代码中出现了一些错误,现在所有信号都按预期工作。
编辑:小例子:http://paste2.org/p/635612 (死链接)
答案 0 :(得分:10)
您似乎正在尝试从主线程以外的线程访问QtGui类。与其他一些GUI工具包(例如Java Swing)一样,这是不允许的。来自Threads and QObjects网页:
虽然QObject是可重入的,但是GUI 类,尤其是QWidget及其所有 子类,不可重入。他们 只能在主线程中使用。
解决方案是使用信号和插槽在主线程(GUI对象所在的位置)和辅助线程之间进行通信。基本上,您在一个线程中发出信号,通过另一个线程传递给QObject。我上面链接的页面对此进行了很好的讨论。实际上,关于Thread Support in Qt的整个部分是一本很好的读物。
您可能遇到的一个潜在问题是,通常,要获得完整的信号和插槽支持跨线程工作,您需要使用QThread::exec()
(或等效的PyQt)在子线程中启动事件循环,以便信号可以传递到生活在那里的QObject中的插槽。在你的情况下,听起来你正在对asyncore.loop()
进行阻止调用,这会阻止你这样做。但是,如果你只需要在一个方向发射信号(从子线程到主线程中的小部件),我认为你不会有问题。