Die folgenden Betrachtungen beleuchten lediglich einen kleinen Ausschnitt aus dem
Qt - Programmierkonzept: den Signal-Slot-Mechanismus.
Ein umfangreiches Beispiel für die Anwendung des Qt-Signal-Slot-Konzepts ist
der Noteneditor
noteedit
|
Wenn einige Klassen einer Klassenbibliothek Widgets darstellen, kommt es häufig zu einem Problem, welches anhand nebenstehenden Beispielprogramms erläutert werden soll: Auf einem Framewidget
erzeugt. Das ansonsten gelbe Widget |
![]() |
Ein Ausschnitt aus dem Qt-Quelltext für die QWidget-Subklasse
flaeche könnte so aussehen(flaeche.h):
class flaeche : public QWidget {
private:
QLabel *haedline;
public:
flaeche(QLabel *l, QFrame *parent);
protected:
void paintEvent (QPaintEvent * evt);
virtual void mousePressEvent ( QMouseEvent * evt);
};
(flaeche.cpp):
.....
flaeche::flaeche(QLabel *l, QFrame *parent):
QWidget(parent) {
haedline = l;
.....
}
.....
void flaeche::mousePressEvent ( QMouseEvent * evt) {
if (evt->x() >= LEFT && evt->x() <= RIGHT &&
evt->y() >= TOP && evt->y() <= BOT) {
haedline->setText("getroffen");
}
else {
haedline->setText("daneben");
}
}
Damit ein Objekt der Klasse flaeche die Aufschrift des Label-Widgets ändern kann,
wird ihm das Label-Widget bekanntgemacht. Zu diesem Zwecke wird das Label-Widget im Konstruktor
übergeben.(mainwindow.cpp):
int main( int argc, char *argv[] )
{
QApplication app( argc, argv );
QFrame f;
myLabel l1(&f);
flaeche blatt(&l1, &f);
f.setGeometry( 0, 0, 300, 300 );
app.setMainWidget( &f );
f.show();
return app.exec();
}
Das gesamte Programm ist hier [qtbsp.tgz] zu finden. Schematisch kann das so dargestellt werden:
Das Objekt f übergibt das Objekt l1 an das Objekt blatt. Das kann zu Problemen führen, wenn es auf Grund der GUI notwendig ist, umfangreichere Strukturen zu erzeugen:
In diesem Fall wird das Label-Widget l1 an p1 und p3 übergeben, obwohl
diese Widgets der Kenntnis von l1 gar nicht bedürfen.
Qt bietet für diesen Fall als Lösung den Signal-Slot-Mechanismus an(flaeche.h):
class flaeche : public QWidget {
Q_OBJECT
public:
flaeche(QFrame *parent);
void paintEvent (QPaintEvent * evt);
signals:
void getroffen(bool ok);
protected:
virtual void mousePressEvent ( QMouseEvent * evt);
};
Im Haeder-File wird eine Signal getroffen definiert ...
(flaeche.cpp):
....
flaeche::flaeche(QFrame *parent):
QWidget(parent) {
....
}
.....
void flaeche::mousePressEvent ( QMouseEvent * evt) {
bool treffer;
treffer = evt->x() >= LEFT && evt-<x() <= RIGHT &&
evt->y() >= TOP && evt->y() <= BOT;
emit getroffen(treffer);
}
.. welches vom Objekt emittiert wird. Das Signal kann einen oder mehrerer Parameter
transportieren. Ein Objekt, das dieses Signale empfangen will, muß über einen Slot
gleicher Parameterliste verfügen(mylabel.h):
class myLabel : public QLabel {
Q_OBJECT
public:
myLabel(QFrame *parent);
public slots: void show_state(bool is_getroffen);
};
Der Slot wird wie eine "normale" Methode implementiert(mylabel.cpp):
void myLabel::show_state(bool is_getroffen) {
if (is_getroffen) {
setText("getroffen");
}
else {
setText("daneben");
}
}
Zwischen dem Signal und dem Slot erzeugt das QWidget f einen Kanal(signale.cpp):
int main( int argc, char *argv[] )
{
QApplication app( argc, argv );
QFrame f;
myLabel l1(&f);
flaeche blatt(&f);
f.setGeometry( 0, 0, 300, 300 );
QObject::connect(&blatt, SIGNAL(getroffen(bool)),
&l1, SLOT(show_state(bool)));
app.setMainWidget( &f );
f.show();
return app.exec();
}
Die Übergabe von l1 an blatt kann entfallen, da es nun einen Nachrichtenkanal
jenseits der Aggregationsstruktur gibt:
Das gesamte Beispiel ist hier [qtsignal.tgz] zu finden.
Für kompliziertere Fälle verfügt Qt über einen Namensdienst, welcher jedes Qt-Objekt
in die Lage versetzt, sich eine Zugangsmöglichkeit zu einem anderen Objekt zu verschaffen:
...
flaeche::flaeche(QFrame *parent_, char *name):
QWidget(parent_, name) {
myLabel *label_ptr;
QObjectList *list;
list = parent()->queryList( "myLabel" , "Label1" );
QObjectListIt it(*list);
label_ptr = (myLabel *) it.current();
if (label_ptr == 0) {
cerr << "internal error" << endl;
}
QObject::connect(this, SIGNAL(getroffen(bool)),
label_ptr, SLOT(show_state(bool)));
}
....
Das gesamte Beispiel ist hier [qtsearch.tgz] zu finden.