Qt für C++ Anfänger: Weitere UI-Erweiterungen

Aus Wikibooks

Wechseln zu: Navigation, Suche

Inhaltsverzeichnis

[Bearbeiten] UI File zur Subtraktion

Um den Taschenrechner nicht nur zur Addition, sondern auch zur Subtraktion verwenden zu können, muss das UI-File angepasst werden. Das UI soll der Art aussehen, dass man im Fenstermenü auswählt, ob man addieren oder subtrahieren möchte und dann in der entsprechende Maske die Werte eingibt. Ferner soll es einen Menüeintrag geben, um das Programm zu beenden. Im ersten Schritt wird das UI-File angepasst und die Menüeinträge mit Funktionen belegt.

[Bearbeiten] Änderungen im UI-File

Das bestehende File kann als Grundlage genommen werden. Das Wechseln des UIs beim Auswählen des entsprechenden Menüeintrags geschieht über ein so genanntes "Stacked Widget". Ein Stacked Widget kann man sich wie einen Block Papier vorstellen und je nach dem, welche Seite gewählt wird, sieht man eine entsprechende Ansicht. Alle schon vorhandenen UI-Elemente werden auf die erste Seite des Stacked Widgets verschoben, danach werden alle Elemente auf die zweite Seite kopiert. Dabei wird noch das Textlabel "A+B" umbenannt in "A-B". Die technischen Namen der kopierten Objekte heißen wie die ursprünglichen Objekte, enden aber mit "_2". Will man die Objekte hier also manuell anlegen, sollte dieser Name gewählt werden. Der technische Name des Stacked Widget in unserem Tutorial ist "stackedWidget". Geht man im Qt-Designer in den Preview-Modus, so sieht man für das Stacked Widget ein paar kleine Pfeile, mit denen man die verschiedenen Ansichten durchblättern kann.

Als letztes muss nun noch das Menü eingefügt werden. Sollte der UI Designer keine leere Menüleiste anzeigen kann man auf dem Reißbrett auf einer leeren Stelle im Hintergrund das Kontextmenü aufrufen und "Create Menu Bar" ausführen. Im ersten Hauptmenü, hier "Main" genannt gibt es nur einen Eintrag "Quit", im zweiten Hauptmenü "Choose" gibt es die Einträge "Add" und "Sub". Die technischen Namen der Einträge sind per Default "action<Menüeintrag>", also z.B. "actionQuit". Änderungen können wieder über den Property Editor vorgenommen werden, leider zeigt der Property Editor nicht die Daten an wenn man auf den gewünschten Menüeintrag klickt. Damit das richtige Objekt im Property Editor angezeigt wird muss man über den Object Inspector gehen, dieser muss evtl. über das Menü im Qt Designer eingeschaltet werden.

Man kann mit dem neuen UI File das Programm nun wieder übersetzen und ausführen. Man sollte die Menüleiste und deren Einträge sehen aber sonst noch keine Veränderungen.

[Bearbeiten] Menüs mit Funktionen belegen

Nun sollen die drei Menüs mit Funktionen belegt werden, das ist nun ganz einfach. Wenn man in der Doku ein wenig sucht findet man die passenden Funktionen. Hier wird nun eine etwas kürzere Beschreibung gegeben als im Kapitel zu vor. Für jeden Menüeintrag muss ein connect String in den Konstruktor eingebaut werden. Der connect String hat die Form

connect(<Menüeintrag>,SIGNAL (triggered()), this, SLOT(<Funktion>));

<Menüeintrag> ist dabei der technische Name des Menüs und <Funktion> ist eine zu implementierende Funktion die gerufen werden soll wenn der Benutzer den entsprechenden Eintrag auswählt. Für jede dieser Funktionen muss im Header-File Taschenrechner.h eine entsprechende Deklaration eingeführt werden und diese in der Quelldatei Taschenrechner.cpp implementiert werden.

[Bearbeiten] Menü Quit

Der connect String sieht hier so aus

connect(actionQuit,SIGNAL (triggered()), this, SLOT(slotClose()));

Anzumerken sei hier, dass der Slot "slotClose()" genannt wurde, man mag geneigt sein ihn einfach nur "close()" zu nennen. close ist aber eine Funktion die es in Qt schon gibt. Die Benutzung von close() als Slotname würde zu unerwünschten Verhalten führen. Generell sollte man bei der Wahl der Funktionsnamen etwas aufpassen und zu "simple" Namen meiden. Weitere Beispiele von Funktionsnamen die nicht verwendet werden können sind add und sub, wohin Add und Sub aber benutzt werden können - auch hier spielt also die Groß- und Kleinschreibung eine Rolle. Die Deklaration der Funktion slotClose() ist trivial

void slotClose();

