32 votes

Combiner une boucle d'événement externe avec des Qt

Je suis en train de construire un Qt client de l'open-source client/serveur 4X jeu de stratégie en Milliers de Parsecs. Ce un Google Summer of Code du projet. Je suis toutefois retrouver dans une impasse. Fondamentalement, les interfaces client avec le serveur via un C++ couche de protocole qui facilite la communication client/serveur. Le protocole de la documentation est disponible ici.

Maintenant, mon problème est que le protocole exige que vous créez une sous-classe de la virtuel EventLoop classe (lien) de votre client. Il est un exemple SimpleEventLoop utilisé pour la console de clients sur le même lien. J'ai du mal à comprendre comment je peux concevoir ma propre boucle d'événement de la sous-classe qui gère le protocole événements, tandis que d'accrochage dans 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 une expérience de liaison externe de la boucle d'événement avec une application Qt? J'ai aussi trouvé cet exemple sur l'intervalle Qt page, mais il n'était pas très utile - ou, au moins, je n'ai pas vraiment le comprendre.

Merci!

33voto

stephan Points 6006

Je n'ai pas fait trop de développement Qt récemment, mais si je me souviens correctement, vous pouvez appeler QApplication::processEvents() au sein de votre propre boucle d'événements (au lieu de départ de l'intervalle Qt boucle principale par le biais QApplication::exec())

Edit: j'ai saisi l'occasion d'une lente dimanche matin pour essayer / apprendre quelque chose sur PyQt (bindings Python de Qt) et bricolé une preuve-de-concept de code ci-dessous. De remplacer l'appel à QApplication::exec() avec un événement personnalisé boucle basée sur QApplication::processEvents() semble fonctionner.

J'ai rapidement 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 l' SimpleEventLoop::runEventLoop(). Pour l'ajouter à la boucle principale, je serais probablement remplacer le tv intervalle de l' select() fonction dans les lignes 106 par 117 avec

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

et modifier la signature en ligne, 89 de void SimpleEventLoop::runEventLoop(QApplication *app). Elle doit être fine pour ajouter à votre habitude Qt trucs à votre mise en œuvre de la client (votre remplacement d' tpclient-cpptext main.cpp)

Ressemble à un hack, si. Je serais probablement commencer avec quelque chose comme ça pour commencer. Je pense que votre idée de l'habillage TPSocket , et le minuteur à l'intérieur de l'intervalle Qt respectifs des concepts afin de les transmettre, avec l' QAbstractEventDispatcher de la QEventLoop est la meilleure solution à long terme. Ensuite, elle devrait être suffisante pour que votre runEventLoop() simplement des appels QApplication::exec(). Mais je n'ai jamais utilisé QAbstractEventDispatcher avant, afin de prendre mes propos 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)

2voto

jamuraa Points 2581

Je serais probablement le code de la boucle d'événement à des threads séparés. Vous pouvez gérer les événements de la bibliothèque dans une classe, et de générer des signaux qui seront ensuite traitées par le principal Qt eventloop chaque fois que vous voulez (appel QApplication::processEvents() si nécessaire, dans les opérations longues). Le seul truc c'est s'assurer que votre événement externe de la boucle est une macro q_object, de sorte qu'il sait comment émettre les signaux que vous vous souciez.

Il y a d'autres thread questions, comme jamais (jamais) de la peinture dans un thread qui n'est pas le principal QT fil.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X