python QObject (QPlainTextEdit) & 多线程问题
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2104779/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
QObject (QPlainTextEdit) & Multithreading issues
提问by smerlin
Im currently trying to learn Networking with Python asyncore and pyqt4.
我目前正在尝试使用 Python asyncore 和 pyqt4 学习网络。
I coded a small server, which basically listens on some port, and resends all messages it recieves to the sender.
我编写了一个小型服务器,它基本上侦听某个端口,并将它收到的所有消息重新发送给发件人。
Since both qts QApplication.exec_()
and asyncore.loop()
are functions which never return i could not start them both in one thread, so i stared asyncore.loop()
in a seperate daemon thread.
由于 qtsQApplication.exec_()
和asyncore.loop()
都是永远不会返回的函数,我无法在一个线程中启动它们,所以我盯着asyncore.loop()
一个单独的守护进程线程。
Whenever my server class (derived from asyncore.dispatcher
) establishes or drops a connection, or sends/recieves a message, it calls methods of my window class (derived from QtGui.QMainWindow
), which displays the information in a QPlainTextEdit
.
每当我的服务器类(派生自asyncore.dispatcher
)建立或断开连接,或发送/接收消息时,它都会调用我的窗口类(派生自QtGui.QMainWindow
)的方法,该类在QPlainTextEdit
.
But the text is not visible, unless you mark the text with the mouse.
但是文本是不可见的,除非你用鼠标标记文本。
Python console displays following error msg:
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().)
I read on some forum, that this may be caused by calling qt-functions from another Thread, and that using signals & slots instead of plain function calling may fix the issue, but i have tried signals aswell, and i still get this error.
我在某个论坛上读到,这可能是由从另一个线程调用 qt 函数引起的,并且使用信号和插槽而不是普通函数调用可能会解决该问题,但我也尝试过信号,但仍然出现此错误。
So, (if that is really the cause of my problems) whats the correct way to call methods of an qt object from another thread ?
那么,(如果这真的是我的问题的原因)从另一个线程调用 qt 对象的方法的正确方法是什么?
EDIT More Info:the asyncore.loop() call is located in the child thread, well its not really blocking, but only during the runtime of asyncore.loop() my Server class (asyncore.dispatcher) can do networking. So, during the runtime of asyncore.loop() the methods of my Server class ARE called by asyncore.loop() (=child thread), and in these i tried to emit signals to the window class running in the main thread
编辑更多信息:asyncore.loop() 调用位于子线程中,它并没有真正阻塞,但只有在 asyncore.loop() 的运行时我的服务器类 (asyncore.dispatcher) 才能进行网络连接。因此,在 asyncore.loop() 运行时,我的 Server 类的方法被 asyncore.loop()(=子线程)调用,并且在这些方法中,我尝试向在主线程中运行的窗口类发出信号
EDIT:Seems like i got it working now, i had some errors in my code, everything works as intended with signals now.
编辑:似乎我现在可以正常工作了,我的代码中有一些错误,现在一切都按预期工作。
EDIT:small example: http://paste2.org/p/635612(dead link)
编辑:小例子:http: //paste2.org/p/635612(死链接)
回答by Rob H
It appears you're trying to access QtGui classes from a thread other than the main thread. Like in some other GUI toolkits (e.g. Java Swing), that's not allowed. From the Threads and QObjectsweb page:
您似乎正在尝试从主线程以外的线程访问 QtGui 类。就像在其他一些 GUI 工具包(例如 Java Swing)中一样,这是不允许的。从线程和 QObjects网页:
Although QObject is reentrant, the GUI classes, notably QWidget and all its subclasses, are not reentrant. They can only be used from the main thread.
尽管 QObject 是可重入的,但 GUI 类,尤其是 QWidget 及其所有子类,是不可重入的。它们只能在主线程中使用。
A solution is to use signals and slots for communication between the main thread (where the GUI objects live) and your secondary thread(s). Basically, you emit signals in one thread that get delivered to the QObjects via the other thread. The page I linked to above has a good discussion of this. Actually, the whole section on Thread Support in Qtis a good read.
一种解决方案是使用信号和插槽在主线程(GUI 对象所在的位置)和辅助线程之间进行通信。基本上,您在一个线程中发出信号,这些信号通过另一个线程传递给 QObject。我上面链接的页面对此进行了很好的讨论。实际上,关于Qt中的线程支持的整个部分都值得一读。
One potential issue you could run into is that, normally, to get full signals and slots support working across threads, you need to start an event loop in the child thread using QThread::exec()
(or the PyQt equivalent) so that signals can be delivered to slots in the QObjects that live there. In your case, it sounds like you're making a blocking call to asyncore.loop()
, which will prevent you from doing this. But, if you only need to emit signals in one direction (from the child thread to widgets in the main thread), I don't think you'll have a problem.
您可能遇到的一个潜在问题是,通常,要获得完整的信号和插槽支持跨线程工作,您需要使用QThread::exec()
(或 PyQt 等效项)在子线程中启动一个事件循环,以便将信号传递到住在那里的 QObjects。在您的情况下,听起来您正在对 进行阻塞调用asyncore.loop()
,这将阻止您执行此操作。但是,如果您只需要在一个方向(从子线程到主线程中的小部件)发出信号,我认为您不会有问题。