Dialoge

Es war - glaube ich - im Religionsunterricht in der Schule, wo lang und breit erklärt wurde DIA und LOGOS bedeutet, dass zwei miteinander reden, also Worte auswechseln.

Um so verwirrter war ich, als ich Microsoft Word und Excel die Erstellung von “Dialogen” vorfand. … wie sollte denn der PC mit mir “reden”?

In der Programmierung sind Dialog-Fenster und besonders die “modalen” Dialoge ein Spezialfall, dessen Implementierung seine Tücken haben kann.


Definition

Dialoge geben dem Benutzer die Möglichkeit sich mit dem Programm “auszutauschen”.

  1. Der Benutzer will etwas haben und öffnet ein Dialog-Fenster.
  2. Das Programm will etwas wissen, der Benutzer gibt es ein.
  3. Der Benutzer fordert ein Ergebnis ein, das Programm liefert.

Theoretisch ist jede GUI, wo man mit einem Eingabegerät etwas ändern kann und eine Anzeige etwas präsentiert eine Form von Dialog.

In der Entwicklung (in erster Linie unter Windows), finden wir aber unterschiedliche Definitionen dazu:

  • Ein Fenster wird mit einer DIALOG Resource erstellt.
    Das witzige daran ist, dass man per Windows Ressourcen keine Nicht-Dialoge erzeugen kann. Man könnte also behaupten, jede UI, die auf einer Resource-Datei (*.rc) basiert ist ein Dialog, und alles was man per API erzeugt ist eben keiner … OK, Spaß bei Seite, aber so sind Dialoge entstanden. Es gab ein Hauptfenster, dass man individuell zusammengecodet hatte, und für die Einstellungen wurden Unterfenster angezeigt, wo man Text und Checkboxen verändern konnte. Und für diese einfachen Label, Textbox und Checkbox Zusammenstellungen hat Microsoft ein eigenes Resource-Format bereitgestellt um diese Art der Entwicklung zu vereinfachen.
  • Man kann zwischen Controls mit der TAB-Taste hin- und herwechseln.
    Genau, denn wer in seiner Message-Pump zwischen GetMessage() und TranslateMessage() den Aufruf von IsDialogMessage() vergisst, wird feststellen, dass TABs nicht funktionieren.
    Wenn ich das also richtig deute, ist die Steuerung per TAB Taste ein essentieller Bestandteil von Dialogen.
  • Ein Fenster wird über einem anderen angezeigt und das hintere ist so lange deaktiviert, bis das Dialog-Fenster geschlossen wird.
    Das nennt man einen “modalen” Dialog. Er blockiert die restliche UI, bis man mit den Eingaben auf dem Dialog fertig ist. In fast allen Frameworks wird das als eigener Fall behandelt. Man kann ein Fenster “anzeigen”, oder es als “modalen Dialog anzeigen” lassen. Offenbar bin ich nicht der einzige, der hier zu anderen Codekunststücken greifen muss als bei “normalen” Fenstern.
  • Ein Programm wartet so lange (blockiert), bis der Benutzer eine Eingabe getätigt und diese bestätigt hat.
    Das trifft auf jeden Kommandozeileninterpreter zu und auch diese Form der Kommunikation zwischen Benutzer und Programm wird gelegentlich als Dialog bezeichnet. Nun gut … das ist eine andere Geschichte
  • Und ich behaupte: Wenn etwas einen “OK” und einen “Cancel” Button hat, ist es ein klassischer Dialog.
    Ist doch klar, seit den ersten Windows Versionen steht in den Hilfen und Bedienanleitungen:

    Um XYZ anzuwenden, öffnen Sie den Dialog mit ABC, nehmen Sie die entsprechenden Änderungen vor und Klicken Sie auf “OK” um die Änderungen zu bestätigen oder auf “Abbrechen” um mit dem vorherigen Zustand weiterzuarbeiten.

    Also: Dialoge haben einen “OK” und “Cancel” Button.

GATE Implementierung

Im GATE Projekt zählt eigentlich nur die Anzeige eines “modalen” Fensters als Dialog. TABs sollten auch auf Nicht-Dialogen arbeiten.

Doch unter den Gesichtspunkten der Plattformunabhängigkeit ist die Umsetzung herausfordernd.

Unter Windows wäre alles so einfach. Man könnte ein blockierende Funktion erdenken, z.B.: showAsDialog(form) die intern eine zweite Nachrichtenschleife implementiert und diese erst mit einem Dialog-Close Event wieder verlässt.

So könnte man das Ergebnis des Dialogs sogar als Rückgabewert “verkaufen”.

Doch andere Frameworks unterstützen diese Methode nicht. Deren Nachrichtenschleife ist eine Blackbox, die genau einmal aufgerufen werden darf.

Also bleibt mir nur die Möglichkeit, die Fenster in die richtigen Zustände zu versetzen und das ganze über zwei Routinen laufen zu lassen:

  • gate_ui_form_begin_dialog(); zeigt eine Form als Dialog über ihrem Owner an, nachdem sie eben diesen disabled hat.
  • und gate_ui_form_end_dialog(); setzt den Zustand zurück, indem die Dialog-Form unsichtbar geschaltet wird und der Owner wieder enabled wird.

Wie jetzt Dialog-Ergebnisse ausgetauscht werden, muss jeweils separat implementiert werden. Doch nachdem man aus dem unsichtbaren Dialog die Werte seiner Controls noch extrahieren kann, ist das gut machbar.

Tja, was soll man machen … In Visual Basic 6 war das noch schön, wo man über form.Show vbModal quasi den laufenden Code blockieren konnte ohne die UI zu blockieren.
Aber man kann eben nicht alles bekommen.

Wobei … ein paar “Dialoge” haben sehr wohl das blockierende Verhalten: Und zwar FilePicker und seine Verwandten. Deren APIs waren immer schon so gestrickt, dass die UI weiterlief aber der Funktionsaufruf selbst blockierte. Nur sind die eben wieder eine Blackbox und nicht direkt nachstellbar.

Fazit

Selbstgestrickte Dialoge sind nun also auch im GATE UI Framework. Und dort werden sie auch dringend benötigt. Man kann mit ihnen hervorragend Auswahlmöglichkeiten und Einstellung abbilden ohne “das Hauptprogramm” damit zu stören.

Und ich bin auch kein Fan dieser aus der Webentwicklung stammenden Unart ein Panel über das Hauptfenster zu ziehen und darauf Dialog-Inhalt darzustellen.
Diese Dinger sind eben keine echten Top-Level Fenster und können nicht auf dem Bildschirm verschoben werden. Sie verdeckten zwangsläufig Daten am Hauptfenster und es gibt immer wieder Situationen wo das extrem nervt, wenn man basierend auf Daten dort Änderungen im Dialog machen möchte … und eben diese sieht man dann nicht und kann den “Dialog” auch nicht bei Seite schieben.

Wie auch immer … Mission accomplished!

Also ab zur nächsten Aufgabe.