Dialoge per Aufruf

Vor einem Jahr waren Dialoge bereits für mich ein Thema.
Jetzt stellt sich die Frage, wie man die Ergebnisse von Dialogen auch als Funktionsaufruf - also “synchron” per “blocking-call” - erhalten kann.

Oder anders gefragt: Wie wird eine UI Message-Loop innerhalb einer anderen UI-Message-Loop für begrenzte Zeit angekurbelt?


WinAPI

Die Windows API ist stets eine Blaupause für mich, wenn es um Fragen zu Message-Loops usw. geht. Denn empfängt die Funktion GetMessage() eine Nachricht, und DispatchMessage() leitet das Ereignis an die entsprechende Callback-Routine der Fensterklasse weiter.

Man implementiert die Message-Loop immer selbst, in dem GetMessage() und DispatchMessage() in einer Endlosschleife laufen, die nur durch WM_QUIT oder programmspezifische Logiken verlassen werden soll.

Ein Dialog, kann seine eigene Schleife einbauen und die so lange laufen lassen, wie der Dialog offen ist und dann zur Elternschleife zurückkehren.

graph TD LOOP[[Main Message Loop]] --> GET GET(GetMessage) --> DISP DISP(DispatchMessage) --> LOOP DISP -- Event --> DLG DLG[[Dialog Message Loop]] --> DLGGET DLGGET(GetMessage) --> DLGDISP DLGDISP(DispatchMessage) --> DLGIF[IF continue_dialog] DLGIF -- yes --> DLG DLGIF -- no --> DISP

Alles läuft in einem Thread und jeder Dialog führt seine eigene Schleife aus, so lange er sie braucht, bis er die Kontrolle wieder eine Ebene zurückgibt. So kann man auch mehrere Dialoge übereinander legen.

GTK

Vor GTK hatte ich bei dem Thema Angst, dass mir ein solche Zugriff nicht möglich hätte sein können.
Doch zu meinem Glück konnte ich die Funktion gtk_main_iteration finden und schon war alles gut.

Ein Aufruf dieser Funktion ist das Äquivalent eines WINAPI GetMessage - DispatchMessage Paares und somit braucht eine Dialog-Funktion nur diese Routine in einer Schleife immer wieder aufrufen, bis der Dialog geschlossen werden kann.

Das Aufruf-Diagramm ist hier viel einfacher, weil auf main-Ebene die Schleife nicht selbst implementiert wird, sondern gtk_main() seine eigene Magie walten lässt.

graph TD MAIN[[GTK main run]] --> GTK(gtk_main) GTK -- Event --> DLG DLG[[Dialog Message Loop]] --> DLGITER DLGITER(gtk_main_iteration) --> DLGIF[IF continue_dialog] DLGIF -- yes --> DLG DLGIF -- no --> GTK

Fazit

Kombiniert man dieses Wissen mit dem Feature, dass ein Top-Level Fenster immer vor einem anderen Fenster gereiht ist und dieses andere Fenster für Events “deaktiviert” ist, hat man jetzt einen Dialog, der per Funktionsaufruf so lange seine eigene Schleife betreibt, bis er fertig ist.

Man ruft den Dialog also synchron auf und hat damit einen einfachen und übersichtlichen Programmaufbau geschaffen.

Ich habe basierend auf dieser Technik sofort eine Input-Box Klasse zum eingeben von Texten erstellt und das Ergebnis hat wie erwartet funktioniert.

Nun steht dem Einsatz von weiteren selbst-definierten Dialogen nichts mehr im Weg.