Obiektowe programowanie w języku C++
Kurs podstawowy
Dr inż. Lucjan Miękina
upel.agh.edu.pl/wimir/login/
Katedra Robotyki i Mechatroniki
May 6, 2013
1/1
Obiektowe programowanie w języku C++ z użyciem biblioteki Qt
Klasa QObject
Klasa QObject jest klasą bazową wszystkich obiektów w bibliotece Qt. Poniżej
podano skróconą definicję tej klasy:
Jak widać, klasa QObject nie posiada
1 class QObject {
publicznego konstruktora kopiującego,
2 public :
3 QObject ( QObject * parent =0); ponieważ obiekty QObject nie mają
4 virtual ~ QObject ();
być kopiowane. Przyjęto zasadę, że
5 QString objectName () const ;
obiekty klasy QObject są unikalne i
6 QObject * parent () const ;
posiadają "tożsamość"; tzn., mają swoje
7 void setParent ( QObject * parent );
8 const ObjectList & children () const ;
odpowiedniki w realnym świecie, które
9 // ... more ...
również cechują się pewną unikalnością i
10 };
trwałością.
Wobec braku publicznego konstruktora kopiującego, obiekty typu QObject nie mogą
być przekazane do funkcji.
Każdy obiekt typu QObject może mieć co najwyżej jeden obiekt rodzicielski (parent) i
dowolnie dużą liczbę obiektów potomnych typu QObject*. Obiekt typu QObject
przechowuje wskazniki do obiektów potomnych w polu QObjectList. Każdy QObject
zarządza swoimi dziećmi. Oznacza to, że destruktor klasy QObject automatycznie
usuwa obiekty swoich dzieci.
Lista obiektów potomnych tworzy dwukierunkowe powiązanie typu jeden-do-wielu
(one-to-many) między obiektami. Ustanowienie rodzica dla obiektu dodaje jego adres
do listy potomków, na przykład objA->setParent(objB); dodaje wskaznik objA do
listy dzieci w objB. Jeśli pózniej wykonamy instrukcję objA->setParent(objC); to
wskaznik objA zostanie usunięty z listy dzieci w objB i dodany do listy dzieci w objC.
2/1
Obiektowe programowanie w języku C++ z użyciem biblioteki Qt
QObject - zarządzanie obiektami potomnymi
Klasa QObject może być użyta do budowy złożonych struktur obiektów. W takich
strukturach występują dwa rodzaje obiektów:
złożone (composite) obiekty, które mogą zawierać obiekty potomne (części)
składniki (component), które mogą mieć właściciela (rodzica).
QObject może reprezentować zarówno obiekty złożone jak i składniki. Przynależność
(lub zawieranie) obiektów możemy wyrazić za pomocą relacji parent-child między
obiektami klasy QObject.
4 # include < QObject >
5
6 class Part : public QObject {
7 public :
8 Part ( QObject * parent , QString name );
9 virtual ~ Part ();
10 };
1 # include < QTextStream >
2 # include " Part .h"
3
4 static QTextStream cout ( stdout , QIODevice :: WriteOnly );
5
6 Part :: Part ( QObject * parent , QString name )
7 : QObject ( parent ) {
8 setObjectName ( name );
9 cout << QString (" Create Part : %1 " ). arg ( name ) << endl ;
10 }
11 Part ::~ Part () {
12 cout << QString (" Destroy Part : %1 " ). arg ( objectName ()) << endl ;
13 }
3/1
Obiektowe programowanie w języku C++ z użyciem biblioteki Qt
QObject - zarządzanie obiektami potomnymi
1 # include < QTextStream > 1 CREATE a root object .
2 # include " Part .h" 2 Create Part : Computer
3 3 Create Part : Main board
4 static QTextStream cout ( stdout , 4 Create Part : Devices
5 QIODevice :: WriteOnly ); 5 Create Part : CPU
6 6 Create Part : Memory
7 int main ( int , char **) { 7 Create Part : Storage
8 cout << " CREATE a root object ." << endl ; 8 Create Part : I/O
9 Part root (0 , " Computer " ); 9 Create Part : Power supply
10 // other objects are created on the heap 10
11 Part * main = new Part (& root , " Main board " ); 11 DISPLAY the object tree :
12 Part * devices = new Part (& root , " Devices " ); 12 QObject :: Computer
13 new Part ( main , " CPU " ); 13 QObject :: Main board
14 new Part ( main , " Memory " ); 14 QObject :: CPU
15 new Part ( devices , " Storage " ); 15 QObject :: Memory
16 new Part ( devices , "I/O" ); 16 QObject :: Devices
17 new Part (0 , " Power supply " ); 17 QObject :: Storage
18 cout << "\ nDISPLAY the object tree " << endl ; 18 QObject :: I/O
19 root . dumpObjectTree (); 19
20 cout << "\ nDESTROY all objects ." << endl ; 20 DESTROY all objects :
21 return 0; 21 Destroy Part : Computer
22 } 22 Destroy Part : Main board
23 Destroy Part : CPU
24 Destroy Part : Memory
UWAGA: "Power supply" nie jest częścią wymienioną
25 Destroy Part : Devices
w liście generowanej przez dumpObjectTree() i nie
26 Destroy Part : Storage
zostanie usunięta (wystąpi przeciek pamięci).
27 Destroy Part : I/O
4/1
Obiektowe programowanie w języku C++ z użyciem biblioteki Qt
Sygnały i sloty
Sygnały i sloty są używane do komunikacji między obiektami. Mechanizm sygnałów i
slotów jest jednym z głównych filarów Qt.
Motywacja
Programując GUI, należy zwykle przekazać informację o zmianie stanu kontrolki
ekranowej (widget), np. przycisku czy suwaka, do innego elementu programu
(kontrolki lub funkcji obsługi zdarzenia). Na przykład, gdy użytkownik klika przycisk
Close, zwykle należy wywołać funkcję close() tego okna. Bardziej ogólnie, potrzebny
jest mechanizm komunikacji między obiektami dowolnego typu.
Podejście alternatywne - funkcje typu callback
Starsze biblioteki realizują ten rodzaj komunikacji za pomocą wywołań zwrotnych
(callback). Użytkownik jedynie rejestruje funkcję (w postaci wskaznika do niej) do
pózniejszego wywołania, natomiast funkcje biblioteki wywołają ją w stosownym czasie.
Mechanizm ten ma dwie podstawowe wady: (1) wywołania zwrotne nie są realizowane
z kontrolą typów (nie ma pewności, że przekazane zostaną poprawne argumenty). (2)
funkcja wywoływana zwrotnie jest silnie związana z kodem użytkownika poprzez
wskaznik do niej dostarczony w chwili rejestracji.
5/1
Obiektowe programowanie w języku C++ z użyciem biblioteki Qt
Sygnały i sloty
Qt oferuje mechanizm sygnałów i slotów, jako następcę funkcji callback.
Sygnał jest emitowany, kiedy występuje określone zdarzenie. Sygnał jest
komunikatem zdefiniowanym w klasie jako funkcja o rezultacie typu void.
Funkcja ta posiada listę parametrów, ale nie ma ciała. Sygnał jest częścią
interfejsu klasy. Przypomina on funkcję, ale nie może być wywołany musi być
wysłany przez obiekt tej klasy.
Slot jest funkcją wywoływaną w odpowiedzi na określony sygnał. Np. kontrolki
Qt (widget) mają wiele pre-definiowanych slotów, ale powszechną praktyką jest
dziedziczenie z kontrolek i dodawanie własnych slotów w celu obsługi
specyficznych sygnałów.
Mechanizm sygnałów i slotów używa kontroli typów: sygnatura sygnału musi się
zgadzać z sygnaturą slotu. Dzięki temu kompilator wykrywa tego rodzaju błędy.
Sygnały i sloty są luzno związane: klasa która emituje sygnał, nie zna slotów
odbierających go.
Mechanizm sygnałów i slotów zapewnia, że po połączeniu sygnału ze slotem, będzie
on wywołany z parametrami przekazanymi w sygnale w odpowiednim momencie.
Sygnały i sloty mogą mieć dowolną liczbę argumentów dowolnego typu.
Wszystkie podklasy QObject, w tym QWidget mogą zawierać sygnały i sloty. Sygnały
są emitowane przez obiekty, gdy zmieniają one swój stan w sposób interesujący dla
innych obiektów. To wszystko co musi zrobić obiekt, by zrealizować sterowanie innymi
obiektami, bez wnikania czy istnieje jakikolwiek slot odbiorczy.
Sloty są używane do odbioru sygnałów, ale są to normalne funkcje składowe klasy.
Slot może być odbiorcą wielu sygnałów. Sygnał może być połączony z wieloma
slotami, jak również z innymi sygnałami (emitowanie innego sygnału).
6/1
Object-oriented programming in C++
Sygnały i sloty
Connecting sygnałs to slots
7/1
Object-oriented programming in C++
Sygnały i sloty
Przykład
Klasa Register przechowuje swój stan w polu (m_value), dostarczając publicznej
metody do jego odczytu, a dodatkowo umożliwia programowanie z użyciem
mechanizmu sygnałów i slotów. Każdy obiekt tej klasy może "obwieścić" reszcie
świata, że jego stan uległ zmianie, emitując sygnał valueChanged(). Każdy obiekt tej
klasy może również odebrać taki sygnał i obsłużyć w kodzie slotu setValue( int ).
Klasy korzystające z sygnałów lub slotów muszą użyć makra Q_OBJECT na początku
bloku deklaracji. Muszą też bezpośrednio lub pośrednio dziedziczyć z QObject.
4 # include < QObject > 1 # include " Register .h"
5 2
6 class Register : public QObject { 3 Register :: Register () :
7 Q_OBJECT 4 QObject (0) {
8 public : 5 m_value = 0;
9 explicit Register (); 6 }
10 int value () const ; 7 int Register :: value () const {
11 public slots : 8 return m_value ;
12 void setValue ( int value ); 9 }
13 signals : 10 void Register :: setValue ( int value ) {
14 void valueChanged ( int newValue ); 11 if ( value != m_value ) {
15 private : 12 m_value = value ;
16 int m_value ; 13 emit valueChanged ( value );
17 }; 14 }
15 }
8/1
Object-oriented programming in C++
Sygnały i sloty
Przykład c.d.
W funkcji main() tworzone są dwa obiekty (a i b). Początkowo są one niezależne,
następnie definiowane jest połączenie od a do b, a w końcu ponownie stają się
niezależne. W każdej z tych faz, wywoływane są funkcje slotu obiektu a i b.
1 # include < QCoreApplication > 1
2 # include < iostream > 2
3 using namespace std ; 3
4 # include " Register .h" 4
5 void print ( const Register & a , const Register & b) { 5
6 cout << endl << "a:" << a. value () 6
7 << " , b:" << b. value (); 7
8 } 8
9 int main ( int argc , char * argv []) { 9
10 QCoreApplication app ( argc , argv ); 10
11 Register a , b; print (a , b ); 11 a :0 , b :0
12 a. setValue (1); print (a , b ); 12 a :1 , b :0
13 QObject :: connect (&a , SIGNAL ( valueChanged ( int )) , 13
14 &b , SLOT ( setValue ( int ))); 14
15 cout << endl << " connect a --> b" ; 15 connect a --> b
16 a. setValue (2); print (a , b ); 16 a :2 , b :2
17 b. setValue (3); print (a , b ); 17 a :2 , b :3
18 QObject :: disconnect (&a , SIGNAL ( valueChanged ( int )) , 18
19 &b , SLOT ( setValue ( int ))); 19
20 cout << endl << " disconnect a --> b"; 20 disconnect a --> b
21 a. setValue (0); print (a , b ); 21 a :0 , b :3
22 cout << endl ;
23 return app . exec ();
24 }
9/1
Obiektowe programowanie w języku C++ z użyciem biblioteki Qt
QApplication i pętla komunikatów
Interaktywne aplikacje Qt posiadające GUI mają inną organizację niż aplikacje
konsolowe czy filtry (sekwencyjne), ponieważ są one sterowane zdarzeniami i często
są wielowątkowe. Obiekty wymieniają komunikaty aby synchronizować swoje działanie.
Klasa QEvent
Klasa QEvent reprezentuje ogólnie pojęcie zdarzenia, będąc klasą bazową dla
specjalizowanych klas, takich jak QActionEvent, QFileOpenEvent, QHoverEvent,
QInputEvent, QMouseEvent, itd. Obiekty typu QEvent są tworzone w systemie okien
w odpowiedzi na akcje użytkownika (QMouseEvent), w określonych odstępach czasu
(QTimerEvent) lub jawnie w programie. Metoda type() zwraca wartość typu enum,
identyfikującą rodzaj zdarzenia.
Typowa struktura programu zbudowanego z użyciem Qt
Typowy program Qt tworzy obiekty, łączy je ze sobą (sygnał/slot), a następnie
wywołuje metodę exec(), która obsługuje pętlę zdarzeń. Od tego momentu obiekty
mogą wysyłać i odbierać komunikaty, przekazywane w różny sposób. Obiekty graficzne
(QWidget) wysyłają QEvent-y do innych QObject-ów w odpowiedzi na akcje
użytkownika. QWidget-y odpowiadają na akcje zarządcy okien, takie jak repaint (),
resize (), czy close (). Obiekty klasy QObject komunikują się za pomocą sygnałów i
slotów.
Pętla zdarzeń jest strukturą programową, która priorytetuje, kolejkuje i wysyła
zdarzenia do obiektów. Tworzenie aplikacji sterowanej zdarzeniami polega na
zdefiniowaniu interfejsu do funkcji wywoływanych w odpowiedzi na konkretne
zdarzenia. Pętla zdarzeń wykonuje się dopóki nie wystąpi zdarzenie końcowe (np.
użytkownik naciśnie klawisz QUIT).
10/1
Obiektowe programowanie w języku C++ z użyciem biblioteki Qt
QApplication i pętla komunikatów
Prosta aplikacja GUI, tworząca obiekt w klasy QWidget, który reprezentuje główne
okno aplikacji. Wewnątrz tworzony jest obiekt klasy QVBoxLayout aby ułożyć obiekty
graficzne w pionowy stos. Następnie tworzone są obiekty klas QTextEdit (do edycji
tekstu) i QPushButton (przycisk uruchamiający obsługę zdarzenia). Ostatecznie
predefiniowany slot clicked () zostaje skojarzony z sygnałem generowanym przez
obiekt pushButton.
1 # include < QApplication >
2 # include < QWidget >
3 # include < QVBoxLayout >
4 # include < QTextEdit >
5 # include < QPushButton >
6
7 int main ( int argc , char * argv []) {
8 QApplication app ( argc , argv );
9 QWidget w;
10 QLayout * layout = new QVBoxLayout ;
11 w. setLayout ( layout );
12 QTextEdit * te = new QTextEdit ;
13 layout -> addWidget ( te );
14 te -> setHtml ("
int main (
void ) {
"
15 "& nbsp ;& nbsp ;
// indicates success "
16 "& nbsp ;& nbsp ;
return 0; < br >"
17 "}" );
18 QPushButton * quitBtn = new QPushButton (" OK " );
19 layout -> addWidget ( quitBtn );
20 QObject :: connect ( quitBtn , SIGNAL ( clicked ()) , & app , SLOT ( quit ()));
21 w. show ();
22 return app . exec ();
23 }
11/1
Obiektowe programowanie w języku C++ z użyciem biblioteki Qt
Klasa QWidget
Widgety są to obiekty klas pochodnych QWidget, które są podstawowymi elementami
składowymi graficznego interfejsu aplikacji.
QWidget jest klasą opartą na dwu klasach bazowych:
QWidget dziedziczy z QObject, dzięki czemu może być w relacji parent-child,
generować sygnały i posiadać sloty do komunikacji z innymi obiektami
QWidget dziedziczy z QPaintDevice, klasy bazowej dla wszystkich obiektów
graficznych przedstawianych na ekranie.
Obiekty klasy QWidget współdziałają ze swoimi potomkami. Obiekt nie mający
rodzica nazywa się oknem (window). Jeśli pewien obiekt jest rodzicem innego,
krawędzie potomka leżą w całości wewnątrz obszaru rodzica. Elementy potomne są
wyświetlane zgodnie z regułami rozmieszczenia, definiowanymi przez klasy pochodne
QLayout.
Obiekt klasy QWidget może obsługiwać zdarzenia przekazywane za pomocą sygnałów
od różnych obiektów istniejących w systemie okien (e.g., mysz, klawiatura, procesy,
itp.). Może również wyświetlać swój obraz w prostokątnym obszarze ekranu, a na
koniec usunąć się z ekranu nie zaburzając stanu innych obiektów.
Typowa aplikacja pulpitu z GUI może posiadać wiele (setki) różnych obiektów klasy
QWidget i pochodnych, związanych relacją parent-child i rozmieszczonych zgodnie z
wymaganiami estetyki, ergonomii i zastosowaniem programu.
12/1
Obiektowe programowanie w języku C++ z użyciem biblioteki Qt
Okna dialogowe
Okno dialogowe pojawia się na ekranie, wyświetlając użytkownikowi istotną informację
i pobiera od niego odpowiedz. Tym samym zapewnia krótką interakcję, w wyniku
której użytkownik może wpływać na działanie programu.
QDialog jest klasą bazową dla wszystkich okien dialogowych; posiada ona pole typu
bool o nazwie modal. If modal ma wartość true, to okno dialogowe blokuje dostęp do
wszystkich innych okien danej aplikacji. Takie modalne okno dialogowe musi być
zamknięte, aby aplikacja mogła kontynuować swoje działanie.
Dlatego modalne okna dialogowe stosuje się tylko wtedy, gdy użytkownik musi
wprowadzić informację niezbędną dla dalszego działania programu lub zostać
poinformowany o pewnym zdarzeniu.
Klasa QMessageBox (pochodna od QDialog) wyświetla modalne okno dialogowe
służące do powiadamiania użytkownika. Zawiera ono informację tekstową (lub
pytanie), ikonę i jeden do trzech przycisków. Ikony informują o istotności zdarzenia
(ostrzeżenie, błąd, awaria) i korespondują z typem powiadomienia.
13/1
Wyszukiwarka
Podobne podstrony:
Wyklad CPP 6Wyklad CPP 1Wyklad CPP 2Wyklad CPP 3Wyklad CPP 5CPP WYKLAD 1CPP WYKLAD 7CPP WYKLAD 6CPP WYKLADY ANALIZA 2CPP WYKLAD 1 2CPP WYKLAD 3CPP WYKLAD 4 5CPP WYKLADY ANALIZA 1Sieci komputerowe wyklady dr FurtakWykład 05 Opadanie i fluidyzacjawięcej podobnych podstron