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

Aus Wikibooks

UI File zur Subtraktion[Bearbeiten]

Um den Taschenrechner nicht nur zur Addition, sondern auch zur Subtraktion verwenden zu können, müssen einige Änderungen vorgenommen werden. Das UI soll so aussehen, dass es ein Fenstermenü gibt, über das man die gewünschte Rechenoperation auswählen kann. Je nachdem, welche Operation gewählt wird, soll sich der Inhalt des UIs (Labels, Eingabefelder und der Button) ändern. 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.

Änderungen im UI-File[Bearbeiten]

Das bestehende UI-File kann als Grundlage genommen werden. Hierin wird ein neues StackedWidget-Element erstellt. Alle schon vorhandenen UI-Elemente werden auf dessen erste Seite verschoben, danach werden die Elemente nochmals auf die zweite Seite kopiert. Dabei wird noch das Textlabel "A+B" umbenannt in "A-B". Durch das Kopieren ändern sich die technischen Namen der kopierten Objekte: Sie 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 (Strg+R), 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ü erstellt werden. Sollte der UI Designer keine leere Menüleiste am oberen Ende des Reißbrettes anzeigen, kann man durch Klick auf eine leere Stelle im Hintergrund das Kontextmenü aufrufen und "Create Menu Bar" wählen. Einträge können direkt durch einen Mausklick auf die Menüleiste hinzugefügt werden. Das Hauptmenü soll aus den zwei Einträgen "Main" und "Choose" bestehen. Dabei enthält das erste Hauptmenü nur den Eintrag "Quit" zum Beenden des Programms und das zweite Menü die Einträge "Add" und "Sub". Die technischen Namen der Einträge sind per Default "action<Menüeintrag>", also z.B. "actionQuit". Änderungen an diesen Namen können über den Property Editor vorgenommen werden. Eventuell zeigt der Property Editor nicht die richtigen Daten an, wenn man auf den gewünschten Menüeintrag klickt. In diesem Fall müsste man über den Object Inspector gehen. Dieser kann ü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.

Menüs mit Funktionen belegen[Bearbeiten]

Nun sollen die drei Menüs mit Funktionen belegt werden. Das ist 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 zuvor. Für jeden Menüeintrag muss ein connect String in den Konstruktor eingebaut werden. Der connect String hat die Form

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

action<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 und diese in der Quelldatei Taschenrechner.cpp implementiert werden.

Menü Quit[Bearbeiten]

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 einem 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. Add und Sub könnten aber benutzt werden. Die Groß- und Kleinschreibung spielt hier also eine Rolle. Die Deklaration der Funktion slotClose() ist sehr einfach:

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, schließt sich das aktuelle Fenster. Ist das aktuelle Fenster das letzte Fenster, so endet a.exec() und das Programm ebenfalls. Der return-Befehl gibt den Status von a.exec() 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 ganze 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 und dann 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.

Menü Add[Bearbeiten]

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.

Menü Sub[Bearbeiten]

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.