Login
Newsletter
Werbung

So, 5. März 2006, 00:00

Entwicklung von Applikationen in Qt 4.0

Schauen wir uns Listing 1 noch einmal an. Es handelt sich um eine Klasse, die einen Mitarbeiter definiert, der sein Gehalt bekommt. Der Konstruktor nimmt traditionell einen Parameter an, der einen Zeiger auf das Elternobjekt darstellt. Nach dem Konstruktor gibt es eine Funktion, die das Gehalt zurück gibt, dann folgt die Deklaration der Slots. Das Schlüsselwort slots ist ein Makro, dessen Wert ein leerer String ist, wodurch der Compiler es nicht sieht. moc sieht es allerdings und baut auf dieser Basis eine Liste von Slots. Der Slot setSalary() ist einfach eine Methode. Wenn wir sie an irgendein Signal anschließen, bewirkt das Senden des Signals einen Aufruf dieser Methode. Da sie eine öffentliche Methode ist, kann man sie auch vom Code aus normal aufrufen.

Die Klasse Employee besitzt auch das Signal salaryChanged(), das dann gesendet wird, wenn sich das Gehalt des Mitarbeiters geändert hat. Das Schlüsselwort signals ist ein Makro, dessen Wert protected ist. Somit sind alle Signale geschützt und können nur durch die Klasse Employee, deren Nachfolger und Freunde aufgerufen werden. Für die Implementierung des Signals salaryChanged() ist moc zuständig. Die Implementation ruft alle Slots auf, die im gegebenen Moment an das Signal angeschlossen sind.

Slots und Signale können Parameter vom beliebigen Typ besitzen. Der Aufruf eines Signals mit Parametern bewirkt, dass alle angeschlossenen Slots mit denselben Parametern aufgerufen werden. Natürlich müssen Parameter des Signals und des Slots übereinstimmen. Genauer gesagt, kann ein Slot weniger Parameter als ein Signal besitzen, aber jeder Parameter des Slots muss auf derselben Stelle und desselben Typs sein wie im Signal. Daraus folgt, dass man an einen Slot ohne Parameter jedes Signal anschließen kann. Wenn die Liste der Parameter des Slots und des Signals inkompatibel sind, ist ein Anschluss nicht erfolgreich.

Listing 2. employee.cpp: Implementierung der Klasse mit einem Signal und einem Slot

#include "employee.h"
Employee::Employee(QObject *parent)
 : QObject(parent)
{
 m_salary = 0;
}
int Employee::salary() const
{
 return m_salary;
}
void Employee::setSalary(int salary)
{
 if (m_salary != salary) {
 m_salary = salary;
 emit salaryChanged(m_salary);
 }
}

Schauen wir uns die Implementierung des Slots setSalary() in Listing 2 an. Dieser Slot sendet das Signal salaryChanged() unter der Bedingung, dass sich das Gehalt tatsächlich geändert hat. Das Schlüsselwort emit ist ein Makro, dessen Wert ein leerer String ist. Man sollte aber emit nicht vernachlässigen - dieses Wort signalisiert, dass ein Signal gesendet wird und dass man nicht nach einer Implementierung von salaryChanged() suchen soll, weil sie sich in einer durch moc generierten separaten Datei befindet.

Listing 3. main.cpp: Verbinden von Signalen und Slots

#include <stdio.h>
#include <QtCore/QTextStream>
#include "employee.h"
static QTextStream qout(stdout);
int main()
{
 Employee emp1;
 Employee emp2;
 QObject::connect(&emp1, SIGNAL(salaryChanged(int)),
 &emp2, SLOT(setSalary(int)));
 QObject::connect(&emp2, SIGNAL(salaryChanged(int)),
 &emp1, SLOT(setSalary(int)));
 Employee emp3;
 Employee emp4;
 QObject::connect(&emp3, SIGNAL(salaryChanged(int)),
 &emp4, SLOT(setSallary(int)));
 QObject::connect(&emp4, SIGNAL(salaryChanged(int)),
 &emp3, SLOT(setSallary(int)));
 emp1.setSalary(100);
 emp3.setSalary(200);
 qout << "emp1: " << emp1.salary() << '\n';
 qout << "emp2: " << emp2.salary() << '\n';
 qout << "emp3: " << emp3.salary() << '\n';
 qout << "emp4: " << emp4.salary() << '\n';
 return 0;
}

Listing 3 zeigt, wie man aus einer Instanz der Klasse Employee ein funktionierendes Programm macht. Wir erstellen zwei Paare von Mitarbeitern und verbinden sie so, dass jeder Mitarbeiter genauso viel wie sein Partner verdient. Die statische Methode

bool QObject::connect(QObject *sender, const char *signal,
 QObject *receiver, const char *slot);

erstellt eine Verbindung zwischen einem Signal und einem Slot zweier QObjects. Die Makros SIGNAL und SLOT nehmen als Argument die Deklaration einer Methode an und geben einen speziellen String zurück (vom Typ const char*), der durch QObject als Identifikator dieser Methode verwendet wird. Wichtig ist, dass Deklarationen der Methoden innerhalb von diesen Makros keine Parameternamen beinhalten. Ein Versuch des Aufrufs von

QObject::connect(&emp3, SIGNAL(salaryChanged(int salary)),
 &emp4, SLOT(setSalary(int salary)));

scheitert und connect() gibt den Wert false zurück. Eine einmal angelegte Verbindung existiert, solange der Sender und der Empfänger existieren. Ein Entfernen des Objektes entfernt automatisch alle Verbindungen, an denen dieses Objekt teilnimmt. Eine Verbindung kann man auch mit Hilfe der statischen Funktion QObject::disconnect() entfernen.

Verfolgen wir, was passiert, wenn wir emp1.setSalary(100) aufrufen. emp1 weist sich selbst eine neue Gehaltshöhe zu, dann sendet es das Signal salaryChanged(100). Dieses Signal ist am Slot setSalary(int) des Objekts emp2 angeschlossen. emp2 weist sich selbst ebenfalls eine neue Gehaltshöhe zu und sendet das Signal salaryChanged(100). Dieses Signal ist am Slot setSalary(int) des Objektes emp1 angeschlossen. Der Slot wird aufgerufen, aber diesmal ist der zugewiesene Wert des Gehalts identisch mit dem aktuellen, deshalb sendet emp1 keine Signale mehr und die Rekursion wird unterbrochen.

Man sollte daran denken, dass das Senden eines Signals gleichzeitig ein Aufruf von allen einzelnen Methoden-Slots ist, die im gegebenen Moment an ihm angeschlossen sind. Wenn wir neue Verbindungen anlegen, müssen wir mögliche Rekursionen beachten.

Qt ermöglicht auch, Warteschlangenverbindungen anzulegen (queued connections). Bei solchen Verbindungen bewirkt das Senden eines Signals einen Aufruf des Slots, aber erst im nächsten Zyklus der Ereignisschleife (event loop). Das Anlegen einer solchen Verbindung sieht wie folgt aus:

QObject::connect(&emp3, SIGNAL(salaryChanged(int)),
 &emp4, SLOT(setSalary(int)), Qt::QueuedConnection);

Kommentare (Insgesamt: 2 || Alle anzeigen )
Pro-Linux
Pro-Linux @Facebook
Neue Nachrichten
Werbung