Подтвердить что ты не робот

Комбинирование контура внешнего события с Qt

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

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

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

Спасибо!

4b9b3361

Ответ 1

В последнее время я не слишком много развивал 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() в lines 106 через 117 с

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

и смените подпись в line 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

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

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

Ответ 3

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

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

Не очень хорошее решение.