Расчесывание внешнего цикла обработки событий с помощью Qt - PullRequest
30 голосов
/ 27 июня 2009

Я создаю Qt-клиент для стратегии клиента с открытым исходным кодом 4X Thousand Parsec . Это проект Google Summer of Code. Я, однако, застрял в тупике. По сути, клиент взаимодействует с сервером через уровень протокола C ++, который облегчает взаимодействие клиент / сервер. Документация по протоколу доступна здесь .

Теперь моя проблема в том, что протокол требует от вас создания подкласса виртуального класса EventLoop ( link ) в вашем клиенте. Существует пример SimpleEventLoop, используемый для консольных клиентов по той же ссылке. Мне трудно понять, как я могу создать свой собственный подкласс цикла обработки событий, который обрабатывает события протокола, одновременно подключаясь к приложению Qt. Мои исследования привели меня к мысли, что QAbstractEventDispatcher - это класс Qt, который я хочу использовать, но документация кажется довольно скудной, и я не совсем уверен, как мне поступить.

Есть ли у кого-нибудь еще опыт связывания внешних циклов событий с приложением Qt? Я также нашел этот пример на странице Qt, но он не очень помог - или, по крайней мере, я его не совсем понял.

Спасибо!

Ответы [ 3 ]

33 голосов
/ 27 июня 2009

В последнее время я не слишком много занимался разработкой Qt, но если я правильно помню, вы можете вызвать QApplication::processEvents() в вашем собственном цикле событий (вместо запуска основного цикла Qt через QApplication::exec())

Редактировать: Я использовал возможность медленного воскресного утра, чтобы протестировать / узнать кое-что о PyQt (привязки Python для Qt) и собрать воедино доказательство код концепции ниже. Замена вызова на QApplication::exec() пользовательским циклом событий, основанным на QApplication::processEvents() , кажется работающим.

Я также быстро посмотрел на simpleeventloop.cpp и tpclient-cpptext main.cpp. Судя по всему, было бы неплохо просто добавить QApplication::processEvents() где-нибудь в основной цикл SimpleEventLoop::runEventLoop(). Чтобы добавить его в основной цикл, я бы, вероятно, заменил интервал tv для функции select() в строках * с 1030 * по 117 на

tv.tv_sec = 0;
tv.tv_usec = 10000;   // run processEvents() every 0.01 seconds
app->processEvents();

и измените подпись в строке 89 на void SimpleEventLoop::runEventLoop(QApplication *app). Это должно быть хорошо, если вы добавите свой обычный Qt в вашу реализацию клиента (ваша замена tpclient-cpptext main.cpp)

Похоже, что взломать. Я бы начал с чего-то подобного, чтобы начать. Я думаю, что ваша идея обернуть 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)
2 голосов
/ 27 июня 2009

Я бы, вероятно, закодировал циклы событий, чтобы они были отдельными потоками. Вы можете обрабатывать события из библиотеки в классе, и она генерирует сигналы, которые затем будут обрабатываться основным циклом событий Qt всякий раз, когда вы захотите (при необходимости вызовите QApplication :: processEvents () в длинных операциях). Единственная хитрость в этом заключается в том, чтобы убедиться, что ваш внешний цикл обработки событий - это Q_OBJECT, чтобы он знал, как излучать сигналы, которые вас волнуют.

Существуют и другие проблемы с потоками, такие как никогда (никогда) рисование в потоке, который не является основным потоком QT.

1 голос
/ 04 июня 2015

Документация Qt гласит:

Чтобы ваше приложение выполняло обработку в режиме ожидания (то есть, выполняя специальную функцию, когда нет ожидающих событий), используйте QTimer с тайм-аутом 0.

Хотя это не очень хорошее решение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...