Peignage un Événement Externe Boucle avec Qt

je construis un client Qt pour le jeu de stratégie open-source client / server 4X Mille Parsecs. Ce un Google Summer of Code du projet. Je suis toutefois retrouver dans une impasse. Fondamentalement, le client se connecte avec le serveur via une couche de protocole C++ qui facilite la communication client/serveur. La documentation du protocole est disponible ici.

maintenant mon problème est que le protocole vous demande de créer une sous-classe de la classe EventLoop virtuelle (lien) dans votre client. Il y a un exemple SimpleEventLoop utilisé pour les clients console sur le même lien. J'ai du mal à comprendre comment je peux concevoir ma propre sous-classe de boucle d'événements qui gère les événements du protocole tout en se connectant à L'application Qt en même temps. Mes recherches m'a conduit à croire QAbstractEventDispatcher est la classe Qt je veux utiliser, mais la documentation semble assez mince et je ne sais pas exactement comment je pourrais faire.

quelqu'un d'autre a-t-il de l'expérience dans la liaison de boucles d'événements externes avec une application Qt? J'ai aussi trouvé ce exemple sur la page Qt mais ça n'a pas été très utile - ou du moins je ne l'ai pas vraiment compris.

Merci!

29
demandé sur Neil G 2009-06-27 01:21:28

3 réponses

je n'ai pas fait trop de développement Qt récemment, mais si je me souviens correctement, vous pouvez appeler QApplication::processEvents() dans votre propre boucle d'événements (au lieu de lancer la boucle principale Qt par QApplication::exec())

Edit: j'ai profité d'un dimanche matin lent pour tester / apprendre quelque chose sur PyQt (Python bindings pour Qt) et a assemblé un code de validation de principe ci-dessous. De remplacer l'appel à QApplication::exec() avec une boucle d'événement personnalisée basée sur QApplication::processEvents() semble au travail.

j'ai également regardé simpleeventloop.cpp et tpclient-cpptext main.cpp. Apparemment, il devrait être bien tout simplement à ajouter QApplication::processEvents() quelque part dans la boucle principale de SimpleEventLoop::runEventLoop(). Pour l'ajouter à la boucle principale, je serais probablement remplacer le tv intervalle pour le select() function lignes 106117

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

et changer la signature en ligne 89void SimpleEventLoop::runEventLoop(QApplication *app). Il ne devrait pas être plus mal d'ajouter vos trucs Qt habituels à votre implémentation du client (votre remplacement de tpclient-cpptext main.cpp)

Ressemble à un hack. Je commencerais probablement par quelque chose comme ça pour commencer. Je pense que votre idée de l'emballage TPSocket et le minuteur dans les concepts respectifs de Qt afin de les transmettre avec le QAbstractEventDispatcherQEventLoop est le mieux solution à long terme. Il devrait alors être suffisant que votre runEventLoop() simplement des appels QApplication::exec(). Mais je n'ai jamais utilisé QAbstractEventDispatcher avant, donc prenez mes commentaires pour ce qu'ils sont.

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)
30
répondu stephan 2016-08-12 14:30:30

Je coderais probablement les boucles d'événements pour être des threads séparés. Vous pouvez gérer les événements de la bibliothèque dans une classe, et lui faire générer des signaux qui seront ensuite manipulés par L'eventloop Qt principal quand vous le voulez (appelez QApplication::processEvents() si nécessaire dans les opérations longues). Le seul truc à faire est de s'assurer que votre boucle d'événement externe est un Q_OBJECT pour qu'il sache émettre les signaux auxquels vous tenez.

il y a d'autres problèmes de fil, tels que jamais (jamais) peindre dans un fil qui n'est pas le fil QT principal.

2
répondu jamuraa 2009-06-26 21:41:00

La documentation de Qt dit:

pour que votre application effectue un traitement inactif (c'est-à-dire l'exécution d'une fonction spéciale chaque fois qu'il n'y a pas d'événements en attente), utilisez un QTimer avec 0 timeout.

Pas une jolie solution.

1
répondu Timmmm 2015-06-04 14:17:27