Die Implementation der Funktion ist ebenfalls sehr simpel

void Taschenrechner::slotClose(){ 
        close();
}

Zur Erinnerung, ganz am Anfang hatten wir in main.cpp eine Code-Zeile "return a.exec()" implementiert. Wenn jetzt close() aufgerufen wird wird das aktuelle Fenster geschlossen. Ist das aktuelle Fenster das letzte Fenster so wird a.exec() angewiesen das Programm zu beenden und der return Befehl gibt den entsprechenden Status zurück. Die Funktion close() bekommt QApplication von QWidget vererbt, ist also unter QWidget zu finden. Möchte man nicht nur das Fenster schließen sondern die Applikation beenden falls noch andere Fenster offen sind so gibt es die Funktionen QCoreApplication::quit() und QCoreApplication::exit().

Nun kann die Applikation wieder neu übersetzt werden und geprüft werden ob "Quit" wirklich die Anwendung schließt. Die Funktion slotClose() ist natürlich sehr kurz da nur close() aufgerufen wird, man kann natürlich einen Slot auch direkt in dem connect String verarbeiten.

connect(actionQuit,SIGNAL (triggered()), qApp, SLOT(quit()));

qApp ist ein Makro welches die aktuelle Instanz von QApplication herausfindet.

[Bearbeiten] Menü Add

Der connect String sieht wie folgt aus

connect(actionAdd, SIGNAL(triggered()), this, SLOT(showAdd()));

Die Deklaration von showAdd() wie folgt

void showAdd();

Für die Implementation von showAdd() muss man sich überlegen wie man zwischen den Seiten des stacked Widget umschalten kann. In der Doku findet man die passende Funktion, damit sieht die Implementation wie folgt aus:

void Taschenrechner::showAdd(){
        stackedWidget -> setCurrentIndex(0);
}

Man beachte, daß die Zählung der Seiten bei Null beginnt.

[Bearbeiten] Menü Sub

Das Menü Sub wird implementiert wie das Menü Add, man ersetze einfach Add durch Sub. Ferner muss darauf geachtet werden, dass der Index von Null auf Eins geändert wird damit auch wirklich die richtige Seite angezeigt wird.

Beim folgenden Coding ist noch zu beachten, dass sich main.cpp nicht geändert hat und dass analog zum vorherigen Kapitel noch Defaultwerte für die Sub-Seite gesetzt wurden.

//--- Taschenrechner.h - start ---

#ifndef TASCHENRECHNER_H
#define TASCHENRECHNER_H

#include "ui_Taschenrechner.h"

class Taschenrechner : public QMainWindow, public Ui::MainWindow{
        Q_OBJECT

public:
        Taschenrechner (QMainWindow *parent = 0);
        ~Taschenrechner();
private slots:
        void addAB();
        void slotClose();
        void showAdd();
        void showSub();
};

#endif //TASCHENRECHNER_H

//--- Taschenrechner.h - end ---
//--- Taschenrechner.cpp - start ---
#include "Taschenrechner.h"

Taschenrechner::Taschenrechner(QMainWindow *parent) : QMainWindow(parent){ 
        setupUi(this);
        InputA -> setText("0");
        InputB -> setText("0");
        InputA_2 -> setText("0");
        InputB_2 -> setText("0");

        connect(Calculate, SIGNAL (clicked()), this, SLOT(addAB()));
        connect(actionQuit,SIGNAL (triggered()), this, SLOT(slotClose()));
        connect(actionAdd, SIGNAL(triggered()), this, SLOT(showAdd()));
        connect(actionSub, SIGNAL(triggered()), this, SLOT(showSub()));
}

Taschenrechner::~Taschenrechner(){
}

void Taschenrechner::addAB(){
        double a, b;
        a = (InputA -> text()).toDouble();
        b = (InputB -> text()).toDouble();
        ResultC -> setText(QString("%1").arg(a+b,0,'f',4));        
}

void Taschenrechner::slotClose(){
        close();
}

void Taschenrechner::showAdd(){
        stackedWidget -> setCurrentIndex(0);
}

void Taschenrechner::showSub(){
        stackedWidget -> setCurrentIndex(1);
}

//--- Taschenrechner.cpp - end ---

Zu guter Letzt könnte man jetzt eine Funktion subAB implementieren und fertig wäre der Taschenrechner. Da dies identisch ist mit der Implementierung von addAB() kann auf eine weitere Erklärung hier verzichtet werden. Wenn man dies macht wird die Datei Taschenrechner.cpp sehr schnell sehr unübersichtlich (es gibt ja noch mehr Rechenarten zu implementieren). Daher soll im folgenden Kapitel der Quellcode auf verschiedene Dateien verteilt werden.

Persönliche Werkzeuge