C++ 将外部事件循环与 Qt 结合
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1051333/
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
Combing an External Event Loop with Qt's
提问by mhilmi
I'm building a Qt client for the open-source client/server 4X strategy game Thousand Parsec. This a Google Summer of Code project. I'm however stuck at a dead end. Basically, the client interfaces with the server via a C++ protocol layer that facilitates client/server communication. The protocol's documentation is available here.
我正在为开源客户端/服务器 4X 策略游戏千秒差距构建 Qt 客户端。这是一个 Google Summer of Code 项目。然而,我陷入了死胡同。基本上,客户端通过促进客户端/服务器通信的 C++ 协议层与服务器接口。该协议的文档可在此处获得。
Now my problem is that the protocol requires you to create a subclass of the virtual EventLoop class (link) in your client. There is an example SimpleEventLoop used for console clients on the same link. I'm having difficulty figuring out how I can design my own event loop subclass that handles the protocol's events while hooking into the Qt application at the same time. My research has lead me to believe QAbstractEventDispatcheris the Qt class I want to use but the documentation seems pretty slim and I'm not exactly sure how I would go about doing this.
现在我的问题是该协议要求您在客户端中创建虚拟 EventLoop 类(链接)的子类。在同一链接上有一个用于控制台客户端的 SimpleEventLoop 示例。我很难弄清楚如何设计我自己的事件循环子类来处理协议的事件,同时连接到 Qt 应用程序。我的研究使我相信QAbstractEventDispatcher是我想要使用的 Qt 类,但文档似乎非常少,我不确定我将如何去做。
Does anyone else have experience linking external event loops with a Qt application? I've also found this exampleon the Qt page but it wasn't very helpful - or at least I didn't really understand it.
有没有其他人有将外部事件循环与 Qt 应用程序链接的经验?我也在Qt 页面上找到了这个例子,但它不是很有帮助 - 或者至少我并没有真正理解它。
Thanks!
谢谢!
回答by stephan
I haven't done too much Qt development recently, but if I remember correctly, you can call QApplication::processEvents()
within your own event loop (instead of starting the Qt main loop through QApplication::exec()
)
我最近没有做过太多的 Qt 开发,但如果我没记错的话,你可以QApplication::processEvents()
在你自己的事件循环中调用(而不是通过 启动 Qt 主循环QApplication::exec()
)
Edit:I have used the opportunity of a slow Sunday morning to test-drive / learn something about PyQt(Python bindings for Qt) and cobbled together a proof-of-concept code below. Replacing the call to QApplication::exec()
with a custom event loop based on QApplication::processEvents()
seemsto work.
编辑:我利用周日早上缓慢的机会来试驾/了解有关PyQt(Qt 的 Python 绑定)的一些知识,并在下面拼凑了一个概念验证代码。QApplication::exec()
使用基于的自定义事件循环替换调用QApplication::processEvents()
似乎有效。
I have also quickly looked at simpleeventloop.cpp
and tpclient-cpptext main.cpp
. From the looks of it, it shoud be fine to just add QApplication::processEvents()
somewhere in the main loop of SimpleEventLoop::runEventLoop()
. To add it to the main loop, I would probably replace the tv
interval for the select()
function in lines 106
through 117
with
我也赶紧看了看simpleeventloop.cpp
和tpclient-cpptext main.cpp
。从它的外观来看,只需QApplication::processEvents()
在SimpleEventLoop::runEventLoop()
. 将其添加到主循环中,我可能会更换tv
为间隔select()
功能行106
通过117
与
tv.tv_sec = 0;
tv.tv_usec = 10000; // run processEvents() every 0.01 seconds
app->processEvents();
and change the signature in line 89
to void SimpleEventLoop::runEventLoop(QApplication *app)
. It should than be fine to add your usual Qt stuff to your implementation of the client (your replacement of tpclient-cpptext main.cpp
)
并将行中89
的签名更改为void SimpleEventLoop::runEventLoop(QApplication *app)
. 将您常用的 Qt 内容添加到您的客户端实现中应该没问题(您的 替换tpclient-cpptext main.cpp
)
Looks like a hack, though. I would probably start with something like this to get started. I think that your idea of wrapping TPSocket
and the timer within Qt's respective concepts in order to forward them with the QAbstractEventDispatcher
to the QEventLoop
is the better long-term solution. It should then be sufficient that your runEventLoop()
simply calls QApplication::exec()
. But I have never used QAbstractEventDispatcher
before, so take my comments for what they are.
不过,看起来像一个黑客。我可能会从这样的事情开始。我认为,你的包装的想法TPSocket
,并以与转发它们Qt的各概念中的计时器QAbstractEventDispatcher
到QEventLoop
是更好的长期解决方案。那么您runEventLoop()
只需调用QApplication::exec()
. 但我以前从未使用QAbstractEventDispatcher
过,所以请接受我的评论。
import sys
import time
from PyQt4 import QtGui
from PyQt4 import QtCore
# Global variable used as a quick and dirty way to notify my
# main event loop that the MainWindow has been exited
APP_RUNNING = False
class SampleMainWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
QtGui.QMainWindow.__init__(self)
global APP_RUNNING
APP_RUNNING = True
# main window
self.setGeometry(300, 300, 250, 150)
self.setWindowTitle('Test')
self.statusBar().showMessage('Ready')
# exit action (assumes that the exit icon from
# http://upload.wikimedia.org/wikipedia/commons/b/bc/Exit.png
# is saved as Exit.png in the same folder as this file)
exitAction = QtGui.QAction(QtGui.QIcon('Exit.png')
,'Exit'
,self)
exitAction.setShortcut('Ctrl+Q')
exitAction.setStatusTip('Exit application')
self.connect(exitAction
,QtCore.SIGNAL('triggered()')
,QtCore.SLOT('close()'))
# main menu
menubar = self.menuBar()
fileMenu = menubar.addMenu('&File')
fileMenu.addAction(exitAction)
# toolbar
self.toolbar = self.addToolBar('Exit')
self.toolbar.addAction(exitAction)
# text editor
textEdit = QtGui.QTextEdit()
self.setCentralWidget(textEdit)
#tool tip
textEdit.setToolTip('Enter some text')
QtGui.QToolTip.setFont(QtGui.QFont('English', 12))
def closeEvent(self, event):
reply = QtGui.QMessageBox.question(self
,'Message'
,"Are you sure?"
,QtGui.QMessageBox.Yes
,QtGui.QMessageBox.No)
if reply == QtGui.QMessageBox.Yes:
event.accept()
global APP_RUNNING
APP_RUNNING = False
else:
event.ignore()
# main program
app = QtGui.QApplication(sys.argv)
testWindow = SampleMainWindow()
testWindow.show()
# run custom event loop instead of app.exec_()
while APP_RUNNING:
app.processEvents()
# sleep to prevent that my "great" event loop eats 100% cpu
time.sleep(0.01)
回答by jamuraa
I would probably code the event loops to be separate threads. You can handle the events from the library in a class, and have it generate signals which will then be handled by the main Qt eventloop whenever you want (call QApplication::processEvents() if needed in long operations). The only trick to this is making sure that your external event loop is a Q_OBJECT so that it knows how to emit the signals that you care about.
我可能会将事件循环编码为单独的线程。您可以在类中处理来自库的事件,并让它生成信号,然后在需要时由主 Qt 事件循环处理(如果在长时间操作中需要,请调用 QApplication::processEvents())。唯一的技巧是确保您的外部事件循环是 Q_OBJECT,以便它知道如何发出您关心的信号。
There are other thread issues, such as never (ever) painting in a thread which is not the main QT thread.
还有其他线程问题,例如从不(永远)在不是主 QT 线程的线程中绘画。
回答by Timmmm
The Qt documentation says:
Qt 文档说:
To make your application perform idle processing (i.e. executing a special function whenever there are no pending events), use a QTimer with 0 timeout.
要使您的应用程序执行空闲处理(即在没有挂起事件时执行特殊功能),请使用超时为 0 的 QTimer。
Not a pretty solution though.
虽然不是一个很好的解决方案。