Qt - klasa QObject oraz sloty i sygnały

Autor podstrony: Krzysztof Zajączkowski

Stronę tą wyświetlono już: 4361 razy

Wszystkie klasy biblioteki Qt dziedziczą po klasie bazowej QObject. Klasa ta zapewnia obsługę elementów biblioteki Qt jakimi są sloty i sygnały, które umożliwiają realizację obsługi interakcji pomiędzy obiektami dziedziczącymi po klasie QObject.

Sloty można porównać do gniazdka, natomiast sygnały do wtyczki. Pod dany slot (wtyczkę) można podpiąć sygnał (gniazdko). Ważne jest jednak, aby slot i sygnał do siebie pasowały tak jak dana wtyczka musi pasować do gniazdka.

Podłączenie slotu do sygnału wygląda następująco:

QObject::connect(sender, SLOT(onEvent()), reciver, SIGNAL(reciveEvent()));

W powyższym kodzie sender jest wskaźnikiem na obiekt wysyłający sygnał. Obiekt ten ma zaimplementowany wewnątrz slot o nazwie onEvent. Z kolei reciver jest wskaźnikiem na obiekt otrzymujący sygnał. Ten obiekt ma zaimplementowany wewnątrz sygnał o nazwie reciveEvent. Aby dany sygnał pasował do danego slotu argumenty, jakie one otrzymują muszą być takie same.

Możliwa jest również operacja odwrotna do połączenia slotu z sygnałem:

QObject::disconnect(sender, reciver);

Czas najwyższy by utworzyć przykład klasy, która będzie miała zaimplementowany slot i sygnały. W tym celu należy kliknąć prawym przyciskiem myszy (tak jak to jest widoczne na poniższym rysunku) i w menu kontekstowym kliknąć pozycję Dodaj nowy.

Menu kontekstowe Qt Creator-a umożliwiające dodanie nowego elementu do projektu
Rys. 1
Menu kontekstowe Qt Creator-a umożliwiające dodanie nowego elementu do projektu

Po tym jakże trudnym zadaniu oczom twym ukazać powinno się okno dialogowe Nowy plik, w którym to niezwłocznie po zaznaczeniu opcji z poniższego screen-a należy kliknąć przycisk Wybierz (co też i ja uczyniłem z najdzikszą rozkoszą).

Widok okna dialogowego Qt Creator-a Nowy plik
Rys. 2
Widok okna dialogowego Qt Creator-a Nowy plik

W kolejnym oknie należy podać nazwę tworzonej klasy, ja wybrałem niezbyt wyszukaną nazwę: A po czym kliknąłem przycisk Dalej.

Okno Qt Creator-a o nazwie Klasa C++
Rys. 3
Okno Qt Creator-a o nazwie Klasa C++

Niestety Qt Creator okazuje się być niezwykle gadatliwym tworem, gada i gada i gęba mu się nie zamyka i z tego powodu w ostatnim widoku okna Klasa C++ pyta się, pod który projekt utworzoną klasę podpiąć. W tym przypadku wypada zostawić tak jak jest i kliknąć przycisk Zakończ.

Okno Qt Creator-a o nazwie Klasa C++ - widok końcowy
Rys. 4
Okno Qt Creator-a o nazwie Klasa C++ - widok końcowy

Uff, po tym jakże nużącym procesie klikania i skakania po oknach Qt Creator-a do projektu powinny zostać dodane dwa pliki:

W pliku A.h kod klasy A należy zmodyfikować do następującej postaci:

#ifndef A_H #define A_H #include <QObject> #include <QDebug> class A : public QObject{ // klasa A musi dziedziczyć po klasie QObject Q_OBJECT // w pierwszej linijce klasy musi być uruchomione makro Q_OBJECT QString name; public: A(QString name): name(name){} public slots: // sekcja dla slotów publicznych (mogą być też prywatne i chronione sloty) void sendMessage(QString to, QString message); // slot do wysyłania wiadomości void messageRecived(QString from, QString to, QString message); // slot do otrzymywania wiadomości signals: // sekcja dla sygnałów void messageSended(QString from, QString to, QString string); // sygnał wywoływany (emitowany), gdy wysłana zostanie wiadomość }; #endif // A_H

Natomiast plik A.cpp należy zmodyfikować do następującej postaci:

#include "a.h" void A::sendMessage(QString to, QString message){ emit messageSended(name, to, message); // tutaj uruchamiany jest slot podpięty pod sygnał wysłanej wiadomości } void A::messageRecived(QString from, QString to, QString message){ if(to == name){ // jeżeli nazwa odbiorcy wiadomości jest równa nazwie nadanej obiektowi klasy to qDebug() << name << "recived some message from:" << from << "and this message is:" << message; // wyświetlaj taką informację } }

W pliku main.cpp kod powinien wyglądać mniej więcej tak:

#include <QCoreApplication> #include "a.h" int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); A *a1 = new A("a1"); // tworzę obiekt klasy A A *a2 = new A("a2"); // łączenie sygnałów i slotów QObject::connect(a1, SIGNAL(messageSended(QString,QString,QString)), a2, SLOT(messageRecived(QString,QString,QString))); QObject::connect(a2, SIGNAL(messageSended(QString,QString,QString)), a1, SLOT(messageRecived(QString,QString,QString))); a1->sendMessage("a2", "Hey, what are you doing here?"); // slot sendMessage obiektu a1, który emituje sygnał messageSended a2->sendMessage("a1", "I spend some time on programming dude!"); // slot sendMessage obiektu a2, który emituje sygnał messageSended return a.exec(); }

Wynik działania powyższego kodu:

"a2" recived some message from: "a1" and this message is: "Hey, what are you doing here?"
"a1" recived some message from: "a2" and this message is: "I spend some time on programming dude!"
Propozycje książek