Heute mal seit langer Zeit wieder ein längerer Beitrag mit einem kleineren Tutorial.

Aktuell bin ich mal wieder dabei eine Qt-(Desktop)-Anwendung für einen Kunden zu erstellen, mal wieder ganz von Null auf, inkl. Analyse, Wireframe-Konzept, Klickdummy, Umsetzung, Dokumentation und Test.

Bis auf Nutzung als C++-Editor habe ich im Qt-Creator lange Zeit nichts mehr mit Oberflächen-/Formularen entwickelt, die anfängliche Idee, die neue Anwendung mit QML zu entwickeln habe ich nach einer Weile QML-Tutorials anschauen und kurzer Überlegung dann verworfen und entwickle das neue Tool nun wieder als Qt-Widget-Anwendung. Wie sagt man so schön:

Schuster bleib bei Deinen Leisten

In meiner bisher umfangreichsten Qt-Desktop-Anwendung “Laserfeed” ist vieles historisch gewachsen, manche Dinge müsste ich eigentlich mal dringend umstellen, u.a. alle Tab-Inhalte als separate Widget-Klassen definieren. Aktuell ist da der Großteil noch im Haupt-Form untergebracht, was diese Klasse echt katastrophal zu pflegen macht.

Mit Umsetzung der neuen Anwendung möchte ich das diesmal gleich von Anfang an richtig machen. Daher habe ich jeden Screen erst mal als eigene Formular-Klasse definiert und das entsprechende Layouting vorgenommen. Anschließend habe ich in dem MainWindow ein StackWidget angelegt und dort die entsprechende Anzahl an Seiten eingefügt. In jede Seite kommt ein Widget und wird über ein Layout entsprechend auf die Größe des StackWidgets gesetzt.

Diese Widgets werden dann als “Delegate” eingerichtet, das macht man, indem man im Qt-Creator rechte Maustaste auf das Widget klickt und “Als Platzhalter für benutzerdefinierte Klasse festlegen…” auswählt.

Das öffnet einen neuen Dialog, in dem man dann den entsprechenden Klassennamen hinterlegt.

Tragt dort unter Klassenname den Namen Eurer Form-Klasse ein, passt ggf. die include-Datei an (ich habe z.B. alle forms im Unterverzeichnis forms angelegt) und vergesst nicht mit “Hinzufügen” diese Klasse einzutragen. Wählt dann den neuen Eintrag in dem oberen Treeview aus und bestätigt die Auswahl mit “Anwenden”.

Nun sind die Formulare zwar als separate Formular-Klasse hinterlegt werden aber trotzdem im MainWindow “verlinkt”.

Für meine Anwendung soll es eine Startseite geben, auf der eine entsprechende Aktion gewählt werden kann. Diese Aktion öffnet dann ein entsprechendes Formular. Im Formular gibt es u.a. einen OK- und Abbrechen-Button.
Wird auf OK bzw. Abbrechen geklickt, soll wieder zum Startbildschirm gewechselt werden. Wie bringt man aber die Delegates dazu, mit dem Haupt-Screen zu interagieren? Ja klar, über Signal -> Slots.

Dazu definiere ich in den Formular-Klassen jeweils signals für ok und abbrechen, z.B:

    signals:
     void okSelected();
     void abbrechenSelected();

Im entsprechenden Formular werden dann die Button-Drücke mit Aktionen hinterlegt. Das macht man im Designer, indem man auf den entsprechenden Button rechtsklickt und “Slot anzeigen…” wählt.

Es öffnet sich wieder ein Fenster, dort wählt man das entsprechende Signal aus, dass man implementieren möchte, in unserem Fall einfach clicked() ohne Parameter (ist ja kein Togglebutton).

Drückt man OK, legt Qt automatisch ein entsprechenden Slot an. Im Code schicken wir dann wieder ein Signal, je nach Button.

OK-Button:

emit okSelected();

Abbrechen-Button:

emit abbrechenSelected();

Nun müssen die Signale noch im Hautpwindow ausgewertet werden. Das kann man entweder auf händische Weise machen, indem man händisch die entsprechenden Slots im Header des Hauptfensters anlegt:

  private slots:
      void widget1OkSelectedSlot();
      void widget1AbbrechenSelectedSlot();

und im Konstruktor die Dinge miteinander verknüpft (wenn unser Formular als widget1 “referenziert ist”):

   connect(ui->widget1, SIGNAL(okSelected()), this, SLOT(widget1OkSelectedSlot()));
   connect(ui->widget1, SIGNAL(abbrechenSelected()), this, SLOT(widget1AbbrechenSlot()));

Alternativ bzw. einfacher geht das direkt im Designer. Irgendwie habe ich den Weg gar nicht mehr in Erinnerung gehabt, aber so geht es eigentlich viel besser.

Öffnet dazu wiederum das HauptWindow im Designer und klickt mit rechter Maustaste auf das entsprechende Formular-Widget.
Dort sollte es einen Eintrag: “Signale/Slots ändern…”.

Ist das nicht der Fall überprüft bitte noch einmal, ob dem Widget auch wirklich mit der Platzhalter-Methode weiter oben eine eigene Formular-Klasse zugewiesen wurde.

Im nachfolgenden Dialog legt ihr um unteren Teil: Signale mit dem +-Symbol zwei Signale an und zwar okSelected() und abbrechenSelected().

Nun können wir analog zu den Button-Klick-Signale auch die beiden neuen Signale implementieren, indem wir wiederum auf dem Widget die rechte Maustaste klicken und wiederum Slot anzeigen… anklicken.

Nun öffnet sich wiederum der Dialog mit der Auswahl und siehe da, dort werden auch unsere beiden Signale angezeigt.

Wählt das entsprechende Signal aus (z.B. okSelected()), klickt auf OK und Qt-Creator erzeugt für Euch den entsprechenden Slot im Haupt-Window. Dort könnt ihr die entsprechende Logik hinterlegen, was passieren soll, wenn der OK-Button des entsprechenden Widgets gedrückt wurde, ohne manuell Slots anzulegen und mit connect-Statements die Sachen händisch zu verknüpfen.