Ich versuche ein einfaches, leichtgewichtiges System zur Aufzeichnung von Qt-GUI-Ereignissen und zur Wiedergabe von einem Skript zu implementieren. Ich dachte, das wäre ziemlich einfach, wenn man die Magie von Qts Event-System benutzt, aber ich stoße auf ein Problem, das ich nicht verstehe.
Hier ist eine kurze Zusammenfassung dessen, was ich mache:
AUFNAHME:
Ich verwende QApplication.instance().eventFilter()
, um alle GUI-Ereignisse zu erfassen, die mich interessieren * und sie in einem Python-Skript zu speichern, in dem jeder Schritt etwa so aussieht:
WIEDERGABE:
Ich führe einfach das obige Skript in einem Worker-Thread ( non-GUI ) aus. (Ich kann den GUI-Thread nicht verwenden, da ich weiterhin Skriptereignisse an die Anwendung senden möchte, selbst wenn die Ereignisschleife 'main' blockiert ist, während ein modaler Dialog-Eventloop ausgeführt wird.)
Die wichtigen Dinge passieren in meiner Funktion post_event()
, die zwei Dinge tun muss:
QApplication.postEvent(obj, recorded_event)
auf
obj
ausgeführt wird. QApplication.processEvents()
Nachdem der zweite Teil abgeschlossen ist, erwarte ich, dass alle Effekte des ersten Teils (des aufgezeichneten Ereignisses) abgeschlossen sind , da das spezielle Ereignis nach in die Warteschlange gestellt wurde aufgezeichnetes Ereignis.
Das ganze System meist scheint bei Mausereignissen, Schlüsselereignissen usw. gut zu funktionieren. Aber ich habe ein Problem mit QAction
handlers, wenn ich versuche, Ereignisse für mein Haupt-% abzuspielen. co_de%.
Egal was ich versuche, es scheint, dass Ich kann nicht zwingen, dass mein Playback-Thread den Abschluss aller QMenuBar
Handler blockiert , die sich aus dem Klicken auf meine QAction.triggered
-Elemente ergeben. Soweit ich das beurteilen kann, gibt QMenu
zurück, bevor der QApplication.processEvents()
-Handler fertig ist.
Gibt es etwas Besonderes an QAction
widgets oder QMenu
signals, das die normalen Regeln für QAction
und / oder QApplication.postEvent()
bricht? Ich benötige eine Möglichkeit, die Verarbeitung meiner QApplication.processEvents()
QMenu
Handler zu blockieren.
[*] Nicht jedes Ereignis wird aufgezeichnet. Ich zeichne nur QAction
-Ereignisse auf, und ich filtere auch ein paar andere Typen heraus (z. B. spontaneous()
-Ereignisse und normale Mausbewegungen).
[**] Dies ist wichtig, da sich das nächste Ereignis im Skript möglicherweise auf ein Widget bezieht, das durch das vorherige Ereignis erstellt wurde .
Ich denke, Ihr Problem könnte am besten durch die Verwendung von QFuture und QFutureWatcher behoben werden (das heißt, wenn Sie den QtConcurrent-Namespace für Threads und nicht QThreads verwenden). Grundsätzlich behandelt das Qt-Event-Handling-System Ereignisse NICHT unbedingt in der Reihenfolge, in der sie gepostet werden. Wenn Sie blockieren müssen, bis eine bestimmte Aktion abgeschlossen ist und Sie diese Aktion in einem separaten Thread ausführen, können Sie das von QtConcurrent :: run () mit einem QFutureWatcher zurückgegebene QFuture-Objekt verwenden, um zu blockieren, bis der betreffende Thread seine Verarbeitung beendet hat .
Etwas anderes ist die Art, wie Sie mit Ereignissen umgehen. Wenn Sie QApplication.postEvent () verwenden, wird das Ereignis, das Sie erstellen, der Ereigniswarteschlange des Empfängers hinzugefügt, um später behandelt zu werden. Hinter den Kulissen kann Qt diese Ereignisse neu anordnen und komprimieren, um Prozessorzeit zu sparen. Ich vermute, das ist eher dein Problem.
Ziehen Sie in Ihrer Funktion, die die Wiedergabe behandelt, die Verwendung von QCoreApplication :: processEvents () in Betracht, die erst zurückgegeben wird, wenn alle Ereignisse abgeschlossen sind. Dokumentation für QCoreApplication ist hier.
QMenu-Widgets und QAction-Signale sind ein Sonderfall. QMenu hat eine exec () -Funktion, die normalerweise für Popups verwendet wird. Ich vermute (aber ich weiß nicht sicher), dass QMenuBar diesen Mechanismus verwenden würde, wenn er ein normales Pull-Down-Menü öffnet. Die Docs sind sich darüber nicht im Klaren, aber Menus verhalten sich ähnlich wie Dialogfelder, da sie alle anderen Benutzeraktivitäten blockieren. Wie würde Qt dies tun, außer, Menüs eine eigene Ereignisschleife zu geben? Ich kann nicht alle Leerstellen aus den Informationen in Ihrem Beitrag ausfüllen, aber ich sehe nicht, wie Ihr Wiedergabe-Thread mit einer neuen Ereignisschleife zurechtkommen würde.