152 2 14MB
Polish Pages [419] Year 2001
A
"
%1 J
program ow anie przy użyciu biblioteki
Qt m. m
JM*: :‘-Î'î: .
m
È&
ñ feuti
D a n ie l Solin Tłu m aczenie: Tomasz R a b ij
Warszawa 2001
Spis rozdziałów C zęść p ie r w s z a P ie rw sz e k ro k i z Q t ........................................................................................... 3 G odzina 1 W p row ad zenie do Q t ........................................................................................................ 5 2 P rogram ow an ie obiektow e .........................................................................................23 3 P o zn ajem y podstaw y Q t ..............................................................................................41 4 Spraw iam y, że coś się dzieje: G niazda i sygnały ................................................ 55 5 Więcej o elem entach konstrukcyjnych Qt .............................................................73 C zęść d r u g a W a ż n e z a g a d n ie n ia d o ty c z ą c e Q t .................................................................... 93 G odzina 6 Poznajem y widgety Qt: Lekcja pierw sza .............................................................95 7 P o zn ajem y w idgety Qt: Lekcja druga ................................................................117 8 Po zn ajem y w idgety Qt: Lekcja trzecia ............................................................. 133 9 T w orzenie prostej g r a f i k i ......................................................................................... 147 10 O kn a dialogow e Qt ................................................................................................... 163 C zęść tr z e c ia P o z n a je m y b a rd z ie j b ib lio te k ę Q t ................................................................183 G o d z in a 11 U ż y w a n ie m en edżerów układu ............................................................................ 185 12 Praca z plikam i i katalogam i .................................................................................203 13 P rzetw arzanie tekstu i w yrażenia regularne ..................................................... 217 14 U żyw anie klas pojem ników .................................................................................231 15 Więcej o grafice ........................................................................................................245 16 K om un ikacja m iędzy program am i .......................................................................259 C zęść c z w a r t a T e c h n ik i p r o g r a m o w a n i a w Q t ..................................................................273 G odzina 17 Pisanie aplikacji dla KDE: Lekcja pierw sza .................................................... 275 18 Pisanie aplikacji dla KDE: Lekcja druga .......................................................... 291 19 U żyw an ie O p en G L -o w y ch klas biblioteki Qt ................................................ 305 20 T w orzenie w tyczek do N etscape ......................................................................... 325 C zęść p ią ta U le p sz a n ie w ła s n y c h p r o g r a m ó w .................................................................... 339 G odzina 21 Internacjonalizacja p rogram ów w Qt ..................................................................341 22 Przenośność ............................................................................................................... 359 23 Techniki debugow ania ..............................................................................................377 24 W ykorzystyw anie konstruktorów GUI ............................................................... 389 D odatek A ........................................................................................................................ 349 C zęść sz ó sta D o d a te k .................................................................................................................... 409 D odatek A ........................................................................................................................................... 411 O dpow iedzi do Q uizu .......................................................................................................................411
Spis treści Część p ie rw sz a Pierw sze k ro k i z Q t
........................................................................................ 3
G o d z in a 1 W p ro w a d z e n ie do Q t ................................................................................................5 Wybór biblioteki Qt ...........................................................................................................................6 Przenośność .................................................................................................................................. 6 Łatwość użycia .......................................................................................................................... 6 Szybkość działania ......................................................................................................................6 Instalowanie biblioteki ......................................................................................................................7 Kompilacja i instalacja dystrybucji źródłowej Qt ............................................................. 7 Instalowanie pakietów RPM z biblioteką Qt ..................................................................... 11 Przykład prostego programu .......................................................................................................... 12 K om pilowanie i uruchamianie programu w Qt ........................................................................14 Kompilacja w systemach UNIX-owych ............................................................................ 14 Kom pilacja w systemie MS Windows przy użyciu Visual C + + ...................................15 Korzystanie z dokumentacji Qt - Qt Reference Documentation ........................................17 Podsum owanie .................................................................................................................................. 20 Pytania i odpowiedzi ......................................................................................................................20 Warsztaty ............................................................................................................................................21 Quiz .............................................................................................................................................. 21 Ćwiczenia .................................................................................................................................. 21 G o d z in a 2 P r o g r a m o w a n ie obiektow e ................................................................................... 23 Pojęcie klas ....................................................................................................................................... 24 Przykład klasy ...........................................................................................................................24 Jak działa dziedziczenie klas ....................................................................................................... 31 W jaki sposób Qt wykorzystuje programowanie obiektowe .............................................. 35 Używanie dziedziczenia klas ................................................................................................35 Tworzenie obiektów i używanie metod ............................................................................. 36 Podsumowanie .................................................................................................................................. 38 Pytania i odpowiedzi ......................................................................................................................38 Warsztaty ............................................................................................................................................ 39 Quiz .............................................................................................................................................. 39 Ćwiczenia .................................................................................................................................. 39 G o d z in a 3 P o z n a je m y p o d sta w y Q t ........................................................................................ 41 Tworzenie pierwszego własnego widgetu głównego ............................................................. 41 Dodawanie obiektów do widgetu głównego ............................................................................ 46 Dodawanie przycisku .............................................................................................................. 46 Dodawanie etykiety .................................................................................................................48 Dodawanie przycisku wyjścia z programu ....................................................................... 50 Podsum ow anie .................................................................................................................................. 52
VI
Poznaj Qt Programming w 24 godziny
Pytania i odpowiedzi ...............................................................................................................52 Warsztaty ................................................................................................................................... 53 Quiz ......................................................................................................................................53 Ćwiczenia .......................................................................................................................... 53 Godzina 4 Sprawiamy, że coś się dzieje: Gniazda isygnały ........................................ 55 Zrozumienie terminologii sygnałów i gniazd ..................................................................... 56 Gniazda ............................................................................................................................... 56 Sygnały ............................................................................................................................... 57 Używanie predefiniowanych sygnałów i gniazd ................................................................ 57 Przykład 1: QSlider i QLCDNumber ............................................................................57 Przykład 2: QPushButton i QLineEdit ..........................................................................59 Tworzenie i używanie niestandardowych sygnałów igniazd ........................................... 61 Zapoznanie się z narzędziem Meta Object Compiler ................................................ 62 Lokalizacja narzędzia Meta Object Compiler w systemie ................................................ 62 Używanie narzędzia Meta Object C o m p ile r ................................................................. 62 Tworzenie gniazd niestandardowych ...................................................................................63 Deklarowanie gniazda niestandardowego ....................................................................63 Definiowanie gniazda niestandardowego .....................................................................64 Kompilacja programu używającego gniazd niestandardowych ................................65 Tworzenie sygnałów niestandardowych ........................................................................ 66 Interesujące cechy gniazd i sygnałów ...................................................................................67 Opuszczanie niechcianych informacji ............................................................................68 Łączenie sygnałów z sygnałami ..................................................................................... 68 Rozłączanie gniazd i s y g n a ł ó w ....................................................................................... 69 Zaoszczędzenie wpisywania przy wprowadzaniu kodu wywołania funkcji connect!) ............................................................................................................ .6 9 Podsumowanie ........................................................................................ T............................... 70 Pytania i odpowiedzi ...............................................................................................................70 Warsztaty ....................................................................................................................................70 Quiz ......................................................................................................................................70 Ćwiczenia .......................................................................................................................... 71 Godzina 5 Więcej o elementach konstrukcyjnych Qt .................................................... 73 Używanie pasków przewijania (Scrollbars) ....................................................................... 74 Zaczynamy pracę z paskami przewijania ...................................................................... 74 Praktyczny przykład ......................................................................................................... 77 Dodawanie menu ......................................................................................................................79 Używanie widgetu QMainWindow ...................................................................................... 83 Dodawanie menu, przycisków i widgetu centralnego ................................................ 84 Dodawanie paska stanu ................................................................................................... 88 Podsumowanie .......................................................................................................................... 89 Pytania i odpowiedzi ...............................................................................................................89 Warsztaty ....................................................................................................................................90
Spis treści
VII
Quiz ............................................................................................................................................. 90 Ćwiczenia ................................................................................................................................. 90 Część d r u g a W ażn e zag a d n ie n ia dotyczące Q t
..................................................................93
G o d z in a 6 P o z n a je m y widgety Q t: L ek cja p i e r w s z a ........................................................95 Używanie przycisków .................................................................................................................. 96 Przyciski zwykłe (Push B u t t o n ) ........................................................................................... 96 Przyciski radiowe (Radio B u t t o n ) ........................................................................................98 Przyciski pola wyboru (Check Button) ............................................................................ 100 Tworzenie etykiet .......................................................................................................................... 101 QLabel ...................................................................................................................................... 102 Q L C D N um ber ........................................................................................................................103 Zmiana katalogu z użyciem komendy cd ........................................................................ 103 Praca z tabelami .............................................................................................................................105 Tworzenie prostej tabeli .......................................................................................................105 Dodanie tekstu i funkcji zaznaczania po kliknięciu ....................................................... 107 Dodanie nagłówka ................................................................................................................ 110 Podsumowanie ............................................................................................................................... 113 Pytania i odpowiedzi ...................................................................................................................114 Warsztaty .........................................................................................................................................114 Quiz ........................................................................................................................................... 114 Ćwiczenia ............................................................................................................................... 115 G o d z in a 7 P o z n a je m y widgety Q t: L ekcja d r u g a ...........................................................117 Używanie widgetów wyboru .................................................................................................... 117 Praca z polami listy ............................................................................................................... 118 Praca z polami kombi ............................................................................................................119 Praca z aranżerami ........................................................................................................................121 Używanie klasy QGroupBox ............................................................................................. 121 Używanie klasy QButtonGroup ........................................................................................ 122 Używanie klasy QSplitter .................................................................................................... 123 Używanie klasy QW idgetStack ........................................................................................ 124 Suwaki i pola przewijane ............................................................................................................127 Używanie klasy QSlider .......................................................................................................127 Używanie klasy QSpinBox .................................................................................................129 Podsumowanie ............................................................................................................................... 131 Pytania i odpowiedzi ................................................................................................................... 131 Warsztaty ......................................................................................................................................... 132 Quiz ............................................................................................................................................132 Ćwiczenia ............................................................................................................................... 132 G o d z in a 8 P o z n a je m y w idgety Q t: L ek cja trzecia .........................................................133 Używanie pól do wprowadzania tekstu ................................................................................... 134 QLineEdit ............................................................................................................................... 134
VIII
Poznaj Qt Program ming w 24 godziny
QM ultiLineEdit ...................................................................................................................... 135 Używanie widoków listy ............................................................................................................ 136 Praca z paskami postępu .............................................................................................................. 142 Podsum owanie ................................................................................................................................145 Pytania i odpowiedzi ....................................................................................................................145 Warsztaty ..........................................................................................................................................145 Quiz ............................................................................................................................................ 146 Ćwiczenia ................................................................................................................................146 G o d zin a 9 T w orzenie p ro ste j grafiki ....................................................................................147 Używanie klasy QPainter ............................................................................................................ 148 Rozpoczęcie pracy z klasą QPainter ................................................................................. 148 Ustawianie stylu rysowania ................................................................................................149 Wybór pióra ............................................................................................................................. 150 Wybór stylu wypełniania .....................................................................................................150 Zmiana czcionki ................................................................................................................... 151 Poznawanie funkcji rysujących klasy QPainter ............................................................. 153 Rysowanie okręgów i elips .................................................................................................. 153 Rysowanie zaokrąglonego prostokąta ...............................................................................154 Rysowanie wycinka koła .....................................................................................................154 Rysowanie odcinka koła ....................................................................................................... 155 Rysowanie łuku ......................................................................................................................156 Rysowanie krzywej Beżiera ................................................................................................156 Praca z kolorami ........................................................................................................................... 157 Zarządzanie kolorami ............................................................................................................ 157 Specyfikowanie kolorów .....................................................................................................158 Model RGB ............................................................................................................................. 158 Model HSV ............................................................................................................................. 158 Użycie nazw anych kolorów ................................................................................................158 Zmiana standardowej palety ................................................................................................159 Drukowanie grafiki za pom ocą Qt ........................................................................................... 159 Ściąganie pakietów z Internetu ........................................................................................... 160 Podsumowanie ................................................................................................................................ 160 Pytania i odpowiedzi ................................................................................................................... 161 Warsztaty ..........................................................................................................................................161 Quiz ............................................................................................................................................ 161 Ćwiczenia ................................................................................................................................161 *
G o d zin a 10 O k n a dialogow e Q t ............................................................................................. 163 Używanie predefiniowanych okien dialogowych ................................................................ 164 Używanie okna dialogowego Color (Kolor) .................................................................. 164 Używanie okna dialogowego File (Plik) ..........................................................................166 Używanie okna dialogowego Font (Czcionka) ............................................................. 168 Używanie okna kom unikatów ........................................................................................... 170 Używanie okna dialogowego Progress (Postęp) ........................................................... 171
Spis treści
U
Tworzenie niestandardowych okien dialogowych ................................................................173 Tworzenie okien dialogowych za pom ocą klasy QDialog ..........................................173 Używanie klasy QTabDialog ............................................................................................. 176 Podsumowanie ................................................................................................................................180 Pytania i odpowiedzi ................................................................................................................... 181 Warsztaty ......................................................................................................................................... 181 Quiz ............................................................................................................................................181 Ćwiczenia ................................................................................................................................182 Część trze cia P o zn ajem y b a rd z iej bibliotekę Q t ..............................................................183 G o d z in a 11 U żyw anie m en e d że ró w u k ła d u ....................................................................... 185 Zrozumienie menedżerów układu ............................................................................................. 186 Używanie m enedżerów układu ................................................................................................187 Rozmieszczanie widgetów w wierszach i kolumnach ................................................. 188 U żywanie klasy QGridLayout ........................................................................................ 190 Zagnieżdżone menedżery układu ............................................................................................. 193 Praktyczny przykład ............................................................................................................ 196 Podsum owanie ............................................................................................................................... 200 Pytania i odpowiedzi ...................................................................................................................200 Warsztaty .........................................................................................................................................201 Quiz ........................................................................................................................................... 201 Ćwiczenia ............................................................................................................................... 201 G o d zin a 12 P r a c a z p lik a m i i k a ta lo g a m i ......................................................................... 203 Czytanie plików przy użyciu klas Qt ..................................................................................... 204 Odczytywanie katalogów przy użyciu klas Qt .................................................................... 207 Uzyskiwanie informacji o plikach za pom ocą klas Qt ........................................................ 210 Podsumowanie ............................................................................................................................... 215 Pytania i odpowiedzi ...................................................................................................................215 Warsztaty .........................................................................................................................................215 Quiz ........................................................................................................................................... 216 Ćwiczenia ............................................................................................................................... 216 G o d z in a 13 P rz e tw a rz a n ie tekstu i w y ra że n ia re g u la rn e ............................................217 Wyrażenia regularne ..................................................................................................................... 218 Metaznaki ............................................................................................................................... 218 Sekwencje unikowe .............................................................................................................. 219 Używanie predefiniowanych klas kontroli poprawności ................................................... 220 Używanie klasy QDoubleValidator ...................................................................................220 Używanie klasy QIntValidator .......................................................................................... 223 Tworzenie niestandardowych klas kontroli poprawności ................................................... 224 Używanie funkcji fixup() .................................................................................................... 227 Podsumowanie ............................................................................................................................... 228 Pytania i odpowiedzi ...................................................................................................................228
X
Poznaj Qt Programming w 24 godziny
Warsztaty ....................................................................................................................................... 229 Quiz ......................................................................................................................................... 229 Ćwiczenia ............................................................................................................................. 229 G odzina 14 U żyw anie klas p o je m n ik ó w ..........................................................................231 Poznajemy klasy pojemników Q t ............................................................................................. 231 Używanie stosów i kolejek ....................................................................................................... 233 Tworzenie stosu za pom ocą klasy QStack .................................................................. 233 Tworzenie kolejki za pom ocą klasy QQ ueue ................................................................236 Używanie tablic asocjacyjnych ................................................................................................237 Buforowanie d a n y c h ....................................................................................................................239 Praca z iteratorami ...................................................................................................................... 241 Podsumowanie ............................................................................................................................. 243 Pytania i odpowiedzi .................................................................................................................243 Warsztaty ....................................................................................................................................... 243 Quiz ...................................................... ...................................................................................243 Ćwiczenia ............................................................................................................................. 244 G od zin a 15 W ięcej o grafice .................................................................................................. 245 Praca z anim acjam i ................................................................................................................... 245 Ładowanie i zapisywanie obrazków ......................................................................................248 Praca z formatem obrazów biblioteki Q t ....................................................................... 249 Praca z obrazami obsługiwanych formatów ................................................................251 Używanie funkcji przekształceń klasy QPainter ................................................................253 Skalowanie obrazów ..........................................................................................................253 Pochylanie obrazów ............................................................................................................254 Obracanie obrazów ............................................................................................................ 254 Translacja obrazów ............................................................................................................ 255 Zmienianie view portu ....................................................................................................... 255 Ustawianie wielkości okna ................................................................................................256 Podsumowanie ............................................................................................................................. 256 Pytania i odpowiedzi ................................................................................................................. 257 Warsztaty ....................................................................................................................................... 257 Quiz ............................................................................................................................................ 257 Ćwiczenia ................................................................................................................................ 258 G o dzin a 16 K o m u n ik a c ja m iędzy p r o g r a m a m i ........................................................... 259 Wykorzystywanie s c h o w k a ........................................................................................................260 Użycie schowka dla tekstu ................................................................................................260 Użycie schowka dla map pikselowych ..........................................................................262 Implementacja funkcji „przeciągnij i upuść” ....................................................................... 266 Podsumowanie ............................................................................................................................... 270 Pytania i odpowiedzi ................................................................................................................. 271 Warsztaty ....................................................................................................................................... 271 Quiz ..........................................................................................................................................271 Ćwiczenia ..............................................................................................................................272
Spis treści
Część czw a rta Techniki p ro g ra m o w a n ia w Q t
XI
.............................................................. 273
G odzina 17 Pisanie aplikacji dla KDE: Lekcja pierw sza ........................................... 275 Poznawanie podstaw programowania w K D E ..................................................................... 276 Instalowanie KDE .............................................................................................................. 277 Pisanie pierwszego programu dla KDE ........................................................................277 Dodawanie przycisków, menu, pasków narządzi i paska stanu ...............................278 Korzystanie z obsługi HTML-a w KDE ............................................................................... 284 Podsumowanie .............................................................................................................................287 Pytania i odpowiedzi ................................................................................................................ 287 Warsztaty ...................................................................................................................................... 288 Quiz .........................................................................................................................................288 Ćwiczenia ............................................................................................................................ 289 G odzina 18 Pisanie aplikacji dla KDE: Lekcja d ru g a ................................................291 Poznawanie biblioteki jądra KDE ........................................................................................... 292 Tworzenie skrótów klawiaturowych za pomocą klasy KAccel ...............................292 Zarządzanie obrazami za pomocą klasy KPixmap .....................................................293 Uruchamianie podprocesów za pomocą klasy KProcess ........................................... 293 Interakcje z menedżerem okien za pośrednictwem klasy KWM ............................ 294 Poznawanie biblioteki interfejsu użytkownika KDE ..........................................................296 Używanie biblioteki operacji plikowych KDE ................................................................... 298 Wybieranie katalogu za pomocą klasy KDirDialog .....................................................298 Wybieranie pliku za pomocą klasy KFileDialog ......................................................... 299 Pobieranie informacji o pliku za pomocą klasy K F i l e l n f o .........................................300 Wyświetlanie podglądu plików za pomocą klasy KFilePreviewDialog ................ 300 Poznawanie pozostałych bibliotek KDE ............................................................................... 301 Podsumowanie .............................................................................................................................301 Pytania i odpowiedzi .................................................................................................................302 Warsztaty ...................................................................................................................................... 302 Quiz ....................................................................................................................................... 302 Ćwiczenia ..............................................................................................................................303 G od zin a 19 Używanie O penG L -ow ych klas biblioteki Q t ..........................................305 Przygotowywanie systemu do programowania OpenGL .................................................. 306 Pobieranie i instalowanie bibliotek MESA ................................................................... 306 Kompilacja OpenGL-owego rozszerzenia Qt .............................................................. 307 Poznawanie OpenGL-owych klas biblioteki Q t ................................................................... 307 QGLWidget: Widget OpenGL .........................................................................................307 Funkcja initializeGL() ....................................................................................................... 308 Funkcja paintGL() .............................................................................................................. 308 Funkcja resizeGL() ............................................................................................................309 QGLContext: Renderowanie grafiki OPenGL ............................................................ 309 QGLFormat: Ustawianie formatu wyświetlania dla kontekstu ............................... 309 Pisanie, kompilacja i uruchamianie programu OpenGL opartego na Q t ........................311
XII
Poznaj Qt Programming w 24 godziny
Analiza kodu programu .................................................................................................... 311 Kompilacja i uruchomienie przykładu ........................................................................... 320 Podsumowanie ...............................................................................................................................321 Pytania i odpowiedzi .................................................................................................................. 322 Warsztaty ........................................................................................................................................ 322 Quiz ........................................................................................................................................... 322 Ćwiczenia ...............................................................................................................................322 G odzina 20 T w orzen ie w tyczek do N etscape ....................................................................325 Przygotowanie systemu do konstrukcji wtyczek ..................................................................326 Pobieranie oprogram owania Netscape Plugin SDK ................................................... 326 Kompilacja rozszerzenia Qt dla wtyczek Netscape ..................................................... 327 Poznawanie klas wtyczek do Netscape dostępnych w Qt .................................................327 QNPlugin: Serce wtyczki ....................................................................................................327 Funkcja getMIMEDescription{) ....................................................................................... 328 Funkcja getP!uginNameString() ....................................................................................... 328 Funkcja getPluginDescriptionStringO ..............................................................................329 Funkcja newlnstance() .........................................................................................................329 QNPInstance: Łącznik między przeglądarką a wtyczką ............................................329 Funkcja newW indow() .........................................................................................................329 Funkcja newStreamCreated() ............................................................................................ 330 QNPWidget: Tworzenie wizualnej części wtyczki ..................................................... 330 QNPStream: Pobieranie strumieni danych z przeglądarki ......................................... 331 Tworzenie pierwszej własnej wtyczki do Netscape .............................................................331 Analiza kodu .......................................................................................................................... 331 Kompilacja i instalowanie wtyczki ...................................................................................333 Testowanie wtyczki ..............................................................................................................335 Podsumowanie ...............................................................................................................................336 Pytania i odpowiedzi .................................................................................................................. 336 Warsztaty .........................................................................................................................................336 Quiz ........................................................................................................................................... 337 Ćwiczenia ...............................................................................................................................337 Część p iąta U lepszanie w łasnych p ro g ra m ó w
..................................................................339
G odzina 21 In te rn a c jo n a liz a c ja p r o g ra m ó w w Q t ........................................................ 341 Zrozumienie znaczenia klasy QString ..................................................................................... 342 Tworzenie plików tłumaczeń ....................................................................................................342 Użycie funkcji tr() ................................................................................................................ 342 W ydobywanie tekstu do tłumaczenia za pom ocą narzędzia findtr .......................... 343 Tworzenie binarnych plików tłumaczeń za pom ocą narzędzia msg2qm .............. 346 Scalanie zmian za pom ocą narzędzia mergetr ............................................................... 347 Implementacja funkcji tłumaczeniowej ...................................................................................348 Praca z wartościami daty i czasu ............................................................................................ 350 Używanie klasy QDate z wartościami daty .................................................................... 350
Spis treści
XIII
Używanie klasy QTime z wartościami czasu .............................................................. 352 Używanie klasy QDateTime do łączenia wartości daty i czasu ...............................354 Podsumowanie ............................................................................................................................. 357 Pytania i odpowiedzi ................................................................................................................. 357 Warsztaty ....................................................................................................................................... 358 Quiz ......................................................................................................................................... 358 Ćwiczenia ............................................................................................................................. 358
G od zina 22 Przenośność .........................................................................................................359 Pisanie przenośnych aplikacji Qt ............................................................................................360 Używanie klas Qt ................................................................................................................. 360 Używanie funkcji strumieniowych Q t ............................................................................. 360 Używanie klas Qt do pracy z plikami i katalogami .....................................................361 Używanie klasy QPainter do rysowania ........................................................................ 361 Używanie klasy QPrinter do drukowania ......................................................................361 Używanie Qt do pracy z łączami sieciowymi ...............................................................362 Zachowywanie zgodności ze standardem POSIX ....................................................... 362 Izolowanie wywołań zależnych od platfonny . . ....................................................... 362 Nieprzenośne funkcje Qt ..........................................................................................................363 Konstruowanie przenośnego projektu za pomocą narzędzia tmake ............................... 365 Pobieranie i instalowanie tmake .......................................................................................366 Używanie tmake do tworzenia plików m a k e ................................................................. 367 Używanie progen do generowania plików projektów ....................................................... 372 Podsumowanie ............................................................................................................................. 373 Pytania i odpowiedzi ................................................................................................................. 374 Warsztaty ....................................................................................................................................... 375 Quiz ......................................................................................................................................... 375 Ćwiczenia ............................................................................................................................. 375 G od zin a 23 Techniki deb ugo w an ia ..................................................................................... 377 Używanie funkcji debugujących biblioteki Qt ....................................................................378 Używanie funkcji qDebug() ..............................................................................................378 Używanie funkcji qWaming() ......................................................................................... 379 Używanie funkcji qFatal() ................................................................................................ 380 Używanie makr debugujących biblioteki Qt ........................................................................ 381 Używanie makra ASSERT() .............................................................................................. 381 Używanie makra CHECK PTR() .................................................................................... 381 Używanie debugera gdb do debugowania programów Qt ................................................ 382 Pobieranie i instalowanie gdb ........................................................................................... 382 Praca z gdb ...........................................................................................................................382 Przydatne opcje linii poleceń ...................................................................................................385 Podsumowanie ............................................................................................................................. 386 Pytania i odpowiedzi ................................................................................................................. 386 Warsztaty ....................................................................................................................................... 387
XIV
Poznaj Qt Programming w 24 godziny
Quiz ........................................................................................................................................... 387 Ćwiczenia ...............................................................................................................................387 G o d zin a 24 W y k o rz y sty w a n ie k o n s tru k to ró w GUI ..................................................... 389 Praca z konstruktorem QtEz ...................................................................................................... 390 Pobieranie i instalowanie QtEz .......................................................................................... 390 Tworzenie prostego intefejsu GUI za pom ocą QtEz ................................................... 391 Tworzenie nowego projektu ...............................................................................................392 Dodawanie widgetów do projektu ...................................................................................394 Łączenie sygnałów i gniazd ...............................................................................................395 Tworzenie plików źródłowych projektu QtEz ............................................................... 396 Kompilacja i uruchomienie projektu QtEz .................................................................... 397 Praca z konstruktorem QtArchitect .......................................................................................... 398 Pobieranie i instalowanie programu Q t A r c h i t e c t .......................................................... 398 Tworzenie prostego interfejsu GUI za pom ocą programu QtArchitect .................399 Praca z konstruktorem Ebuilder ...............................................................................................402 Pobieranie i instalowanie programu Ebuilder ............................................................... 402 Tworzenie prostego interfejsu GUI za pom ocą programu Ebuilder ........................ 403 Podsumowanie ...............................................................................................................................405 Pytania i odpowiedzi .................................................................................................................. 406 Warsztaty ........................................................................................................................................ 406 Quiz ........................................................................................................................................... 406 Ćwiczenia ...............................................................................................................................407 Część szósta D o d a te k ................. 409 Dodatek A ...................................................................................................................................... 411 Odpowiedzi do Quizu .................................................................................................................. 411
Wstęp Sposób, w jaki ludzie używ ają komputerów, gwałtow nie zmieniał się przez lata. To. co za częło się od tajem niczych poleceń na czarnym ekranie, w ciągu ostatnich 10 lat rozw inęło się w środow isko prawie całkowicie graficzne, gdzie klaw iatura odgry w a mniej w a żn ą ro lę. Obecnie niew ielu ludzi bierze jeszcze pod uwagę korzystanie z pro gram ów działających w trybie tekstow ym . Dlatego też do tworzenia udanych program ów dla dzisiejszych użyt kowników w ym agane są graficzne interfejsy użytkow nika (GUI). Książka niniejsza nauczy Cię tw orzenia łatwych w użyciu program ów graficznych. Stosu jąc m etodę nauki „krok po kroku” będziem y przerabiać m ateriał zaczynając od rzeczy naj bardziej podstaw ow ych i stopniowo przechodzić do tych bardziej zaaw ansow anych. 24 lekcje, z których zbudow ana jest ta książka, w ypełnione są logicznym i wyjaśnieniam i, przykładami i instrukcjami, dzięki którym nauka program ow ania z użyciem Q t je st łatwa. Istnieje kilka różnych tzw. pakietów narzędzi (ang. toolkit) służących do tw orzenia graficz nych program ów w Linuksie. Jednak ten, o którym będziesz się tutaj uczyć - Qt - je s t je d nym z bardziej popularnych. Ze względu na obiektow ą hierarchię Qt, je g o solid n ą struktu rę, dobrze zaprojektow ane widgety i fakt, że oprócz funkcji do tw orzenia graficznych in terfejsów zaw iera on jeszcze wiele innych funkcji, pakiet ten stanowi dobry w y b ó r zarów no dla początkujących, ja k i dla ekspertów. Qt jest także zestaw em narzędzi w yk orzysty wanym przez dobrze znane środow isko desktopow e K D E i dlatego, w raz z pakietem na rzędzi Gtk+, w yznacza standard dla program ów graficznych w Linuksie. O przew adze Qt nad G tk+ stanowi jednak fakt. że ten pierwszy jest dostępny nie tylko dla system u U N IX /Linux, ale także dla M icrosoft W indows. O znacza to, że program w Qt napisany pod Linuksem jest faktycznie p opraw nym program em rów nież dla M icrosoft W indows! Przy lekturze tej książki zdziwisz się, z ja k ą łatw ością m ożna projektow ać program y gra ficzne jedno cześnie dla system ów M icrosoft W indow s i L inux/U N IX !
CZĘSC PIERWSZA Pierwsze kroki z Qt G od zin a
1 W prowadzenie do Qt 2 Programowanie obiektowe 3 Poznajemy podstawy Qt 4 Sprawiamy, że coś się dzieje: Gniazda i sygnały 5 Więcej o elementach konstrukcyjnych Qt
G o d z in a
1
Wprowadzenie do Qt Niniejsza, wstępna lekcja będzie wprowadzeniem do biblioteki Qt. O m ów im y zalety Qt to jest te cechy, które sprawiają, że biblioteka ta jest lepszym wyborem w porównaniu z in nymi bibliotekami do projektowania GUI, takimi jak Motif, Gtk+, w xW indows i Xforms. Powiemy także o tym, jak korzystać z dokumentacji Qt Reference Documentation. Jest ona bardzo ważnym źródłem informacji przy pracy z Qt. Mimo że w książce tej om aw iam y większość rzeczy, które powinieneś wiedzieć o Qt, to jednak nie powie Ci ona o wszyst kich aspektach dotyczących tej biblioteki. Dlatego od czasu do czasu będziesz m usiał za glądać do dokumentacji Qt Reference. Na koniec dowiesz się, jak utworzyć, skompilować i uruchomić bardzo prosty program w Qt, co będzie już wstępem do właściwego programowania, na którym skoncentrujemy się w następnych godzinach.
6
Godzina 1
Wybór biblioteki Qt Pakiet narzędzi GUI (lub biblioteka GUI) jest to zestaw przycisków, pasków przewijania, menu i wielu innych obiektów, których można używać do tworzenia graficznych interfej sów użytkownika (programów). W systemach UNIX-owych dostępnych jest wiele takich bibliotek GUI. Jedną z nich jest biblioteka Qt - pakiet narzędzi GUI oparty na języku pro gramowania C++. Ponieważ Qt bazuje na C++ (zamiast C), jest szybka, łatwa w użyciu i posiada dobre wspomaganie przenośności, więc stanowi najlepszy wybór, gdy chcemy tworzyć programy z graficznym interfejsem użytkownika dla systemów UNIX i/lub MS Windows.
Przenośność Qt jest dostępna nie tylko dla systemów UNIX-owych; jest dostępna również dla MS W in dows. Jeśli jesteś profesjonalnym programistą (skoro czytasz tę książkę, to przypuszczam, że nie, ale możemy założyć, że jesteś), który tworzeniem programów zarabia na życie, to Twoim celem musi być dotarcie do jak największej liczby użytkowników, tak aby mieli oni szansę nabyć (używać) Twój produkt. Jeśli specjalizujesz się w platformie MS Windows, to prawdopodobnie mógłbyś skorzystać ze standardowej biblioteki Microsoft Foundation Classes (MFC). Jednakże wtedy straciłbyś miliony użytkowników UNIX-a z całego świa ta. Z drugiej strony, jeśli Twoją główną platformą jest UN1X, mógłbyś skorzystać z jakiejś innej biblioteki, np. Gtk+ czy Xforms. Ale wtedy straciłbyś miliony (jeśli nie miliardy) użytkowników systemu MS Windows. Wynika z tego, że najlepszym wyborem byłby p a kiet narzędzi GUI, który jest dostępny zarówno dla UNIX-a, jak i MS Windows, prawda? Odpowiedź brzmi oczywiście: Qt.
Łatwość użycia Jak ju ż pow iedzieliśm y w cześniej, Qt jest pakietem narzędzi bazującym na jęz y k u C++. Składa się on z setek klas C++, gotow ych do zaim plem entow ania we w łasnych program ach. Poniew aż C + + je s t obiektow ym języ k iem program ow ania, a Qt opiera się na C++, więc Qt rów nież posiada w szystkie zalety program ow ania obiektow ego. O program ow aniu obiektow ym dow iesz się więcej w G odzinie 2, „P rogram ow anie obiektow e” . Jeśli wciąż nie jesteś przekonany do tego, że Qt stanowi najlepszy wybór, m ożesz spróbo wać także z innymi pakietami. Będziesz mógł wówczas zdecydować, który z nich najlepiej Ci odpowiada.
Szybkość działania Biblięteka Qt jest bardzo łatwa w użyciu, ale jest również bardzo szybka. Te dwa fakty zwykle nie idą ze sobą w parze. Gdy m owa o innych pakietach narzędzi GUI, łatwe często
Wprowadzenie do Qt
7
znaczy powolne, a szybkie często znaczy trudne (lub na odwrót: powolne znaczy łatwe, a szybkie znaczy trudne). Kiedy jednak mowa o Qt, szybkie i łatwe idą ze sobą w parze. Słowa uznania należą się za to ciężko pracującym twórcom biblioteki Qt; poświęcili oni mnóstwo czasu na optymalizację swojego produktu. Inna rzecz powodująca, że Qt jest szybszy od wielu innych pakietów narzędzi GUI to spo sób jego implementacji. Qt jest emulacyjnym pakietem narzędzi GUI. Oznacza to, że Qt w ogóle nie korzysta z wywołań żadnych macierzystych pakietów narzędzi. Qt emuluje wygląd i zachowanie zarówno interfejsu MS Windows, jak i M otif (standardowej bibliote ki GUI dla komercyjnych UNIX-ów) poprzez niskopoziomowe funkcje graficzne na wła ściwej platformie. Zwiększa to oczywiście szybkość programu. Inne pakiety narzędzi, jak np. wxWindows, które również są dostępne na wielu platformach, korzystają albo z warstwy API, albo z emulacji API. Obydwie te metody w taki czy inny sposób korzystają z macierzystego pa kietu narzędzi i często powodują spowolnienie programów.
Instalowanie biblioteki Qt Proces instalacji Qt jest łatwy. Sekcja ta opisuje, jak zainstalować Qt w systemach UNIX/Linux. W celu zainstalowania Qt w systemie MS Windows należy nabyć licencję od firmy Troll Tech lub poprosić o wersję próbną. Wszelkie informacje na ten temat można znaleźć w witrynie www.troll.no.
Kompilacja i instalacja dystrybucji źródłowej Qt Najlepszym chyba rozwiązaniem będzie ściągnięcie z witryny www.troll.no najnowszej w e rsji pakietu Qt Free Edition (w czasie, gdy to piszę, jest to wersja 2.0.2), a następnie sam o dzielne jego skompilowanie. W ten sposób upewnisz się, czy biblioteka jest zainstalowana poprawnie i czy Twoja wersja Qt zawiera najnowsze elementy i usprawnienia wprow adzo ne przez firmę Troll Tech. Plik z dystrybucją znajdziesz pod adresem ftp.troll.no, w podkatalogu /qt/source. W czasie, gdy piszę te słowa, najnowsza wersja znajduje się pod ftp.troll.no/qt/source/qt-2.0 2.tar.gz i zaj muje około 4MB. Przy ściąganiu dystrybucji upewnij się, że pobierasz najnow szą wersję (tę z najwyższym num erem wersji). Rysunek 1.1 przedstawia okno N etscape’a skierowane na archiwum plików ftp.troll no. Rozpocznie się proces pobierania pliku. Po zniknięciu okna pobierania z ekranu ściąganie będzie ukończone i można wówczas przystąpić do instalowania pakietu. Rozpocznij od przeniesienia nowo pobranego pliku do katalogu /usr/local. Teraz, z poziomu /usr/local, wykonaj następujące polecenie: # tar xvfz qt-2.0.2.tar.gz
Godzina 1
8
Rys. 1.1
W przeglądarce Netscape wprowadź adres taki jak pokazano w polu Address i naciśnij Enter. Następ nie kliknij prawym przyciskiem myszy plik z najnowszą dystrybucją i wybierz Save Link As.
Current directoryIs /qr/sonrcc T h u d i r e c to r y c o r.tsin * »eure« cod* fo r th « K v « rs io n cont«i(ni ri» i.« fll« x f o r appro*) m atni y « ílcruri ut! : r*s .
Ufc-lftJUaLSLU-iVtsi ’ uatali j._Raí¡as; .1 1 . ,
V *1 «i. .V i i 1 Kfc lt Kfc
2 Kh
:i .
Mi» Qct Tu« Tul
Mor. Oct
Kb
Ttm O c t
p.—ił\ .... '*J. ' , í > J.
25B1 Kb
W«tl Dec
A
252 S
i
2521
> ii ł l....
I a;.::» , “ii. u . ,
Kb
Thu
2.63? Kb
Mon Te i To« W« i
2Cjí>: Kh 42 4 ? Kb
. J L.
,0 i h i . . . >
> pewien_samochod.makspredkosc;
„Określ maks. prędkość samochoduhn:";
33: 34:
// Wczytaj moc silnika samochodu z klawiatury:
35:
cout «
36.
cin »
„Określ moc silnika samochodu!\n:”; pewien_samochod.mocsilnika;
37: 38:
II Wypisz dane samochodu:
26
Godzina 2
39:
cout «
„\n\nOto dane samochodu:\n";
40:
cout «
„\nWaga: ” «
41:
cout «
„\nDługość: ” «
pewien_samochod.waga; pewien_samochod.dlugosc;
42:
cout «
„\nSzerokość: ’’ «
43:
cout «
„\nMaks. prędkość: ” «
pewien_samochod.szerokosc;
44:
cout «
„\nMoc silnika: ” «
45:
cout «
„\n”;
pewien_samochod.makspredkosc;
pew iensam ochod.m ocsilnika;
4 6 :}
Zauważmy, że program z tego przykładu działałby dokładnie tak samo, gdyby zamiast klasy użyć struktury. Jeśli jednak chcemy, żeby klasa była troszkę „inteligentniejsza'’, musimy powiększyć ją o pewne cechy specyficzne dla klas. Powiedzmy, że chcemy, aby klasa umiała dokonywać obliczeń opartych na danych samochodu. W takim razie musimy dodać funkcje składowe, które zrobią dla nas te obliczenia. Funkcji nie można dodawać do struktur, ale można je dodawać do klas. Przykład pokazujący, w jaki sposób można by to zrobić, przedstawiono na listingu 2 .2 . Listing 2.2 Klasa samochód z funkcjami składowymi 1 #include 2 3 class samochód 4 { 5 public:
6
samochod();
7
void wypiszdane();
8 9 10 private: 11
void wypiszwage();
12 13 14
int szerokosc;
void wypiszmakspredkoscf); int dlugosc; int mocsilnika;
15 16 samochod::samochod() 17 { 18
II Wczytaj długość samochodu z klawiatury:
19
cout «
20
cin »
„Określ długość samochoduhn:”; this->dlugosc;
21
22
// Wczytaj szerokość samochodu z klawiatury:
23
cout «
24
cin »
25
„Określ szerokość samochoduhn:” ; this->szerokosc;
Programowanie obiektowe
27
26
// Wczytaj moc silnika samochodu z klawiatury:
27
cout «
28
cin »
29
„Określ moc silnika sam ochodu!\n:”; this->mocsilnika;
}
30 31 void samochód::wypiszdane() 32
{
33
// W ypisz dane samochodu:
34
cout «
„\n\nOto dane samochodu:\n” ;
35
cout «
tp\nDługość: ’’ «
36
cout «
„\nSzerokość: " «
37
cout «
„\nMoc silnika: " «
38
c o u t«
„\n";
39
this->dlugosc; this->szerokosc; this->mocsilnika;
}
40 41 void samochod::wypiszwage() 42
i
43
// W ypisz wagę samochodu na ekran:
44
cout «
45
„Waga: ” «
(this->dlugosc * this->szerokosc * 100 );
}
46 47 void samochod::wypiszmakspredkosc() 48
{
49
// Wypisz maks. prędkość samochodu na ekran:
50
if{ this->mocsilnika mocsilnika > 200)
55
{ cout «
56 57 58
„\nMaks. p rędko ść:" «
(this->m ocsilnika * 1.2) d!ugosc;
27 28
// W czytaj szerokość samochodu z klawiatury:
29
cout «
30
cin >> *this->szerokosc;
31
„Określ szerokość samochoduhn:";
Godzina 2
30
32
II W czytaj moc silnika samochodu z klawiatury:
33
cout «
34
cin »
35
„Określ moc silnika sam ochodu!\n:’’; *this->mocsilnika;
}
36 37 sam ochod::~sam ochod() 38
{
39
// Funkcja ta zostanie wywołana, gdy skończy się czas życia obiektu,
40
II zwalniam y pamięć poprzez użycie słowa kluczowego delete,
41
delete dlugosc;
42
delete szerokosc;
43
delete mocsilnika;
44
}
45 46 void sam ochod::wypiszdane() 47
{ II W ypisz dane samochodu: cout « „\n\nOto dane sam ochodu:\n”;
48 49 50
cout «
„\n D łu g o ść:" «
51
cout «
„\nS zerokość:" «
52
cout «
„\nM oc silnika: ’’ «
53
cout «
„\n";
54
*this->dlugosc; *this->szerokosc; *this->mocsilnika;
}
55 56 void sam ochod::wypiszwage() 57
{
58
// W ypisz wagę samochodu na ekran:
59
cout «
60
„Waga: ” «
( (*this->dlugosc) * (*this->szerokosc) * 100 );
}
61 62 void sam ochód::wypiszm akspredkosc() 63
{
64
// W ypisz maks. prędkość samochodu na ekran:
65
if{ *this->m ocsilnika m ocsilnika > 200)
70
{ cout «
71
„\n"; 72: 7 3 :} 74:
( (*this->m ocsilnika) * 1.2) «
}
„\nMaks. prędkość: " «
( (*this->m ocsilnika) * 0.8) «
Programowanie obiektowe
31
75: void main() 76: { 77:
// Utwórz obiekt klasy i wywołaj funkcje składowe:
78:
samochód pewien_samochod;
79:
pewien_samochod.wypiszdane();
80:
pewien_samochod.wypiszwage();
81:
pewien_samochod.wypiszmakspredkosc();
8 2:}
Jak widzimy, do przydzielania i zwalniania pamięci służą słowa kluczowe new i delete. Zwróćmy uwagę, że dostęp do właściwych danych uzyskujemy poprzez użycie operatora *. Gdyby pominąć ten operator, program znalazłby tylko adres pamięci (ponieważ mamy do czynienia ze wskaźnikami). No ale to są podstawowe rzeczy w C, więc powinieneś już o nich wiedzieć.
Jak działa dziedziczenie klas Inna znakomita rzecz związana z programowaniem obiektowym jest taka, że umożliwia ono wielokrotne używanie starego kodu. Mechanizm dziedziczenia klas umożliwia pro gramiście budowanie nowych klas na bazie starych, już przetestowanych. Możemy dodawać do klasy potrzebne nowe cechy i wciąż mieć możliwość wykorzystywania starego i (miejmy nadzieję) stabilnego kodu. Przeróbmy teraz przykład pokazujący, jak to może być zrealizowane. Przypuśćmy, że chce my zmodyfikować klasę z poprzedniej sekcji tak, aby można j ą było również wykorzystać do przechowywania informacji o samochodzie ciężarowym. Tak się składa, że ta ciężarówka przewozi rudę, więc będziemy chcieli przechowywać informacje o tym, jaką ilością rudy jest aktualnie załadowana. Program z nową klasą jest przedstawiony na listin gu 2.4.
Listing 2.4 Klasa ciężarówka na bazie klasy samochód 1: #include
2: 3: // Najpierw musimy dołączyć kod klasy samochód: 4: class samochód 5 :{ 6: public: 7: samochod(); 8:
~samochod();
9:
void wypiszdaneQ;
10 :
void wypiszwage();
Godzina 2
32
11:
void wypiszm akspredkosc();
12: private: 13:
int *dlugosc;
14:
int*szerokosc;
15:
in t ‘ mocsilnika;
1 6 :}; 17: 18: sam ochod::sam ochod() 19: { 20:
// Przydziel dynamicznie pamięć dla danych:
21:
dlugosc = new int;
22:
szerokosc = new int;
23:
m ocsilnika = new int;
24: 25:
// W czytaj długość samochodu z klawiatury:
26:
cout «
27:
cin »
„Określ długość samochodu!\n:"; *this->dlugosc;
28: 29:
// W czytaj szerokość samochodu z klawiatury:
30:
cout «
31:
cin »
32: 33:
// W czytaj moc silnika samochodu z klawiatury:
34:
cout «
35:
cin »
„Określ szerokość samochodu!\n:"; *this->szerokosc;
„Określ moc silnika samochodu!\n:"; *this->mocsilnika;
3 6 :} 37: 38: sam ochod::~sam ochod() 39: { 40:
// Funkcja ta zostanie wywołana, gdy skończy się czas życia obiektu,
41:
// zwalniam y pamięć poprzez użycie słowa kluczowego delete.
42:
delete dlugosc;
43:
delete szerokosc;
44:
delete mocsilnika;
4 5 :} 46: 47: void sam ochod::wypiszdane() 48: { 49:
// W ypisz dane samochodu:
50:
cout «
„\n\nOto dane samochodu:\n";
51:
cout «
„\n D łu g o ść:" «
52:
cout «
„\nSzerokość: ” «
53:
cout «
„\nMoc s iln ik a :" «
54:
cout «
„\n”;
5 5 :}
*this->dlugosc; *this->szerokosc; *this->mocsilnika;
33
Programowanie obiektowe
56 57 void sam ochód::wypiszwage() 58
{
59
// W ypisz wagę samochodu na ekran:
60
cout «
61
„Waga: " «
( (*this->dlugosc) * (*this->szerokosc) * 100 );
}
62 63 void sam ochod;:wypiszm akspredkosc() 64
{
66
II W ypisz maks. prędkość samochodu na ekran: if( *this->mocsilnika m ocsilnika > 200)
71
{ cout «
72 73 74
„\nMaks. p rę d ko ść:" «
( (*this->m ocsilnika) * 1.2) «
„\n";
( (*this->m ocsilnika) * 0.8) «
„\n";
} }
75 76 // Następnie tworzymy now ą klasę na bazie klasy samochód: 77 class ciężarówka : public samochód 78
{
79 public: 80
ciezarowka();
81
~ciezarowka();
82
void wypiszladunekrudyO;
83 private: int *ladunek_rudy;
84 85
86 87 ciężarówka:: ciężarówka () 88 { // Przydziel pamięć dla naszej nowej składowej z danymi: 89 la du n e kjru d y = new int;
90 91 92
// W czytaj ładunek rudy z klawiatury:
93
cout «
94
cin »
95
„Określ ładunek rudy!\n:"; *this->ladunek_rudy;
}
96 97 ciezarowka::~ciezarowka() 98
{
99
// Zwolnij pamięć przydzieloną w konstruktorze:
100:
delete ladunek rudy;
34
Godzina 2
101:} 102: 103: void ciezarowka::wypiszladunekrudy() 104: { 105:
II W ypisz ładunek rudy ciężarówki:
106:
cout «
„Ładunek r u d y :" «
*this->ladunek_rudy «
„\n”;
1 0 7 :} 108: 109: void main()
110 : { 111:
// Utwórz obiekt klasy i wywołaj funkcje składowe:
112:
ciężarówka pewna_ciezarowka;
113:
pewna_ciezarowka.wypiszdane();
114:
pewna_ciezarowka.wypiszwage();
115:
pewna_ciezarowka.wypiszm akspredkosc();
116: 117:
// Chcem y także w yw ołać specyficzną dla ciężarów ki funkcję w ypis-
zladunekrudy(): 118:
pewna_ciezarowka.wypiszladunekrudy();
1 1 9 :}
Kiedy uruchom isz ten program, szybko uzmysłowisz sobie, że konstruktor z klasy sam o chód także jest wykonywany. W ten sposób nie musisz ponownie pisać całkowicie nowego konstruktora, żeby wczytać wszystkie dane z klawiatury. Zam iast tego m ożesz stworzyć drugi konstruktor z cechami (właściwymi ciężarówce), które chcesz umieścić w klasie ciężarówka. Dzięki temu zaoszczędzisz sobie mnóstwo pracy. Nie musisz ponow nie tworzyć zmiennych utworzonych w klasie samochód, lecz tylko te zmienne, o które chcesz powiększyć nową klasę. Nie musisz także przedefiniowywać funkcji składowych do obliczania maksymalnej prędkości i wagi pojazdu. Przyjrzyjmy się nieco bliżej następującej linii: class ciężarówka : public samochód
Właśnie w tym m iejscu określamy, z jakiej klasy będzie dziedziczyć nowa klasa (w tym przypadku samochód). Zastosowaliśm y coś, co jest znane wśród program istów C++ jako dziedziczenie publiczne, które zasadniczo oznacza, że to, co jest zdefiniowane jak o pry watne w klasie bazowej, będzie prywatne także w nowej klasie. G dybyśm y zmienili słowo kluczowe public na private, to zostałoby użyte dziedziczenie pryw atne. Dziedziczenie pry watne czyni wszystkie funkcje prywatnymi w nowej klasie, łącznie z funkcjami pu b licznymi. Jednak zdecydowanie najczęściej stosowaną m etodą dziedziczenia - także przy pracy z Qt - je st dziedziczenie publiczne.
Programowanie obiektowe
35
W jaki sposób Qt wykorzystuje programowanie obiektowe Prawie wszystkie aspekty programowania obiektowego są, w taki czy inny sposób, obec ne w Qt. W tej sekcji przeanalizujemy parą przykładów na to, jak Qt korzysta z pro gramowania obiektowego. Qt jest biblioteką w pełni obiektową, ale do jej opanowania wcale nie będzie Ci potrzebna znajomość wszystkich aspektów programowania obiek towego. W sekcji tej nauczysz się najistotniejszych aspektów, które są wymagane do pełnego zrozumienia biblioteki Qt
Używanie dziedziczenia klas w Qt Wcześniej w tej godzinie dowiedziałeś się. jak przy użyciu dziedziczenia klas można wykorzystywać istniejący kod. Przy tworzeniu aplikacji Qt będziesz bardzo często korzys tać z dziedziczenia klas. W rzeczywistości, duża część procesu pisania aplikacji Qt składa się z pisania własnych klas w oparciu o istniejące klasy Qt. Bardzo prosty przykład tego przedstawiono na listingu 2.5.
Listing 2.5 Prosty przykład dziedziczenia klas w Qt 1: #include 2: #include 3: 4: class mojaklasa : public QWidget 5 :{ 6: public: 7:
mojaklasa();
8 :}; 9: 10: mojaklasa::mojaklasa() 11 : { 12 :
this->setMinimumSize( 200. 200 );
13:
this->setMaximumSize( 200, 200 );
14: }
15 16: int main( int argc, char **argv ) 17: { 18
QApplication a( argc, argv );
19
mojaklasa w;
20
a.setMainWidget( &w );
Godzina 2
36
21:
w,show();
22:
return a.exec();
23}
Mamy tu dokładnie to samo, co robiliśmy w poprzednim przykładzie. Dziedziczymy składowe z klasy QW idget przy użyciu dziedziczenia publicznego. Tworzony jest nowy konstruktor w celu zdefiniowania maksymalnych i minimalnych rozmiarów widgetu (klasy). Zauważmy, że można było także opuścić wskaźnik this; umieszczono go tylko dla przejrzystości. Rezultat kodu z listingu 2.5 pokazano na rys. 2.1.
Rys. 2.1
Prosta klasa bazująca na QWidget.
Tworzenie obiektów i używanie metod Ponieważ Qt jest biblioteką klas, więc musisz oczywiście wiedzieć, jak tworzyć obiekty klas udostępnianych przez Qt. Widziałeś, jak to się robi w elementarnym przykładzie z G o dziny l, „W prowadzenie do Q t”. Jednakże przy tworzeniu własnych klas robi się to nieco inaczej. Właściwie to ta metoda była już opisywana wcześniej w tej godzinie, ale teraz przerobimy przykład używający klas Qt. Musisz także wiedzieć, jak korzystać z metod (funkcji składowych) zawartych w klasach. Przykład znajduje się na listingu 2.6. Jest on dobrze okomentowany, abyś mógł w pełni zrozumieć, jak pisać programy obiektowe w Qt. Listing 2.6 Przykład programowania obiektowego w Qt 1: //include 2: #include 3: #include 4: 5: //Najpierw opisujemy klasę; jakie metody 6: II i inne składowe ma zawierać. 7: class mojaklasa : public QWidget 8: { 9: public; 10: 11: private:
mojaklasaQ;
P ro g ra m o w an ie o b iek tow e
12
II Zlokalizuj o bsza r pam ięci dla obiektu Q P ushB utton:
13 14
37
Q P ushB utton *b1;
};
15 16 II Z definiuj konstruktor: 17 m ojaklasa::m ojakla sa() 18
{
19
II O p uszczam y w ska źnik this, obiekt d om yśln y
20
II i ob ie kt bieżący to i tak to sam o:
21
setM inim um S ize( 200, 200 );
22
se tM a xim um S ize ( 200, 200 );
23 24
II P rzydziel pam ięć dla obiektu O P ushB utton,
25
II P rze ka zu je m y dw a arg u m e n ty do konstruktora
26
II klasy. P ierw szy je st e tykie tą
27
II przycisku, drugi to w id g e t m acie rzysty
28
// przycisku. Tutaj w ska źn ik this nap ra w dę
29
II się przydaje!
30
b1 = new Q P ushB utton ( „H ello", this );
31
II Tutaj u żyw am y m etody se tG e om e try()
32
II aby ustaw ić geom etrię przycisku.
33
b1-> setG eo m e try( 20, 20, 160, 160 );
34
}
35 36 int m ain( int argc, char **argv ) 37
{
38
// U tw órz obiekt Q A pplica tion:
39
O A pplication a( argc, arg v );
40
// U tw órz o b ie kt naszej now ej klasy:
41
m oja klasa w; // W yw ołaj m etodę Q A p p !ica tion::setM ain W idget:
42
a .se tM ainW id get( & w );
43
// W yw ołaj m etodę show () obiektu w (m ojaklasa):
44
w .show ();
45
II P rzekaż sterow anie do biblioteki Qt:
46 47 48
return a.exec();
}
P ow inieneś ju ż teraz m ieć elem entarn e pojęcie o tym , ja k pisać p ro g ra m y o b iek to w e w Qt. Na rys. 2.2 p o k a za n o obrazek p ro g ram u z listingu 2.6.
38
Godzina 2
Rys. 2.2
Bardzo prosty program w Qt napisany w stylu obiektowym.
Podsumowanie W tej godzinie przedstawiliśmy Ci mnóstwo nowych, a czasami skomplikowanych, infor macji. Jeśli rzeczywiście było to dla Ciebie zbyt skomplikowane, to powinieneś przeczy tać jakąś dobrą książkę o C++, która pomoże Ci w pełni zrozumieć logikę programowania obiektowego. Mimo że nie będziesz musiał być ekspertem od programowania obiek towego, aby z powodzeniem pracować z biblioteką Qt to jednak przyjdzie Ci łatwiej zrozumieć te bardziej skom plikow ane aspekty biblioteki, jeśli pośw ięcisz trochę dodatkowego czasu na naukę aspektów programowania obiektowego w języku C++. Jak już zaczniesz czuć się swobodniej w programowaniu obiektowym, szybko odkryjesz korzyści, jakie można odnieść ze stosowania wszystkich tych nowych rzeczy, które m a do zaoferowania język C++.
Pytania i odpowiedzi Mój kom pilator nie m oże skom pilować napisanego przeze mnie obiektowego kodu. Narzeka na brakujące p liki .h. Co je s t nie ta k? Aby móc skompilować program obiektowy, musisz mieć kompilator obiektowy, taki jak np. eges. Musisz mieć także zainstalowaną bibliotekę C++ i pliki nagłówkowe. Są to rzeczy, które otrzymujesz wraz z kompilatorem lub dystrybucją. Dlaczego otrzymują kom unikat o błędzie mówiący o zwracanym typie konstruktora, gdy próbuję skom pilow ać program obiektowy? Prawdopodobnie zapomniałeś o dodaniu średnika (;) po ostatnim nawiasie klamrowym ( 1) deklaracji swojej klasy. Gdy próbuję skom pilować program w Qt, otrzymuję masę błędów o brakujących odw oła niach (missing rejerences). Co je s t nie tak? Prawdopodobnie zapomniałeś dodać znacznika -!qt przy próbie kompilacji programu. Otrzymuję kom unikat o błędzie base operand oj '->' lias non-pointer type 'samochód'. O co chodzi? Jeśli obiekt jest wskaźnikiem, to w celu odwołania się do jego składowych należy użyć operatora ->. W przeciwnym razie należy użyć operatora kropka (.).
Program o wan ie obiek to we
39
Podczas ko m p ila cji pro g ra m u otrzym uję o strzeżenie initia lizin g no n -co n st 'bool & ' with 'int *' w ill use a tem porary. Co jest nie tak? Praw dopodobnie p ró b o w a łe ś o d w o ła ć się do z m ie n n e j, k tó ra fa k ty c z n ie je s t wskaźnikiem. Aby dostać się do w łaściw ych danych, m usisz użyć operato ra *.
Warsztaty Zachęcamy Cię do przerobienia poniższych pytań i ćw iczeń, które p o m o g ą Ci utrwalić sobie wiedzę zdo bytą w tej godzinie. Przerobienie następujących pytań pom oże Ci zro z u mieć istotę p ro g ram o w an ia obiektow ego.
Quiz 1. Co oznacza skrót O O P ? 2. Co to jest klasa? 3. Co to jest obiekt? 4. Co to jest m etoda? 5. Co to jest dziedziczenie klas? 6. Dlaczego do używ ania Qt potrzebna jest znajom ość p ro g ram o w a n ia o biek to w ego?
Ćwiczenia 1. Napisz klasę opisu jącą internautę. Niech klasa ta przechow uje płeć internauty, wiek, w y kształcenie oraz czas spędzany tygod nio w o w Internecie, a konstruktor niech zatroszczy się o w czytanie tych informacji z klawiatury. 2. Zmień program z poprzedniego ćw iczenia tak, by stosow ał dy n a m icz n e przydzielanie pamięci. Dodaj rów nież do klasy destruktor, który zwolni pam ięć za p o m o c ą słow a klu czowego delete. 3. Napisz program na podstaw ie listingu 2.2. U żyw ając d ziedziczenia klas, dodaj funkcję, która obliczy pole pow ierzchni sam ocho du w zależności od je g o szerokości i długości, a następnie w ypisze wynik na ekranie.
G o d z in a
3
Poznajemy podstawy Qt W tej godzinie sk o n c en tru jem y się na absolutnych p o d sta w ac h p ro g ra m o w a n ia w Qt. M o ż liwe, że tym , co skłoniło C ię do sięgnięcia po tę książkę, była chęć tw o rze n ia p ro g ra m ó w z graficznym interfejsem u ż y tko w nika (GU I). Jeśli tak, to zo b aczysz, że będzie to p a sjo nująca godzina. W trakcie tej lekcji utw orzysz sw o ją w ła sn ą klasę bazując na klasie O W idget. K la sa ta b ę dzie Twoim g łó w n ym okn em ; fun dam entem , na którym b ędziesz u m ie sz cz ał inne o b iek ty
Qt.
Tworzenie pierwszego własnego widgetu głównego Pierwszą rzeczą,, ja k ą m usisz zrobić, gdy z am ierzasz napisać n o w y p ro g ram w Q t, je st stworzenie w idg etu głów nego. W idget głów ny m o żn a sobie w y o b rażać ja k o p rzestrzeń ro
Godzina 3
42
boczą, na której umieszcza się przyciski, suwaki, etykiety, itd. Twój program może fak tycznie składać się z wielu takich widgetów, ale możesz użyć tylko jednego widgetu głów nego. Tym, co odróżnia główne okno od innych widgetów Qt, jest fakt, że wraz z zamknię ciem widgetu głównego kończy się cały program.
Wyjaśnijmy, dla pewności, czym tak napraw dę jest widget. W idget je st to graficzny (i prostokątny) obiekt, taki jak przycisk czy pasek przewijania. Puste okno je st także widgetem. Jednak, gdy m ó w im y o widgecie głównym, to n ajpraw dopodobniej jest to głów ne okno, chociaż m oże to być też jakiś inny widget. Główne okno bywa też nazy w an e w idg ete m najw yższego poziomu.
Najczęściej spotykana metoda tworzenia widgetu głównego polega na utworzeniu własnej klasy w oparciu o klasę OWidget lub QDialog. W tej książce będziemy głównie korzystać z klasy QWidget. Swoją własną klasę oprzesz na klasie QWidget przy użyciu dziedziczenia publicznego. Utworzysz nowy konstruktor, w którym zdefiniujesz wygląd okna przez wy wołanie kilku funkcji składowych (metod). Przyglądaliśmy się temu pobieżnie w Godzinie 2, „Programowanie obiektowe” , ale teraz bardziej się w to zagłębimy. Przykład takiej m e tody znajduje się na listingu 3.1. Tworzone jest tutaj puste okno i wyświetlane na ekranie. Rozmiary okna są ustawiane na 200 x 120 pikseli. Poza tym zwróć uwagę na to, że maksy malne i minimalne rozmiary są takie same, a więc nie będzie można zmieniać rozmiarów okna. Listing 3.1 Twój pierwszy widget główny 1: #include 2: #include 3: 4: // W deklaracji klasy potrzebujemy 5: // umieścić jedynie nowy konstruktor. Pozostałe 6: II metody są dziedziczone z klasy OWidget: 7: class MyMainWindow : public OWidget 8: {
9: public: 10:
MyMainWindow();
11:}: 12: 13: MyMainWindow::MyMainWindow() 14: { 15: 16: 17: 18: 19:
// Ustaw maksymalne i minimalne rozmiary
II okna (widgetu). Nie musimy II używać wskaźnika this, // ponieważ C++ domyślnie użyje / / klasy bieżącej:
Poznajemy podstawy Qt
20 :
setMinimumSize( 200, 120 );
21:
setMaximumSize{ 200, 120 );
43
22: } 23: 24: void main( int argc, char **argv ) 25: { 26 : // Utwórz wymagany obiekt klasy 27: II QApplication. Przekaż argumenty linii 28 : // poleceń do tego obiektu: 29: OApplication a(argc, argv); 30: // Utwórz obiekt głównego okna (MyMainWindow) 31: // i ustaw go jako widget główny: 32: MyMainWindow w; 33: a.setMainWidget( &w ); 34: II Namaluj na ekranie obiekt MyMainWindow 35: // i wszystkie jego widgety potomne: 36: w.show(); 37; II Przekaż sterowanie do biblioteki Qt: 38 : a.exec(); 39: }
Po skompilowaniu tego źródła, poprzez wpisanie w linii poleceń g++ -lqt plikwej -o plikwyj, musisz wykonać plik wynikowy plikwyj. Na rys. 3.1 pokazano, co pojawi się na ekranie.
Spróbuj teraz zmienić rozmiary okna. Co się dzieje? Nie da się tego zrobić! Powodują to linie 20 i 21. Ustawiają one maksymalne i minimalne rozmiary okna na taką samą wartość; dlatego nie można zmienić rozmiarów okna. Zauważmy też, że w liniach tych opuszczono wskaźnik this. Możesz go dołączyć, jeśli chcesz. Niektórzy programiści uważają, że kod łatwiej jest zrozumieć, jeśli wskaźnik ten jest dołączony. A teraz spróbuj zmienić wartości w liniach 20 i 21. Na przykład, zmień rozmiary maksy malne na 400 x 240 pikseli. Teraz da się zmienić rozmiary okna od 200 x 120 pikseli do 400 x 240 pikseli. Jeśli oprócz tego zmienisz rozmiary minimalne na 100 x 60 pikseli, to będzie można także pomniejszać okno. Do zdefiniowania rozmiarów okna, jak również jego położenia na ekranie, można wyko rzystać funkcję QW idget::setGeometry( ). Przykład użycia tej funkcji do tego celu przedsta wiono na listingu 3.2.
Godzina 3
44
Listing 3.2 Główne okno z zastosowaniem funkcji setGeometry() 1: tfinclude 2: #include 3: class MyMainW indow : public OWidget 5 { 6 public: 7
MyMainWindow();
8 }; 9
10 MyMainWindow::MyMainWindow() 11 {
12
setGeometry( 100, 100, 200, 120 );
13 } 14 15 void main( int argc, char **argv ) 16 { 17
QApplication a(argc, argv);
18
MyMainWindow w;
19
a.setMainWidget( &w );
20
w.show();
21
a.exec();
22 }
Za pomocą funkcji QWidget::setGeometry() ustalamy rozmiary okna i jego położenie w m o mencie, gdy pojawia się ono po raz pierwszy na ekranie. W pełni możliwe jest jednak prze suwanie i/lub zmienianie rozmiarów okna już po jego pojawieniu się. W aplikacji z listin gu 3.2 lewy górny róg okna pojawi się 100 pikseli na prawo i 100 pikseli w dół względem lewego górnego rogu ekranu [reprezentują to dwa argumenty podawane funkcji QWidget::setGeometry()]. Dwa ostatnie argumenty reprezentują rozmiary okna, gdy pojawia się ono na ekranie. W tym przypadku jest to 200 pikseli szerokości i 120 pikseli wysokości. Tak więc, gdybyś chciał, żeby okno pojawiło się 200 pikseli na prawo i 350 pikseli w dół względem lewego górnego rogu ekranu, i żeby miało 400 pikseli szerokości i 300 pikseli wysokości, mógłbyś wywołać setGeometry() następująco: setGeometry( 200, 350, 400, 300 ); Rys. 3.2 pokazuje, jak okno z listingu 3.2 będzie wyglądać na ekranie. Rys. 3.3 pokazuje, jak mogłoby ono wyglądać po przesunięciu i zmianie rozmiarów. Analizując te dwie metody definiowania geometrii okna, widzimy, że obydwie zawierają zarówno aspekty pozytywne, jak i negatywne. Jeśli nie dasz użytkownikowi swojego pro gramu możliwości zmiany rozmiarów okna, ryzykujesz tym, że okno nie zmieści się na jego ekranie. Z drugiej strony, jeśli pozwolisz użytkownikowi zmieniać rozmiary okna.
Poznajemy podstawy Qt
45
będzie Ci o wiele trudniej sprawić, żeby obiekty w oknie wyglądały dobrze. Nie stanowiło to jednak jeszcze problemu, ponieważ okno nie posiada jak na razie żadnych widgetów (obiektów) potomnych.
Rys. 3.2
Rysunek ten pokazuje, jak będzie wyglądać na ekranie okno z listingu 3.2.
Rys. 3.3
Ten rysunek pokazuje, jak mogłoby wyglądać okno z listingu 3.2, gdyby zmienić je g o rozmiary i przesunąć j e w inne miejsce ekranu.
!Cierni
46
Godzina 3
Dodawanie obiektów do widgetu głównego Z Twojego okna (programu) nie będzie większego pożytku, jeśli nie dodasz do niego obiektów umożliwiających interakcję z użytkownikiem. Puste, niewypełnione okno nie wiele może. Dlatego teraz dowiesz się, jak dodawać obiekty do nowo utworzonego okna. Nie jest to jednak trudne zadanie - do jego wykonania wystarczy podstawowa znajomość C + + . Na przykład, przy dodawaniu obiektów bardzo ważny jest wskaźnik this . Tak na prawdę, bez niego zadanie to jest zupełnie niewykonalne. Dlatego, jeśli nie wiesz, co to jest wskaźnik this i co się za jego pomocą robi, koniecznie to sobie przypomnij (po objaśnienia dotyczące wskaźnika this zajrzyj do Godziny 2 , „Programowanie obiektowe” ).
Dodawanie przycisku Na początek dodajmy do okna prosty przycisk. Przycisk ten nic nie będzie robił; będzie on tylko widoczny i aktywny (reagujący na kliknięcia). Dodajmy też jakiś sformatowany tekst do przycisku. Przykład znajduje się na listingu 3.3.
Listing 3.3 Obiekt MyMainW indow z przyciskiem 1: #include 2: #include 3: II Dołączamy plik qpushbutton.h, aby móc 4: // używać klasy OPushButton: 5: #include 6.
// Dołączamy także qfont.h, aby móc
7: // sformatować etykietę przycisku: 8: #include
9: 10: class M yMainW indow : public QWidget 11 : { 12: public: 13:
MyMainW indow();
14; private: 15: // Zlokalizuj pamięć dla przycisku:
16:
OPushButton *b1;
17: }; 18: 19: M yMainW indow::MyM ainW indow()
20 : { 21 : 22:
setGeometry( 100, 100. 200, 120 );
Poznajemy podstawy Qt
23:
// W tym m iejscu tw orzym y przycisk. Podajem y dwa argum enty
24:
// konstruktorow i: pierw szy reprezentuje
25:
// tekst etykiety, drugi reprezentuje w idget
26:
// m acierzysty przycisku. Tutaj wskaźnik this
27:
/ / jest bardzo użyteczny!
28:
b1 = new Q PushButton( „Przycisk 1", this );
29:
II Ponieważ b1 jest wskaźnikiem , więc używ am y operatora ->.
30:
II Ustawiam y geom etrię przycisku przez w yw ołanie
31:
II funkcji Q PushButton::setG eom etry():
32:
b1->setG eom etry( 20, 20, 160, 80 );
33:
// Ustaw czcionkę etykiety przycisku:
34:
b1->setFont( Q Font( „Times", 18, Q Font::Bold ) );
47
35: } 36: 37: void m ain( int argc, char **argv ) 38: { 39:
Q Application afargc, argv);
40:
M yM ainW indow w;
41:
a.setM ainW idget( &w );
42:
// Ponieważ b1 jest widgetem potom nym w, więc
43:
// zarów no b1, jak i w pokażą się po następującym w yw ołaniu:
44:
w.show();
45:
a.execQ;
46: }
Nie było to trudne, praw da? Zw róćm y uwagę na linię 34, w której form atow any jest tekst przycisku. Jest to robione za pośrednictwem funkcji QPushButton::setFont(), która jak o ar gument przyjm uje obiekt QFont. Zw róćm y także uwagę na trzy argum enty podaw ane k on struktorowi QFont - pierwszy reprezentuje czcionkę, drugi definiuje w ielkość czcionki, a trzeci sygnalizuje, że tekst m a być pogrubiony. Ostatni argum ent znany jest ja k o w aga te kstu; definiuje ona grubość tekstu (pełną listę wszystkich dostępnych wag m ożna znaleźć w sekcji QFont dokum entacji Qt Reference Docum entation). Opcjonalnie, m ożna również dodać czwarty argum ent do konstruktora. Pow inna to być wartość typu bool, określająca, czy tekst ma być pochylony, czy nie. R ozw ażm y poniższy przykład: b1->setFont( Q Font( „C ourier”, 12, Q Font::Light, TRUE );
Kod ten ustawiłby czcionkę na Courier, jej wielkość na 12 pikseli, wagę na lekką (przeci wieństwo pogrubienia) i wreszcie dokonałby jej pochylenia.
Godzina 3
48
Jeśli uważasz, że linia b1->setFont( QFont( „Times”, 18, QFont::Bold )); wygląda dziwnie, to zauważ, że równie dobrze działa poniższy kod: QFont font( „Times”, 18, QFont::Bold ); b1->setFont( fo n t); który być może da się już łatwiej zrozumieć.
Kompilując listing 3.3 utworzysz program pokazany na rys. 3.4. Rys. 3.4
Klasa MyMaili Window z obiektem QPushButton. Etykieta tekstowa je st sforma towana za pomocą funkcji QFont.
-;mii '•H *-V i> ' •' .*■" -»¿.y* «*'-
”,
-
' • / *• ,
1
’ -
o ! ■
■
.■
:• ■
r-< ■-V-' •
.
. v - i*.
•
'■'K ”-‘ - - •
■
•
■
...
*■* v.\" “r ' r
Dodawanie etykiety Chociaż proces dodawania widgetu potomnego do okna jest prawie taki sam - niezależnie od widgetu, jaki chcesz dodać - to jednak spójrzmy na to, jak wyglądałoby dodawanie etykiety tekstowej do okna - tak dla pewności, czy to rozumiesz. W tym celu musimy użyć klasy QLabel. Przykład znajduje się na listingu 3.4. Listing 3.4 Obiekt MyMainWindow z przyciskiem i etykietą 1: #include 2: #include 3: #include
Poznajemy podstawy Qt
49
4: #include 5: // Dołączamy plik qlabel.h, aby uzyskać dostęp do 6: // klasy QLabel: 7: #include 8:
9: class MyMainWindow : public OWidget 10: { 11: public:
12
MyMainWindow();
13 private: 14
QPushButton *b1;
15
QLabel ‘ label;
16 }; 17 18 MyMainW indow::MyMainWindow() 19 { 20
setGeometry( 100, 100, 200, 170 );
21
22
b1 = new QPushButton( „Przycisk 1", this );
23 24
b1->setGeometry( 20, 20, 160, 80 ); b1->setFont( QFont( „Times”, 18, QFont::Bold ) ) ;
25 26 27
// W tym miejscu tworzymy etykietę (label), definiujemy tekst
28
label = new QLabel( this );
29
label->setGeometry( 20, 110, 160, 50 );
30
label->setText( „To jest pierwsza linia\n
31 32
// i określamy, w jakim miejscu okna ma się pojawić etykieta:
To jest druga lin ia "); label->setAlignment( A lig n C e n te r);
33 } 34 35 void main( int argc, char “ argv ) 36 { 37
□Application a(argc, argv);
38 39
MyMainWindow w;
40 41
w.show();
a.setMainWidget( &w ); a.exec();
42 }
Zwróć uwagę, że użyliśmy tu tej samej metody, co wcześniej przy dodawaniu przycisku. Lokalizujemy pamięć dla etykiety (label) w deklaracji klasy, a następnie tworzymy i defi niujemy etykietę w konstruktorze. Linia 28 wywołuje konstruktor QLabel i przekazuje do niego wskaźnik this jako argument (tzn. ustanawia nie utworzony jeszcze obiekt MyMain Window widgetem macierzystym etykiety). Linia 29 ustawia, za pom ocą funkcji QLabel::set-
50
Godzina 3
Geometry(), geometrię etykiety. Zwróć uwagę, że etykietą tekstową operuje się w Qt lak jak prostokątnym polem, a więc jej geometrię można ustawiać tak samo jak w przypadku obiektu OPushButton. Linie 30 i 31 ustawiają tekst etykiety. Zawierają one także sekwencję \n, która reprezentuje przejście do nowej linii. Linia 32 mówi Qt, że tekst ma być wyśrod kowany w poziomie względem granie prostokątnego pola QLabel. Program ten jest poka zany na rys. 3.5. Klasy OLabel powinno się używać do wyświetlania krótkich napisów, np. w celu wyjaśnienia, co należy wpisać w danym polu tekstowym. Do wyświetlania dłuższych tek stów nie zaleca się stosowania QLabeI, gdyż w takich przypadkach lepiej funkcjonują widgety, takie jak QMultiUneEdit.
Rys. 3.5
Klasa My Main Window z przyciskiem i etykietą.
Powinieneś już teraz rozumieć zasady dodawania widgetów' do okien. Czy nie byłoby je d nak fajnie, gdyby po kliknięciu przycisku coś się działo? Oczywiście, że tak. No to zrób my to teraz.
Dodawanie przycisku wyjścia z programu Jedną z rzeczy, która tak bardzo różni Qt od innych, podobnych bibliotek, jest sposób, w jaki jej widgety wchodzą w interakcje z użytkownikami tzn. jaki jest bieg wydarzeń, gdy np. klikniesz przycisk lub przeciągniesz suwak. Podczas gdy większość innych bibliotek GUI używa tzw.fu n kcji zwrotnych (ang. callback functions), Qt używa sygnałów (ang. sig nals) i gniazd (ang. slots). Mówiąc prosto, sygnały i gniazda są to funkcje, które są ze sobą połączone. Gdy wykonany zostaje sygnał (który faktycznie jest funkcją), wykonywane jest również gniazdo połączone z tym sygnałem. Przykład znajdziesz w tej sekcji. Temat ten omówimy szczegółowo w dalszej części tej godziny. A tymczasem dowiesz się, w jaki sposób można dodać do przycisku prostą funkcję quit (patrz, listing 3.5).
Listing 3.5 Kliknij przycisk, a wyjdziesz z programu 1: ^include 2: #include 3: #include 4: #include 5: ^include
Poznajemy podstawy Qt
51
6: 7: class MyMainW indow : public QW idget 8: {
9: public: 10:
MyMainWindow();
11: prívate: 12:
QPushButton *b1;
13:
QLabel *label;
14:}; 15: 16: M yM ainW indow::MyM ainW indow()
17 18
setGeometry{ 100. 100, 200, 170 );
19
20 21 22
b1 = new QPushButton( „W yjście”, this ); b1->setGeometry( 20, 20, 160, 80 ); b1->setFont( QFont( „Times”, 18, QFont::Bold ) );
23 24
label = new QLabel( this );
25
label->setGeometry( 10, 110, 180, 50 );
26
label->setText( „Jeśli klikniesz przycisk powyżej,
27 28
nastąpi wyjście z program u” ); label->setAlignment( A lig n C e n te r);
29 30
// Poniższa linia wymusza wyjście z programu po tym,
31
//ja k nastąpi kliknięcie przycisku b1:
32
connect{ b1, SIGNAL( c lic k e d ()), gApp, SLOT( q u it( ) ));
33 } 34 35 void main( int argc, char **argv ) 36 i 37
QApplication a(argc, argv);
38
MyMainW indow w:
39
a.setMainW idget( &w );
40
w.show();
41
a.exec{);
42 }
Najbardziej interesującą częścią tego listingu jest linia 32. W linii tej sygnał clicked() przy cisku b l jest łączony z gniazdem quit() obiektu qApp. Teraz, po kliknięciu przycisku zostanie wyemitowany sygnał Q PushButton::clicked(), wykonane gniazdo qu it() z qApp i nastąpi w yj ście z programu. Ale cóż to za obiekt qApp? Otóż qApp jest wbudowanym w Qt wskaźni kiem. Został on tak zaprojektowany, aby zawsze wskazywał obiekt QApplication programu
52
Godzina 3
(w tym przypadku a), i działa tak jak wskaźnik this: Wskazuje obiekt, który nie został je szcze utworzony. Jest to bardzo ważny element Qt, ułatwiający programowanie przy uży ci insertltem( „Nowy" );
48:
plik->insertltem( „Otwórz" );
49:
plik->insertltem ( „Z a p is z ");
50:
plik->insertSeparator();
51:
plik->insertltem { „Wyjście". qApp, SLOT( q u it( ) ));
46:
52: 53:
edycja = new QPopupMenu( this );
54:
edycja->insertltem ( „Cofnij” );
55:
edycja->insertltem ( „Ponów" );
56:
edycja->insertSeparator();
57:
edycja->insertltem ( „W ytnij” );
58:
edycja->insertltem ( „Kopiuj" );
59:
edycja->insertltem ( „W k le j");
60:
edycja->insertSeparator();
61:
edycja->insertltem ( „Zaznacz w s z y s tk o ");
62: 63:
opcje = new QPopupMenu( this );
64:
opcje->insertltem( „Preferencje” );
65: 66:
pomoc = new QPopupMenu( this );
85
Godzina 5
86
67:
pom oc->insertltem ( „Spis tre ś c i");
68:
pom oc->insertSeparator();
69:
pom oc->insertltem ( „Inform acje” };
70:
II Koniec definicji menu.
71: 72:
II Rozpocznij wstawianie menu
73:
// w QMainW tndow:
74:
m enuBar()->insertltem ( „Plik", plik );
75:
m enuBar()->insertltem ( „Edycja", edycja );
76:
m enuBar()->insertltem ( „Opcje", opcje );
77:
m enuBar()->insertltem ( „Pomoc", pom oc );
78: 79:
/ / Zdefiniuj trzy mapy pikselowe
80:
ik o n a o tw o rz = QPixm ap( fileopen );
81:
ik o n a z a p is z = QPixm ap( filesave );
82:
ikona drukuj = Q Pixm ap( file p rin t);
83: 84:
// Utwórz pasek narzędzi i dodaj do niego
85:
II trzy przyciski. Przyciski te
86:
// łączym y z trzem a nie istniejącymi
87:
// gniazdami ( ale nie krępuj się ich
88:
// zaim plem entować!):
89:
toolbar = new QToolBar( this );
90:
b1 = new QToolButton{ ikona_otworz, „Otwórz plik", „O tw órz plik",
91: 92: 93: 94: 95:
this, SLOT( otworzQ ), to o lb a r); b2 = new QToo!Button( ikona_zapisz, „Zapisz
plik", „Zapisz plik”,
this, SLOT( zapiszQ ), to o lb a r); b3 = new QToolButton( ikona_drukuj, „Drukuj
plik", „Drukuj plik",
this, SLOT( d ru k u j()), to o lb a r);
96: 97:
// Ustaw w idgetcentralny jako
98:
II centralny w idget aplikacji. widgetcentralny = n ew QM ultiLineEdit( this );
99: 100:
setC entralW idget( w id g etcen tra ln y);
101 :} 102: 103: void main( int argc, char **argv ) 104: { 105:
Q Application a(argc, argv);
106:
M yM ainW indow w;
107:
a.setM ainW idget( &w );
108:
w.show():
109:
a.exec();
110: }
__
Więcej o elementach konstrukcyjnych Qt
87
Jak już nadmieniono, program ten bazuje na klasie OMainWindow. Fakt ten sprawia, źe me nu i przyciski są tworzone w trochę inny sposób. Na przykład, nie trzeba tworzyć żadnych obiektów QMenuBar; kwestią tą zajmuje się sam obiekt OMainWindow w liniach 7 4 -7 7 . W li niach 80-82 definiowane są trzy obiekty QPixmap (mapy pikselowe). Obiekty te są potem wykorzystywane na pasku narzędzi.
W Godzinie 9, „Tworzenie prostej grafiki", dowiesz się o innej metodzie wykorzystywa nia map pikselowych. Dołączanie map pikselowych jako zasobów (jak zrobiono w tym przykładzie) działa jednak bardzo dobrze.
W linii 89 tworzony jest pasek narzędzi, a w liniach 90-95 tworzone są trzy przyciski dla tego paska. Argumenty podawane konstruktorowi QToolButton zostały opisane w Tabeli 5 . 1.
Tabela 5.1 Argumenty dla konstruktora QToolButton Opis
Argument ikona_otworz
O biekt QPixmap zawierający mapę pikselow ą z obrazkiem danego przycisku
„Otwórz plik"
Tekst, który pojaw i się, gdy zatrzymasz wskaźnik m yszy nad przy ciskiem na kilka sekund
„Otwórz plik”
Tekst, który pojawi się na pasku stanu, gdy zatrzymasz wskaźnik m yszy nad przyciskiem na kilka sekund (tj. je ś li pasek stanu istnieje).
this
O biekt zawierający gniazdo, do którego chcesz przyłączyć ten przy cisk
SLOT( otworz() )
Gniazdo obiektu (p. w yżej)
toolbar
W idget macierzysty
W Godzinie 9, „Tworzenie prostej grafiki”, dowiesz się o innej metodzie wykorzystywa nia map pikselowych. Dołączanie map pikselowych jako zasobów (jak zrobiono w tym przykładzie) działa jednak bardzo dobrze.
Linia 99 tworzy obiekt OMultiLineEdit, a linia 100 ustanawia ten obiekt widgetem central nym. Widget centralny, w programie opartym na OMainWindow, jest widgetem, wokół którego są dodawane wszelakie menu, paski narzędzi oraz paski stanu. Widget, który definiujesz jako swój widget centralny, powinien być najważniejszą częścią Twojego pro gramu (jak np. obszar tekstowy w edytorze tekstów). Gdybyś tworzył program do rysowa nia, widgetem centralnym byłby prawdopodobnie obszar, w którym użytkownik miałby robić rysunki. Innym przykładem byłaby gra typu Tetris, gdzie widgetem centralnym byłby widget, w którym odbywałaby się sama gra (w tym przypadku widget, który sam
88
Godzina 5
utworzyłeś). W powyższym przykładzie, jako widgetu centralnego użyto obiektu dzięki czemu program będzie wyglądać tak jak edytor tekstów. Program ten zilustrowano na rys. 5.9.
QMultiLineEdit,
Rys. 5.9
Przy użyciu niezbyt wielu linii kodu można utworzyć program wyglądem i stylem przypominający składnik pakietu Microsoft Office.
Dodawanie paska stanu Pasek stanu jest tym małym paskiem, który zwykle widzisz u dołu wielu aplikacji. Poka zuje on użytkownikowi różne komunikaty, w zależności od tego, co ten użytkownik aktu alnie robi z aplikacją. Dodanie paska stanu do programu z listingu 5.5 to naprawdę proste zadanie. Wystarczy dodać do konstruktora klasy następującą linię: statusBar();
Jest to funkcja składowa klasy QMainWindow. Tworzy ona prosty pasek stanu na dole okna. Program będzie teraz wyglądać tak, jak pokazano na rys. 5.10.
Rys. 5.10
Widać tutaj, że u dołu okna dodany został pasek stanu. Pokazuje on aktualnie komu nikat dotyczący przycisku Otwórz.
Więcej o elementach konstrukcyjnych Qt
89
Jeśli zatrzymasz wskaźnik myszy nad którymś z przycisków, na pasku stanu pojawi się komunikat. Komunikat ten jest zdefiniowany przez trzeci argument podawany konstruk torowi QToolButton (w tym przypadku Otw órz plik). Normalnie należałoby tu jednak umieś cić bardziej szczegółowy opis polecenia, np. Kliknij ten przycisk, aby otworzyć plik. Jak powiedzieliśmy, pasek stanu ma za zadanie skrótowo informować użytkownika o tym, co się stanie, gdy wywoła on określone zdarzenie użytkownika. Wyświetlając na pasku sta nu tekst z krótkim objaśnieniem dla każdego elementu programu, ułatwiasz użytkownikom obsługę swojego programu oraz jego poznanie. Pamiętaj, że pasek stanu można wykorzystywać również do innych rzeczy poza objaśnie niami. Na pasku stanu można na przykład wyświetlać numer bieżącej linii lub nazwę pli ku aktualnie otwartego w edytorze, Pasek stanu zwiększa funkcjonalność Twojego progra mu. To, do czego możesz go wykorzystywać, zależy w dużej mierze od Twojej wyobraźni.
Podsumowanie W tej godzinie zrobiłeś kolejny krok w kierunku lepszego poznania Qt. Omówiliśmy niek tóre z najważniejszych części Qt - części, których wielką przydatność docenisz przy tworzeniu łatwych w użyciu GUI. Dowiedziałeś się, jak dodawać paski przewijania, menu, paski narzędzi i paski stanu. Są to elementy, które prawie każdy użytkownik chciałby widzieć w aplikacji. Wszystkie te ele menty polepszają funkcjonalność programu. Pasek przewijania ułatwia korzystanie z programu na różnych pulpitach i pozwala użytkownikowi zmienić rozmiary okna - w celu dopasowania go do wielkości ekranu - bez utraty żadnej z części programu. Dzięki menu i paskom narzędzi, funkcje i opcje progra mu można łatwo organizować, a sam program staje się łatwiejszy do poznania (i łatwiej się z niego korzysta). Przyjrzałeś się także klasie OMainWindow. Jest ona chyba jedną z najmocniejszych stron bib lioteki Qt. Właściwie, to klasy OMainWindow powinno się używać w większości przypadków (tam, gdzie interfejs użytkownika nie jest zbyt szczególny). Przy użyciu OMainWindow kon struowanie standardowego GUI staje się zarówno szybsze, jak i łatwiejsze. Jak już nadmieniono, w godzinie tej poruszyliśmy wiele z najważniejszych aspektów pro gramowania w Qt. Dlatego w celu sprawdzenia, czy wszystko zrozumiałeś - powinieneś przerobić znajdujące się poniżej sekcje „Pytania i odpowiedzi” oraz „Warsztaty” .
Pytania i odpowiedzi Tworzą przewijane okno i dodałem trochę obiektów za pomocą funkcji addChUdj). Jednak klasa QScrollView zdaje się troszczyć tylko o obiekt, który dodałem ja ko pierwszy. Paski przewijania nie pojawiają się, jeśli pierwszy obiekt może być pokazywany normalnie. Co jest nie tak? Najłatwiejsze, co możesz zrobić, aby rozwiązać ten problem, to dodać swoje widgety
90
Godzina 5
potomne do obiektu QW idget, a następnie dodać obiekt QWidget jako widget potomny do QScrollView za pom ocą funkcji addChild(). Po szczegóły zajrzyj do listingu 5.2. Chcę utworzyć pasek menu, ale menu, które dodałem nie pojaw iają się w oknie. Co jest nie tak? Upewnij się, czy dodajesz wszystkie menu do obiektu QMenuBar za pom ocą funkcji Q M enuBar::insertltem ().
Piszę klasę opartą na QMainWindow, ale moje menu nie pojaw iają się w oknie. Co je s t nie tak? Wszystkie menu musisz dodawać za pomocą fu n k c ji m enuBar()->insertltem (). Podczas próby kom pilacji listingu 5.5 kom pilator skarży się, że nie może odnaleźć plików map pikselowych. Co je s t nie tak? Aby kompilacja przebiegła poprawnie, musisz skopiować pliki map pikselowych fileopen.xpm, filesave.xpm i fileprint.xpm do katalogu, z którego próbujesz skompilować pro gram. Pliki te m ożesz znaleźć w katalogu examples/application swojej instalacji Qt.
Warsztaty Zachęcamy Cię do przerobienia poniższych pytań i ćwiczeń. Pomogą Ci one utrwalić sobie zdobytą w tej godzinie wiedzę i dadzą pewność, że dobrze rozumiesz, w jaki sposób działają ważne klasy Qt, omówione w tej godzinie.
Quiz 1.
Do czego można wykorzystać klasę QScrollView? 2. Jaka funkcja składowa służy do dodawania obiektów do klasy QScrollView'? 3. Co oznacza przew ijanie na żądanie? 4. Czym są Q MenuBar i QPopupMenu? 5. Kiedy należy wywołać funkcję Q M enuBar::insertltem ()? 6 . Czym są QToolBar i QToolButton? 7. Do czego jest dobra klasa QMainW indow? 8. Co to jest widget centralny w obiekcie QMainWindow? 9. Czy trze b a w y w o ły w a ć ja k ie ś sp e cja ln e fu n k c je , aby dodać pasek narzędzi do klasy o p a rte j na QMainW indow?
10. Co to jest QPixmap?
Ćwiczenia 1. Napisz program oparty na klasie QScrollView. Utwórz obiekt QW idget i d o d a j d o niego kilka widgetów (pomocna Ci tu będzie dokumentacja Qt, w której możesz znaleźć kilka
Więcej o elem entach konstrukcyjnych Qt
91
znakom itych w idgetów , o których jeszc ze nie m ów iliśm y). N astępnie dodaj obiekt QWidget do QScrollView. 2. Dodaj kilka m enu do program u napisanego w ćw iczeniu 3. Pam iętaj o tym, aby m enu te uczynić w idgetam i po tom nym i obiektu QWidget. 3. Uruchom popularny edytor tekstów, taki ja k kedit lub Notepad. Spróbuj sk opiow ać wygląd tego edytora, pisząc program oparty na OMainWindow. Staraj się ja k najbardziej upodobnić w ygląd m enu, pasków narzędzi oraz pasków stanu do tych z p raw d ziw e g o edytora tekstów. (B yć m oże będziesz m usiał zajrzeć do dokum entacji Q t R eference Docum entation).
CZĘŚĆ DRUGA Ważne zagadnienia dotyczące Qt Godzina 6 Poznajemy widgety Qt: Lekcja pierwsza 7 Poznajemy widgety Qt: Lekcja druga 8 Poznajemy widgety Qt: Lekcja trzecia 9 Tworzenie prostej grafiki 10 Okna dialogowe Qt
G o d z in a
6
Poznajemy widgety Qt: Lekcja pierwsza W tej godzinie przyjrzym y się dokładniej niektórym z w idgetów Qt. W szczególności na uczysz się używ ać przycisków, etykiet i tabel. Zarówno przyciski, ja k i etykiety są bardzo często w ykorzystyw ane w aplikacjach GUI. Dlatego m usisz wiedzieć, ja k z nich korzystać - nawet wtedy, gdy tw orzysz tylko n ajpro stsze programy. Z arów no przyciski, jak i etykiety m ają w yznaczone sw oje m iejsce we wszystkich w spółczesnych bibliotekach GUI - dotyczy to rów nież Qt. Tabele, z drugiej strony, nie są aż tak pow szechnie stosow ane w aplikacjach G U I, ale po trafią być one bardzo funkcjonalne (jeśli zostaną właściwie użyte). Tak więc pow inieneś używać tabel, kiedy tylko czujesz, że są one potrzebne w Twoich aplikacjach. W ięcej o ta belach dow iesz się przy końcu tej godziny.
96
Godzina 6
Używanie przycisków Przyciski są prawdopodobnie najczęściej używanymi obiektami GUI. Qt udostępnia trzy typy przycisków: • Przyciski zwykłe (Push button) • Przyciski radiowe (Radio button) • Przyciski pola wyboru (Check button) Przyciski zwykłe (typu push) służą do wywoływania pewnych zdarzeń, podczas gdy przy ciski radiowe i przyciski pola wyboru służą do dokonywania pewnego typu wyborów.
Przyciski zwykłe (Push Button) Klasa QPushButton jest prawdopodobnie tą klasą Qt, której będziesz używać najczęściej przy tworzeniu aplikacji Qt. Kilka przycisków utworzyłeś już we wcześniejszych godzi nach tej książki, ale obecnie przyjrzymy się dokładniej temu, jak faktycznie działa klasa CłPushButton i jakie funkcje składowe m ogą być Ci przydatne. Jak powiedzieliśmy, przyciski zwykłe są tworzone przez klasę QPushButton. Listing 6.1 przedstawia prosty przykład. Listing 6.1 Przykład użycia przycisku QPushButton 1: tfinclude 2: #include 3: #include
4: 5: class MyMainWindow : public QWidget
6:{ 7: public: 8:
MyMainWindow();
9: private: 10:
QPushButton *b1;
11:}; 12: 13: MyMainW indow::MyMainWindow() 14: { 15:
setGeometry( 100, 100, 200, 100 );
16:
b1 = new QPushButton( „To jest przycisk zwykły!",
17:
b1->setGeometry( 10, 10, 180, 80 );
18:
b1->setFont( QFont( „Times", 16. QFont::Bold ));
19:}
20 :
this );
Poznajemy widgety Qt: Lekcja pierwsza
97
21: void main( int argc, char **argv ) 22: { 23:
OApplication a(argc, argv);
24:
MyMainW indow w;
25:
a.setMainW idget( &w );
26:
w.show();
27:
a.exec();
28: }
W linii 10 przydzielana jest pamięć dla obiektu OPushButton. W linii 16 tworzony jest przy cisk (tj. wykonywany jest jeden z konstruktorów klasy OPushButton). Jest tutaj również ustawiana etykieta (pierwszy argument) oraz widget macierzysty (drugi argument) dla przycisku. W linii 17 ustawiane jest położenie i rozmiary przycisku. W tym przypadku, górny lewy róg przycisku jest umieszczany 10 pikseli w dół i 10 pikseli na prawo wzglę dem górnego lewego rogu widgetu macierzystego przycisku (tj. samego okna). W linii 18 ustawiane są wielkość i styl etykiety na przycisku. Przycisk utworzony w program ie z li stingu 6.1 pokazano na rys. 6 . 1. Rys. 6.1
Przycisk z listingu 6. f.
Gdy będziesz chciał połączyć przycisk z określonym zdarzeniem, połączysz sygnał OPushButton::clicked() z odpowiednim gniazdem. Przy użyciu funkcji Q PushButton::setPixm ap() możesz także dodać do przycisku mapę pikselową, w następujący sposób: QPixmap pixmap( „jakaspixm apa.xpm "); b1->setPixmap( pixmap );
gdzie jakaspixm apa.xpm jest wybraną przez Ciebie m apą pikselową. Rys. 6.2 pokazuje, jak może wyglądać przycisk z m apą pikselową. Rys. 6.2
Przycisk z umieszczoną na nim mapą p ik selową.
Przy pracy z przyciskami prawdopodobnie będziesz potrzebował skorzystać z funkcji Q PushButton::setDefauit(). Funkcja ta jest użyteczna, gdy w jednym oknie m asz wiele przy cisków. Przycisk, na którym użyjesz funkcji setDefau!t() stanie się przyciskiem dom yślnym - tj. przyciskiem, który zostanie kliknięty, gdy użytkownik naciśnie Enter.
98
Godzina 6
Przyciski radiowe (Radio Button) Przycisków radiowych powinieneś używać, gdy chcesz umożliwić użytkownikowi doko nanie jednego (i tylko jednego) wyboru z kilku możliwości. Przy użyciu klas OButtonGroup i QRadioButton można utworzyć grupę przycisków radiowych, tak jak pokazano na listingu 6.2.
Listing 6.2 Przykład użycia przycisku QRadioButton 1 ^include 2 tfinclude 3 #include 4 #include 5
6 class M yMainW indow : public QWidget 7 { 8 public: 9
MyMainWindow();
10 private: 11
OButtonGroup ‘ grupa;
12
QRadioButton *b1;
13
QRadioButton *b2;
14
QRadioButton *b3;
15 16 17 MyMainW indow::MyMainW indow() 18
{
19
setGeometry( 100, 100, 150, 140 ),
20 21 22
grupa = new QButtonGroup( „Opcje", this ); grupa->setGeometry( 10, 10, 130, 120 );
23 24
b1 = new QRadioButton( „Możliwość 1", grupa );
25
b1->move( 20, 20 );
26
b2 = new QRadioButton( „Możliwość 2H, grupa );
27
b2->move( 20, 50 );
28
b3 = new QRadioButton( „Możliwość 3", grupa );
29
b3->move( 20, 80 );
30 31
grupa->insert( b1 );
32
grupa->insert( b2 );
33
grupa->insert( b3 );
34 35
Poznajem y widgety Qt: Lekcja pierwsza
99
36: void main( int argc, char **argv ) 37: { 38:
CJApplication a(argc, argv);
39:
M yM ainW indow w;
40:
a.setM ainW idget( &w );
41:
w.show();
42;
a.exec();
4 3 :}
liniach 1 1 - 1 4 przydzielana jest pamięć dla jednego obiektu Q B u tto n G ro u p oraz trzech obiektów QRadiol3utton. W liniach 21 i 2 2 ustawiane są atrybuty obiektu CJButtonGroup. Pierwszy argum ent podawany konstruktorowi CJButtonGroup (linia 2 1 ) reprezentuje na główek dla tej grupy przycisków (patrz rys. 6.3 ). W linii 2 2 ustawiana jest geom etria gru py przycisków - tak jak zwykle, za pom ocą funkcji s e tG e o m e try (). Następnie, w liniach 2 4 - 2 9 tw orzone są i ustawiane trzy przyciski radiowe. Z w róćm y uwagę, że jak o widget macierzysty dla tych przycisków podawana jest grupa radiowa. Poza tym zauważmy, że za pomocą funkcji Q R a d io B u tto n ::m o v e () ustawiana jest pozycja przycisków. Choć m ożna by ło użyć tu funkcji s e tG e o m e try (), to jednak jest to niewskazane, poniew aż nie wiemy, ja k ą szerokość i w ysokość powinny mieć te przyciski. Na koniec, przyciski są w staw iane do grupy za pom ocą funkcji Q B u tto n G ro u p ::in s e rt() (linie 31, 32 i 33). K ońcow y efekt progra mu z listingu 6.2 pokazano na rys. 6.3. W
Rys. 6.3
Przykład obiektu QButtonGroup, grupują cego trzy obiekty QRadioButton.
hr yCWfcłJ !
.*
•V V
\
: - V.' 'C .iT 1 l'» Żhok«3 . * * ' V Air«:
Zauważmy, że w danym m om encie może być wciśnięty (zaznaczony) tylko jeden przycisk radiowy. To jest właśnie cecha różniąca przyciski radiowe od przycisków pola wyboru. Za każdym razem , gdy przycisk radiow y je s t zaznaczany (klikany), em ito w an y je s t sy gnał Q R a d io B u tto n ::isC h e cke d (). Jednak, w odróżnieniu od p rzyciskó w zw ykłych, p rz y c i sków radiow ych zazw yczaj nie używ a się do tego, by spo w o d o w ać ja k ie ś w izualne działanie program u, lecz do tego, by dokonać ja k ie g o ś rodzaju w yboru. N a przykład, w program ie spraw d zający m pisow nię m ożna by użyć kilku p rzyciskó w radiow ych, aby pozwolić uży tko w nikow i dokonać w yboru języka. W ó w czas gniazdo p o łąc zo n e z sy gnałem Q R a d io B u tto n ::isC h e cke d () nie pow odo w ałob y żadnej w izualnej z m ian y w p ro gramie, a zam iast tego w y w oły w ało by funkcję, która ustawia ję z y k na ten no w o w y brany.
100
Godzina 6
Przyciski pola wyboru (Check Button) Przyciski pola wyboru pow inieneś stosow ać, gdy chcesz umożliwić użytkow nikow i wy bór więcej niż jednej opcji spośród wielu dostępnych. Przy użyciu klas QButtonGroupi Q CheckBox m ożna utw orzyć grupę przycisków pola w yboru, co pokazuje przykład z listingu 6.3.
Listing 6.3 Przykład użycia pól wyboru QCheckBox 1 #include 2 #include 3 #include 4 #include 5
6 class MyMainW indow : public QW idget 7
{
8 public: MyMainW indow{);
9
10 private:
11 12
QButtonGroup "grupa;
13
Q CheckBox *b2;
14
Q CheckBox *b3;
Q CheckBox *b1;
15 16 17 MyMainW indow: :MyMainW indow() 18
{
19
setGeometry( 100, 100, 150, 140 );
20 21
grupa = new QButtonGroup( „Opcje", this );
22
grupa->setGeom etry( 10, 10, 130, 120 );
23 24
b1 = new QCheckBox( „Możliwość 1", grupa );
25
b1->move( 20, 20 );
26
b2 = new QCheckBox( „Możliwość 2", grupa );
27
b2->move( 20, 50 );
28
b3 = new QCheckBox{ „M ożliwość 3", grupa );
29
b3->move( 20, 80 );
30 31
grupa->insert( b1 );
32
grupa->insert( b2 );
33
grupa->insert( b3 );
34 35
Poznajemy widgety Qt: Lekcja pierwsza
101
36: voici main( int arge, char **argv ) 37 38:
QApplication a(argc, argv);
39: 40:
MyMainWindow w; a.setMainWidget{ &w );
41:
w.show();
42: 4 3 :}
a.exec();
W przykładzie tym, w liniach 11-14 przydzielana jest pamięć dla grupy przycisków i przy cisków pola wyboru. Grupa przycisków jest inicjalizowana w liniach 21 i 22, a przyciski pola wyboru w liniach 24-29. Następnie - identycznie jak w przykładzie z przyciskami radiowymi - przyciski pola wyboru są wstawiane do grupy przycisków za pomocą funkcji QButtonGroup::insert() (linie 31, 32 i 33). Rys. 6.4 przedstawia końcowy efekt programu z listingu 6.3. Rys. 6.3
Przykład obiektu QBultonGroup, grupującego trzy obiekty QCheckBox.
Tak jak w przypadku przycisków radiowych, o wciśnięciu obiektu QCheckBox informuje sygnał isChecked() (QCheckBox::isChecked()). Jak już wcześniej stwierdzono, przyciski pola wyboru pozwalają użytkownikowi wybrać więcej niż jedną możliwość. Dlatego nie użylibyśmy przycisków pola wyboru w sytuacji programu do sprawdzania pisowni, opisy wanej dla przycisków radiowych w poprzedniej sekcji. Gdybyśmy ich użyli, użytkownik mógłby wybrać jednocześnie angielski, francuski i niemiecki i nasz program do sprawdza nia pisowni byłby w wielkim kłopocie! Bardziej realistycznym przykładem, w którym przyciski pola wyboru są użyteczne, jest sytuacja z programu procesora tekstów, gdzie chcielibyśmy dać użytkownikowi możliwość wybrania stylu dla tekstu. W tym przypadku, w pełni dopuszczalny jest jednoczesny wybór atrybutów pogrubienia, kursywy i podkreślenia. Gdyby jednak użyć w’ tym przypadku przycisków radiowych, to użytkownicy mogliby wybierać w danym momencie tylko jedną metodę formatowania, a to jest niepożądane. Tak więc poznałeś trzy typy przycisków udostępnianych przez Qt i widziałeś, że używanie ich jest naprawdę proste. Pamiętaj, że jeśli potrzebujesz więcej informacji, zawsze możesz zajrzeć do dokumentacji Qt Référencé Documentation.
Tworzenie etykiet Od czasu do czasu zachodzi potrzeba dodania do własnej aplikacji tekstu w formie etykie ty. Etykiety stosuje się zwykle w celu przedstawienia krótkich informacji lub instrukcji do-
Godzina 6
102
tyczących w idgetów program u. Przy użyciu etykiety m ożna na przykład określić, co po winno być wpisane do danego pola tekstowego. Etykiety w Qt im plem entuje się przy uży ciu klasy O Label i, czasami, klasy O LCD Num ber.
QLabel Klasa O Label służy do w yśw ietlania prostego tekstu. Jest to bardzo podstawowy, ale uży teczny widget. N a listingu 6.4 przedstawiono prosty przykład.
L isting 6.4 Przykład użycia klasy QLabel 1 #include 2 #include 3 4 class M yM ainW indow : public Q W idget 5
{
6 public: 7
M yM ainW indow();
8 private: Q Label *tekst;
9
10 }; 11 12 M yM ainW indow: :M yM ainW indow () 13
{
14
setG eom etry( 100, 100, 170, 100 );
15 16
tekst = new Q Label( this );
17
tekst->setG eom etry{ 10, 10, 150, 80 );
18
tekst->setText( „To jest \nobiekt O L a b e l.");
19
tekst->setAlignm ent{ A lig n H C e n te r) A iig n V C e n te r);
20 ) 21
22 void m ain( int argc, char **argv ) 23
{
24
Q Application a(argc, argv);
25
M yM ainW indow w;
26
a.setM ainW idget( &w );
27
w.show();
28
a.exec();
29
}
Poznajemy widgety Qt: Lekcja pierwsza
103
Na rys. 6.5 pokazano program z listingu 6.4. Rys. 6.5 Okno z prostym obiektem QLabel.
Zwróćmy uwagę na sposób ustawiania wyrównania tekstu w linii 19. Jest to standardowy sposób ustawiania wyrównań w Qt. AlignHCenter oraz AlignVCenter są definicjami Qt. Opisy wszystkich definicji dla ustawień wyrównania podano w tabeli 6 1.
Tabela 6.1 Definicje dla ustawień wyrównania Funkcja
Opis
AlignTop
Tekst zostanie dodany u góry obiektu QLabel.
Align Bottom
Tekst zostanie dodany u dołu obiektu Q l,abcl.
AlignLeft
Tekst zostanie dodany po lewej stronie obiektu QLabel.
AligriRirght
Tekst zostanie dodany po prawej stronie obiektu QLabel.
AlignHCenter
Tekst zostanie dodany w poziomej pozycji środkowej obiektu QLabel.
AlignVCenter
Tekst zostanie dodany w pionowej pozycji środkowej obiektu QLabel.
AlignCenter
To samo co ustawienie A lignH C enter + A lignVC enter.
WordBreak
Jeśli ta funkcja jest ustawiona, stosowane je st automatyczne dzielenie wyrazów.
ExpandTabs
Funkcja ta powoduje, że QLabel rozw ija tabulatory.
Zauważmy, jak za pomocą operatora „lub” (|) rozdzielane są argumenty dla funkcji QLabel::setAlignment(). Metodę tę stosuje się także, gdy trzeba dodać więcej argumentów; po prostu należy je rozdzielać operatorami |.
Klasę QLabel można także wykorzystać do wyświetlania map pikselowych i animacji. Robi się to za pomocą funkcji QLabel::setPixmap() i QLabel::setMovie().
QLCDNumber Jeśli chcesz prezentować w swoim programie informacje numeryczne, to właściwym wy borem będzie dla Ciebie klasa OLCDNumber. Podobnie jak QLabel, klasa OLCDNumber jest często wykorzystywana do przedstawiania użytkownikowi krótkich infonnacji (w' tym
Godzina 6
104
przypadku informacji num erycznych), takich ja k np. bieżąca data. Listing 6.5 przedstawia przykład program u w ykorzystującego obiekt Q LCDNum ber.
L isting 6.5 Przykład użycia klasy Q L C D N um ber 1: #include 2: #include 3: 4: class M yM ainW indow : public O W idget
5: { 6: public: 7:
M yM ainW indow();
8: private: 9:
O LC D N um ber ‘ liczba;
10:}; 11: 12: M yM ainW indow ::M vM ainW indow () 13: { 14:
setGeometry( 100, 100, 170, 100 );
15:
liczba = new Q LCDNum ber( this );
16:
liczba->setG eom etry( 10, 10, 150, 80 );
17:
liczba->display( 12345 );
1 8 :} 19: 20: void main( int argc, char **argv )
21: { 22:
O Application a(argc, argv);
23:
M yM ainW indow w;
24:
a.setM ainW idget( &w );
25:
w.show();
26:
a.exec();
27:}__________________________________________________________________ W linii 9 pow yższego program u przydzielana jest pamięć dla obiektu O LC D N um ber. Obiekt ten jest tworzony w linii 15, a w linii 16 jest ustawiana jeg o geometria. Następnie wywoływana jest funkcja Q LC D N um ber::display() w celu wyświetlenia liczby podanej jako argument (linia 17). Rys. 6.6 przedstawia rezultat kodu z listingu 6 .6 . Rys. 6.6 Okno z obiektem QLCDNumber.
Poznajemy widgety Qt: Lekcja pierwsza
105
Inne funkcje, przydatne przy pracy z obiektami klasy QLCDNumber, opisano w tabeli 6.2. Tabela 6.2 Interesujące funkcje składowe klasy QLCDNumber Funkcja
Opis
setNumDigits()
Ustawia liczbę c yfr do wyśw ietlania.
setBinMode()
Ustawia
w yśw ietlacz na reprezentację dw ójkow ą.
setOctMode()
Ustawia
w yśw ietlacz na reprezentację ósemkową.
setHexMode()
Ustawia
w yśw ietlacz na reprezentację szesnastkową.
setDecMode()
U staw ia w yśw ie tla cz na domyślne).
setSmallDecimalPointO
Przekazując jeden z argumentów (TRUE lub FALSE) do tej funkcji, można określić, czy m ożliw a kropka dziesiętna będzie pokazywana na samodzielnej pozycji, czy pom iędzy dwom a cyfram i. Innym i słowy, je ś li przekażesz do tej funkcji TRUE, kropka dziesiętna zajm ie m niej miejsca niż zw ykle.
setSegmentStyleO
Za pomocą tej funkcji można zm ienić w ygląd w yśw ietlanych cyfr. Przekaż do niej jeden z argumentów (O utlinc, F illcd lub Fiat).
checkOverFlow()
Funkcję tę należy w yw ołać w celu sprawdzenia, czy dana wartość zmieści się w polu wyświetlacza. (OLCDNum ber em ituje także sygnał, o ve rflo w (), który możesz połączyć z gniazdem, które stosownie obsłu ży taką sytuację.)
reprezentację
dziesiętną
(ustaw ienie
Pamiętaj o tym, że obiekt OLCDNumber jest często używany w połączeniu z obiektem QSlider. Przykład na to znajdziesz na listingu 4.1 z Godziny 4, „Sprawiamy, że coś się dzieje: Gniazda i sygnały”.
Praca z tabelami Klasa QTableView jest przeznaczona w Qt do tworzenia tabel. Jest to użyteczna klasa, ale jej definicje są dość abstrakcyjne. Dlatego, aby zrobić jakiś użytek z QTableView, trzeba z niej wyprowadzić nową klasę.
Tworzenie prostej tabeli Przy tworzeniu klasy opartej na QTableView trzeba zaimplementować funkcję paintCell(). Funkcja ta nie jest zdefiniowana w klasie QTableView, ale jest przez nią wykorzystywana do rysowania komórek tabeli. Dlatego trzeba zaimplementować funkcję o tej nazwie, która wykona zadanie rysowania komórek. Być może wydaje Ci się, że to coś taidnego - ale to nic z tych rzeczy. Na listingu 6.6 przedstawiono prosty przykład wykorzystania klasy QTableView do stworzenia tabeli.
Godzina 6
106
Przy implementowaniu funkcji paintCell() będziesz musiał użyć jakichś funkcji rysują cych z klasy OPainter. Klasa ta i jej metody są szczegółowo omawiane w Godzinie 9, „Tworzenie prostej grafiki", oraz w Godzinie 15, „Więcej o grafice".
Listing 6.6 Prosta tabela utworzona za pomocą klasy QTableView 1: #include 2: #include 3; #include 4: #include 5: 6: class MyMainW indow : public QTableView
7:{ 8: public 9:
MyMainWindowQ;
10: private: 11:
void paintCell( QPainter *, int, int );
12: }; 13: 14: M yMainW indow::MyM ainW indow() 15: { 16:
setGeometry( 100, 100, 300, 300 );
17: 18:
// Ustaw liczbę kolumn:
19:
setNumCols{ 6 );
20:
// Ustaw liczbę wierszy:
21:
setNumRowsf 10 );
22:
// Ustaw szerokość komórek:
23:
setCellW idth( 50 );
24:
II Ustaw wysokość komórek:
25:
setCellHeight( 30 );
2 6 :} 27: 28: // Tutaj zaczyna się prosta implementacja funkcji paintCell(): 29: void M yMainW indow::paintCell( QPainter* p, int wiersz, int kolumna ) 30: { 31:
// Uzyskaj wysokość i szerokość komórek:
32:
int x = cellW idth( kolumna );
32:
int y = cellHeight( wiersz );
34: 35:
// Do utworzenia komórki wystarczą dwie linie:
36:
p->drawLine( x, 0, x, y );
37:
p->drawLine( 0, y, x, y );
38: }
Poznajemy widgety Qt: Lekcja pierwsza
107
39: 40: void main( int arge, char **argv ) 41: { 42:
QApplication a(argc, argv);
43:
MyMainW indow w,
44:
a.setMainW idget( &w );
45:
w.show();
46:
a.exec();
4 7 :}
Program z powyższego listingu rysuje prostą siatką, z sześcioma kolumnami (linia 19) i dziesięcioma wierszami (linia 21). Wszystkie komórki mają takie same rozmiary: 50 pi kseli szerokości (linia 23) i 30 pikseli wysokości (linia 25). W linii 29 rozpoczyna się definicja funkcji paintCell(). Jak widzisz, jest to bardzo prosta we rsja funkcji, składająca się tylko z czterech linii kodu. Linie 32 i 33 wywołują funkcje cellW idth() i cellH eight() w celu stwierdzenia, jaka jest, odpowiednio, szerokość i wysokość bie żącej komórki (komórki, która ma zostać narysowana). Linie 36 i 37 wykonują zadanie ry sowania. Zauważ, że rysowane są tylko linie dolna pozioma i prawa pionowa. Patrząc na linie kodu 36 i 37 może Ci się wydawać, że linie rysowane są cały czas na tej samej pozycji. Jednak tak nie jest - dba o to klasa QTableView. Klasa ta za każdym razem ustawia obszar rysowania dla obiektu OPainter i dlatego narożnik każdej komór ki ma wsp. (0,0).
Rys. 6.7 przedstawia okno programu z listingu 6 .6. Rys. 6.7 Prosty program oparty na klasie QTableView.
Dodanie tekstu i funkcji zaznaczania po kliknięciu Mimo że w programie z listingu 6.6 utworzyliśmy ładną tabelkę, nie jest ona jeszcze użyteczna. Najprawdopodobniej chciałbyś, abyśmy dodali do komórek jakieś informacje tekstowe. Program przedstawiony na listingu 6.7 zawiera już tekst oraz dodatkowo funkcję powodującą zaznaczenie tekstu po kliknięciu komórki.
Godzina 6
108
Listing 6.7 Tabela z tekstem i funkcją zaznaczania po kliknięciu 1 #include 2 #include 3 #include 4 #include 5
6 class MyMainW indow : public QTableView 7
8 public 9
M yM a'\nW \ndow (V ,
10 private: 11 12
void paintCell( Q Painter *, int, i n t );
13
int biezWiersz, biezKolumna;
14
void mousePressEvent( QMouseEvent * ) ;
};
15 16 M yMainW indow::MyM ainW indow() 17
{ setGeometry( 100, 100, 300, 300 );
18 19
20
setNum Cols( 12 );
21 22
setNumRows( 20 );
23
setCellHeight( 30 );
setCellW idth( 80 );
24 25
// Poniższe wywołanie funkcji powoduje
26
II pojawienie się poziomego i pionowego
27 29
II paska przewijania: setTableFlags( Tbl_vScrollBar | T b l_h S cro llB a r);
30
II Poniższa linia zmienia kolor
31
II komórek: setBackgroundM ode( PaletteBase );
28
32 33
biezW iersz = biezKolumna = 0;
34 35
}
36 37 void M yM ainW indow::paintCell( QPainter* p, int wiersz, int kolumna ) 38
{
39
int x = (cellW idthf kolumna ) -1 );
40
int y = (cellHeight( wiersz ) - 1);
4 4
p->drawUne( x, 0, x, y );
4
p->drawLine( 0, y, x, y );
Poznajemy widgety Qt: Lekcja pierwsza
44 45
// Dodaj tekst „Trochę tekstu" w środku każdej z komórek:
46
p->drawText( 0, 0, (x+1), (y+1), AlignCenter, „Trochę tekstu” );
47 48
// Jeśli jest to bieżąca komórka, to narysuj
49
// wokół niej dodatkową ramkę:
50
if( (wiersz == biezWiersz) && (kolumna == biezK olum na))
51
{
52
// Jeśli mamy fokus, narysuj ciągły
53
// prostokąt wokół bieżącej komórki
54
if( hasF ocus())
55
{
56
p->drawRect( 0, 0, x, y );
57
}
58
II Jeśli nie mamy fokusa, // narysuj prostokąt przerywany, else
59 60 61 62
{ p->setPen( DotLine );
63
p->drawRect(0, 0, x, y);
64
p->setPen( SolidLine );
65 66 67
}
68 69 // Poniższa funkcja obsługuje kliknięcia myszą: 70 void MyMainWindow::mousePressEvent( QMouseEvent *e) 71 { int staryWiersz = biezWiersz; 72 int staraKolumna = biezKolumna; 73 74 QPoint kliknietaPoz = e->pos(); 75 76 II Dowiedz się, którą komórkę kliknięto: 77 biezWiersz = findRow{ kliknietaP oz.y()); 78 biezKolumna = findCol( kliknietaPoz.x()); 79 80 // Jeśli nie była to bieżąca komórka, zaktualizuj zarówno 81 // bieżącą, jak i starą komórkę; 82 if( (biezWiersz != staryWiersz) || (biezKolumna != staraK olum na)) 83 84 { updateCell( staryWiersz, staraKolumna ); 85 updateCell( biezWiersz, biezKolumna ); 86 87
88
}
109
110
Godzina 6
89: 90: void main( int arge, char **argv ) 91: { 92:
QApplication a(argc, argv);
93:
MyMainW indow w;
94:
a.setMainWidget( &w );
95:
w.show();
96:
a.exec();
9 7 :}
W przykładzie tym paski przewijania są dodawane do tabeli poprzez wywołanie funkcji setTableFlags() z odpowiednimi argumentami (linie 28 i 29). W linii 32 zmieniany jest ko lor komórek. Kilka nowych rzeczy dodano też do funkcji paintCell(). Pierwszą z nich jest prosta etykieta tekstowa dodawana do komórek w linii 46. Nie musisz, oczywiście, w swoim programie dodawać identycznego tekstu do 240 komórek, jak zrobiono w tym przykładzie! Jednak metoda jest zawsze taka sama. Funkcja paintCell() sprawdza teraz, czy komórka, którą ma narysować, jest aktualnie zaznaczona. Jeśli program posiada fokus (tzn. jest on aplikacją aktualnie aktywną), a aktualnie rysowana komórka jest zaznaczona, wokół tej komórki zo stanie narysowany dodatkowy prostokąt. Jeśli program nie posiada fokusa, prostokąt bę dzie przerywany. Rys. 6.8 przedstawia ten program w akcji. Rys. 6.8
Tabela z tekstem w komór kach. Aktualnie zaznaczona jest lewa górna komórka.
Safnit
SO««
Dodanie nagłówka Prawdopodobnie będziesz chciał dodawać jakiegoś typu nagłówki do w ierszy i kolumn swoich tabel. Robi się to przy użyciu klasy OHeader. Przykład znajdziesz na listingu 6 .8 . Listing 6.8 Tabela z poziomym n a g ł ó w k i e m ________________________________ 1: #include 2: #include 3: #include
Poznajemy widgety Qt: Lekcja pierwsza
4: #include 5: #include 6: #include 7: 8: class MyTable : public QTableView
9 { 10 11 12 13 14 15 16 17 18 19 20
public MyTable( QWidget ‘ widgmacierz = 0 ); private: void paintCell( QPainter *, int, in t );
}; MyTable::MyTable( QW idget ‘ widgmacierz ) : QTableView( widgm acierz )
{ setNumCols( 5 ); setNumRows( 5 ); setCellWidth( 100 );
21 22 23
setCellHeight( 30 ); setBackgroundMode( PaletteBase );
}
24 25: void MyTable::paintCell( QPainter* p, int wiersz, int kolumna ) 26: { 27:
int x = (cellWidth( kolumna ) - 1);
28: 29
int y = (cellHeight( wiersz ) - 1 ) ;
30
p->drawLine( x, 0, x, y );
31
p->drawLine( 0, y, x, y );
32 33
if( kolumna == 0 )
34
{
35
p->drawText( 0, 0, (x+1), (y+1), AlignCenter, „Nazwisko” );
36
}
37:
if( kolumna == 1 )
38
{
39
p->drawText( 0, 0, (x+1), (y+1), AlignCenter, „Adres” ),
40
}
41:
if( kolumna == 2 )
42:
{
43: 44:
p->drawText( 0, 0, (x+1), (y+1), AlignCenter, „M ie jsco w o ść"); }
45: 46:
if( kolumna == 3 ) {
47: 48:
p->drawText( 0, 0, (x+1), (y+1), AlignCenter, „Płeć” ); }
111
112
Godzina 6
49
if( kolumna == 4 )
50
{
51
p->drawText( 0, 0, (x+1), (y+1), AlignCenter, „ T e l );
52
}
53
}
54 55 class M yM ainW indow : public QW idget 56
{
57 public: MyMainW indow();
58 59 private: 60
MyTable ‘ tabela;
61
Q Header ‘ nagłówek:
62
QLabel ‘ etykieta;
63
};
64 65 M yM ainW indow::M yM ainW indow()
66 { 67
resize( 500, 250 );
68 69
tabela = new MyTable( this );
70
tabela->set(_ ^m etry( 0, 100, 500, 150 );
71 72
nagłówek = new QHeader( this );
73
naglowek->setGeom etry( 0, 70, 500, 30 );
74
naglowek->setOrientation( H o riz o n ta l);
75
naglowek->addl_abel( „Nazwisko", 100 );
76
naglowek->addl_abel( „Adres", 100 );
77
naglowek->addLabel( „Miejscowość", 100 );
78
naglowek->addLabel( „Płeć", 100 );
79
naglowek->addLabel( „Tel.", 100 );
80 81
etykieta = new QLabel( this );
82
etykieta->setG eom etry( 0, 0, 500, 70 );
83
etykieta->setAlignm ent( A lig n C e n te r);
84
etykieta->setText( „Przypuśćmy, źe to jest prawdziwy
85
program, który prezentuje
86 87 } 88
informacje personalne w tabeli. ),
89 void main( int argc, char “ argv ) 90
i
91
QApplication a(argc, argv);
92
M yM ainW indow w;
93
a.setM ainW idget( &w );
Poznajemy widgety Qt: Lekcja pierwsza
94:
w.show();
95:
a.exec();
113
96: }
W przykładzie tym klasa MyMainWindow z listingu 6.7 została przemianowana na MyTable. Po raz pierwszy zetknęliśmy się z sytuacją, kiedy nowo utworzona klasa nie została mia nowana widgetem głównym. Zauważmy, że do konstruktora MyTable dodano parę rzeczy (linie 11 i 16). W linii 11 określa się, że konstruktor będzie otrzymywał obiekt QWidget ja ko argument. Argument ten będzie reprezentować widget macierzysty. Nie trzeba jednak pisać kodu do obsługi tego argumentu. Zamiast tego jest on przekazywany do konstrukto ra QTableView (linia 16). W linii 69, do konstruktora MyTable przekazywany jest jako argument wskaźnik this. W ten sposób nie utworzony jeszcze obiekt MyMainWindow staje się widgetem macierzystym. W liniach 72-79 tworzony jest nagłówek. Ta część kodu mówi sama za siebie. Program pokazano na rys. 6.9. Rys. 6.9 Tabela z poziom ym nagłówkiem.
Podsumowanie W tej godzinie dowiedziałeś się, jak pracować z przyciskami: przyciskami zwykłymi, ra diowymi i przyciskami pola wyboru. Przycisk jest prawdopodobnie tym widgetem, które go będziesz używać w swoich programach najczęściej; dlatego sekcja o przyciskach jest ważna. Gdy się nad tym zastanowić, to łatwo stwierdzić, że program GUI bez przycisków jest niewiele warty. Potem dowiedziałeś się, jak zastosować tekst i etykiety numeryczne. Dowiedziałeś się tak że, że zdecydowanie najczęściej używaną klasą do implementacji etykiet jest QLabel. Poza tym przyjrzałeś się klasie OLCDNumber, którą można wykorzystywać do przedstawiania in formacji numerycznych. Etykiety, podobnie jak przyciski, są podstawowymi elementami wszystkich bibliotek GUI. Na koniec dowiedziałeś się, jak pracować z tabelami. Powinieneś postarać się poszerzyć wiedzę zdobytą w tej godzinie, aby zobaczyć różne sposoby implementowania tabel w Qt. W godzinie tej przedstawiliśmy Ci jedynie podstawy. Pamiętaj, że klasa QTableView wyma ga od Ciebie wykonania mnóstwa samodzielnej pracy. Jak stwierdzono wcześniej, jest to
Godzina 6
dość abstrakcyjna klasa, więc aby zrobić z niej jakiś użytek, potrzeba trochę pracy. Jest to nawet pewna zaleta, gdyż możesz sam zadecydować, co dokładnie powinno być zrobione i jakie cechy należy dodać.
Pytania i odpowiedzi Etykieta, którą dodają do przycisku radiowego (przycisku pola wyboru) je s t niewidoczna lub widoczna tylko częściowo. Co je s t nie tak? Sprawdź, czy jest wystarczająco dużo miejsca dla etykiety. Możliwe, że tekst jest ukry ty pod jakimś innym widgetem. Gdy używam obiektu QLabel do wyświetlenia tekstu, moje pozostałe widgety (lub część z nich) znikają. Dlaczego? Obiekt QLabel jest obiektem prostokątnym (chociaż nie zawsze to widać). Potrzebuje on miejsca dla całego prostokąta, a nie tylko dla tekstu. Dlatego, jeśli masz obiekt QLabel o szerokości 400 pikseli, a tekst, który się w nim znajduje, ma szerokość tylko 50 pikse li, obiekt ten i tak zajmie 400 pikseli. Nie widzę, w ja k i sposób funkcja zaznaczenia po kliknięciu z listingu 6.7 miałaby być uży teczna w tym programie. Czyżbym coś przeoczył? Nie, niczego nie przeoczyłeś! Funk' a tę umieściliśmy tylko po to, by pokazać Ci, jak dodaje się nowe cechy. Aby nadać jej sens, musisz zaimplementować inne funkcje (np. funkcję, która pozwoli użytkownikowi zmieniać zawartość komórki).
Warsztaty Zachęcamy Cię do przerobienia poniższych pytań i ćwiczeń. Pomogą Ci one utrwalić sobie zdobytą w tej godzinie wiedzę.
Quiz 1. Do czego służą poszczególne typy przycisków? 2. Jakiego sygnału trzeba użyć w celu sprawdzenia, czy został kliknięty przycisk QPushButton?
3. Jakiej klasy należy użyć w celu pogrupowania przycisków? 4. Jaka funkcja ustawia wyrównanie tekstu w obiekcie QLabel? 5. Jak zmienić wielkość, czcionkę i styl tekstu w obiekcie QLabel? 6 . Jaką funkcję poza konstruktorem trzeba zaimplementować przy tworzeniu podklasy na bazie QTableView? 7. Dlaczego trzeba zaimplementować tę funkcję? 8. Jakiej klasy należy użyć w celu utworzenia nagłówka tabeli?
Poznajemy widgety Qt: Lekcja pierwsza
115
Ćwiczenia 1. Utwórz program zawierający trzy przyciski zwykłe i trzy przyciski pola wyboru. Niech za pom ocą przycisków zwykłych będzie m ożna sterować stanem pól wyboru. 2. Napisz program z jednym jedynym widgetem - obiektem QLabel. Dodaj do niego tekst. Uważam, że Qt jest dobrą, szybką, profesjonalną i przyjem ną biblioteką GUI (lub jakikolw iek inny). Zmień wyrównanie na dolne, w yśrodkow ane w poziomie. Wielkość tekstu ustaw na 14 punktów oraz zastosuj czcionkę Times i styl kursywy. 3. Utwórz tabelę, którą będzie m ożna wykorzystać do prezentowania informacji o kom puterach. Dodaj kolumny dla typu procesora, szybkości procesora oraz wielkości pam ię ci RAM. Dodaj nagłówki do kolumn, a następnie kilka pozycji do samej tabeli.
G o d z in a
7
Poznajemy widgety Qt: Lekcja druga W tej godzinie kontynuujem y przegląd w idgetów Qt Przyjrzym y się w idgetom służącym do dokonywania w yboru, w idgetom służącym do rozm ieszczania innych w idgetów oraz widgetom um ożliw iającym użytkow nikow i w ybó r wartości liczbowej. W godzinie tej nie przedstaw iam y niczego rew olucyjnego dla prog ram o w ania G U I, lecz omawiamy kilka użytecznych aspektów Qt, które każdy program ista Qt pow inien d ogłęb nie zrozumieć.
Używanie widgetów wyboru Widgety wyboru, takie ja k pola listy i pola kom bi, pozw alają użytkow nikow i dokonyw ać wyboru spośród predefiniow anej listy pozycji. Przykładem widgetu w yboru je s t w idget do
118
Godzina 7
wybierania czcionki w programie Microsoft Word (pole kombi). Do implementacji pól li sty w Qt służy klasa QListBox, zaś do implementacji pól kombi - klasa QComboBox.
Praca z polami listy Widget pola listy QListBox jest generalnie wykorzystywany tam, gdzie trzeba dać użyt kownikowi możliwość wyboru jednej lub większej liczby pozycji z listy. Zazwyczaj jest to pozycja tekstowa, ale może być również mapą pikselową. Przykład znajdziesz na li stingu 7.1. Listing 7.1 Przykład użycia obiektu QListBox 1 #include 2 #include 3 #include 4 5 class MyMainWindow : public QWidget
6 { 7 public: 8
MyMainWindow{);
9 private: QListBox *listbox;
10
11
};
12 13 MyMainWindow: :MyMainWindow() 14
{
15
setGeometry( 100, 100, 170, 100 );
16
listbox = new QListBox( this );
17
listbox->setGeometry( 10, 10, 150, 80 );
18 19
// Wstaw pozycje do listy:
20
listbox->insertltem( „Pozycja 1” )
21
listbox->insertltem( „Pozycja 2" )
22
listbox->insertltem( „Pozycja 3" )
23
listbox->insertltem( „Pozycja 4” )
24
listbox->insertltem( „Pozycja 5" )
25
\\stbox->insertttem( „Pozycja 6” )
26
}
27 28 void main( int argc, char **argv ) 29
{
30
QApplication a(argc, argv);
31
MyMainWindow w;
32
a.setMainWidget{ &w );
Poznajemy widgety Qt: Lekcja druga
33:
w.showQ;
34:
a.exec();
3 5 :}
W linii 10 powyższego programu przydzielana jest pamięć dla widgetu pola listy. W linii 16 pole listy jest tworzone, a w linii 17 ustawiana jest jego geometria. Następnie, za pom o cą funkcji Q ListBox::insertltem () do pola listy wstawiane są pozycje listy (linie 20-25). A r gument podawany tej funkcji reprezentuje, jak m ożna się domyślić, etykietę pozycji pola listy. Na rys. 7.1 pokazano okno program u z listingu 7.1. Rys. 7.1
Okno zawierające obiekt QListBox.
Odnotujmy, że jest także możliwe przekazanie obiektu QPixmap do funkcji insertltem (), co pokazano na rys. 7.2. Rys. 7.2
Obiekt QListBox z kilko ma pozycjam i tekstowymi i jedna pozycją graficzną (mapa pikselowa).
Aktualnie wybraną pozycję w polu listy QListBox można odczytać przy użyciu funkcji Q ListBox::currentltem (). Następnie można przekazać uzyskany w ten sposób num er pozycji do funkcji Q ListBox::text() lub Q ListBox::pixm ap() i otrzymać sam tekst lub m apę pikselową aktualnie wybranej pozycji.
Praca z polami kombi Jeśli nie masz w swoim oknie wystarczająco dużo miejsca dla obiektu Q ListBox, to zamiast niego m ożesz równie dobrze użyć obiektu QComboBox. Obiekt Q Com boBox jest dość podob ny do QListBox w sposobie działania. Przykład podano na listingu 7.2.
Input
Listing 7.2 Przykład użycia obiektu QComboBox
1: #inciude 2: #include 3: #include 4:
120
Godzina 7
5 class MyMainW indow : public QWidget
6 { 7 public:
8
MyMainW indow();
9 private: QComboBox *combobox;
10 11
};
12 13 MyMainWindow: :MyMainWindow() 14
{
15
setGeometry( 100, 100, 150, 50 );
16
combobox = new QComboBox( false, this );
17
combobox->setGeometry( 10, 10, 130, 30 );
18
20
II W staw pozycje do listy: com bobox->insertltem ( „Pozycja 1" ); com bobox->insertltem ( „Pozycja 2" );
21
com bobox->insertltem ( „Pozycja 3" );
22
com bobox->insertltem ( „Pozycja 4” );
23
com bobox->insertltem ( „Pozycja 5" );
24
com bobox->insertltem { „Pozycja 6” );
19
25
}
26 27 void main( int argc, char **argv ) 28
{
29
QApplication a(argc, argv);
30
MyMainW indow w;
31
a.setMainW idget( &w );
32
w.show();
33
a.exec();
34
}
W linii 10 powyższego programu przydzielana jest pamięć dla obiektu QComboBox. W li nii 16 wykonywany jest konstruktor QComboBox. Pierwszy argument podawany konstruk torowi określa, czy pole kombi ma być typu odczyt-zapis, czy tylko odczyt. Jeśli jest usta wiony na wartość false, pole kombi będzie tylko do odczytu. Jeśli jest ustawiony na true, pole kombi będzie polem typu odczyt-zapis (tzn. użytkownik będzie mógł wstawiać ele menty dynamicznie w czasie wykonania). Drugi argument reprezentuje, tak jak zwykle, widget macierzysty. W linii 17 ustawiana jest geometria pola kombi. 1 wreszcie, w liniach 19-24, do pola kombi jest wstawianych sześć pozycji. Odbywa się to dokładnie tak, jak w przypadku pola listy. Okno tego programu pokazano na rys. 7.3. Rys. 7.3
Obiekt QComboBox z w ybra ną pozycją Pozycja 4.
Poznajemy widgety Qt: Lekcja druga
121
Za pom ocą funkcji insert() można wstawiać do obiektów QComboBox m apy pikselowe. Nie można jednak stosować map pikselowych jako pozycji w polach kombi typu odczyt-zapis, ponieważ nie ma możliwości edytowania map pikselowych przez użytkownika.
Praca z aranżerami Jeśli mądrze zorganizujesz widgety w swoim programie, Twój program będzie wyglądał lepiej i będzie łatwiejszy w użyciu. Qt udostępnia kilka klas ułatwiających aranżację widgetów: • • • •
QGroupBox QButtonGroup QSplitter QW idgetStack
Klasy te om ówimy kolejno w tej sekcji.
Do aranżacji widgetów można wykorzystać także klasę QFrame, choć w praktyce lepiej spełnia ona swą rolę jako klasa bazowa do tworzenia widgetów niestandardowych.
Używanie klasy QGroupBox Klasa QGroupBox służy do rysowania ramki wokół widgetów. Umożliwia ona także dodanie jakiegoś opisu na górze ramki. Przykład przedstawiono na listingu 7.3.
Input
L isting 7.3
Przykład użycia klasy QGroupBox
1: #include 2: #include 3: #include 4: #include 5: 6: class M yMainW indow : public QWidget 7 :{ 8: public: 9:
MyMainW indow();
10: private: 11:
QGroupBox ‘ groupbox;
12:
QLabel ‘ etykieta;
Godzina 7
122
13:}; 14: 15: MyMainW indow::MyMainWindow() 16: { 17:
setGeometry( 100, 100, 150, 100 );
18: 19:
groupbox = new QGroupBox( this );
20:
groupbox->setGeometry( 10, 10, 130, 80 );
21:
groupbox->setTitle( „Pole g ru p y ");
22: 23:
etykieta = new QLabel{ this );
24:
etykieta->setGeometry( 30, 35, 90, 40 );
25:
etykieta->setText{ „Tutaj dodaj\n w id g e ty!");
26:
etykieta->setAlignment( AlignHCenter | A lign V C enter);
2 7 :} 28: 29: void main( int argc, char **argv ) 30: { 31:
QApplication a(argc, argv);
32:
MyMainWindow w;
33:
a.setMainW idgetf &w );
34:
w.show();
35:
a.exec();
36: )_________________________________________________________________________________________
W linii 11 powyższego programu przydzielana jest pamięć dla obiektu QGroupBox. Pole grupy jest tworzone i pozycjonowane w liniach 19 i 20. Jedyną nową rzeczą jest tutaj funk cja Q GroupBox::setTitle() (linia 21). Jak można było zgadnąć, funkcja ta ustawia tytuł pola grupy (patrz rys. 7.4). Rys. 7.4
Okno z obiektami QGroupBox i QLabel.
Używanie klasy QButtonGroup Klasa QButtonGroup jest dość podobna do klasy QGroupBox. Ma ona jednak kilka specjal nych funkcji do grupowania przycisków. Najczęściej spotykanym zastosowaniem klasy OButtonGroup jest grupowanie przycisków radiowych. Układ przycisków radiowych zgru powanych w obiekcie OButtonGroup zapewnia, że użytkownik będzie mógł zaznaczyć (klik nąć) tylko jeden przycisk w danej grupie (tzw. układ przycisków wzajemnie wykluczających się). Przykład użycia takiego układu przycisków możesz znaleźć na listingu 6.2 z Godziny 6, „Poznajemy widgety Qt: Lekcja pierwsza” .
Poznajemy widgety Qt: Lekcja druga
123
Choć przyciski radiowe automatycznie stają się wzajemnie wykluczającymi z chwilą wsta wienia ich do obiektu OButtonGroup, to dla pozostałych typów przycisków trzeba ju ż zro bić wywołanie QButtonGroup::setExclusive( true ) w celu uaktywnienia tej cechy. Przykłady pokazujące sposoby użycia tego aranżera znajdziesz w sekcji „Używanie przy cisków” z Godziny 6.
Używanie klasy QSplitter Obiekt rozdzielacza (ang. splitter) pozwala użytkownikowi kontrolować rozmiar widgetów potomnych poprzez przeciąganie granicy między widgetami. Do tego celu Qt udostępnia klasę OSplitter. Przykład użycia tej klasy przedstawiono na listingu 7.4. W programie tym tworzony jest rozdzielacz umożliwiający użytkownikowi zmienianie rozmiaru dwóch przycisków.
Input
L isting 7.4 Przykład użycia klasy QSplitter
1: #include 2: #include 3: #include 4: #include 5: 6: class M yMainW indow : public QWidget
7:{ 8: public: 9:
MyMainWindowQ;
10: private: 11:
Q S p litte r‘ splitter;
12:
QPushButton *b1, *b2;
1 3 :}; 14: 15: MyMainW indow::MyM ainW indow() 16: { 17:
setGeometry( 100, 100, 150, 100 );
18: 19:
splitter = new QSplitter( this );
20:
splitter->setGeometry( 10, 10, 130, 80 );
21: 22:
b1 = new QPushButton( „Przycisk 1", s p litte r);
23:
b2 = new QPushButton( „Przycisk 2”, s p litte r);
2 4 :} 25: 26: void main( int argc, char **argv ) 27: {
124
Godzina 7
28:
Q A p p lic a tio n a (a rg c , a rg v );
29:
M y M a in W in d o w w ;
30:
a .s e tM a in W id g e t( & w );
31:
w .s h o w ();
32:
a .e x e c Q ;
33:}
W linii 19 programu tworzony jest rozdzielacz (splitter), a w linii 20 ustawiana jest jego geometria. Następnie, w liniach 22 i 23 tworzone są dwa przyciski, dla których jako widget macierzysty podaje się obiekt rozdzielacza. Dzięki temu rozdzielacz zostanie wstawio ny między te przyciski. Na rys. 7.5 i 7.6 pokazano ten program w akcji. Rys. 7.5 Program z obiektem QSplitter w swojej pierwotnej postaci.
■ J,
V
- •
„ *i { BsetG eom etry{ 10, 100, 60, 20);
50: 51:
cb2 = new Q PushButton( „Przywołaj P2", this );
52:
cb2->setG eom etry( 80, 100, 60, 20);
53: 54:
connect( cb1, S!G NAL( c lic k e d {)), this, SLOT( p o k a z b 1 {)) );
55:
connect{ cb2, SIG NAL( c lic k e d {)), this, SLOT( pokazb2() ) );
56: 57: 58: void m ain( int argc, char **argv ) 59: { 60:
Q Application a(argc, argv);
61:
M yM ainW indow w;
62:
a.setM ainW idget( &w );
63:
w.show();
64:
a.exec();
65: }
W program ie tym definiowane są dw a bardzo proste gniazda niestandardow e (linie 25-33). W ywołują one funkcję Q W idgetS tack::raiseW idget(), aby wystawić na w idok przycisk b l lub b2 (linie 27 i 32). W liniach 54 i 55 gniazda te są łączone z sygnałem clicke d () przycisków cbl i cb2. Dzięki tem u m ożna kontrolować to, który z przycisków (bl czy b2) ma być w danym m om encie widoczny. Rys. 7.7 i 7.8 pokazują ten program w akcji. (Rysunki te um ieszczono jedy nie w celach ilustracyjnych; tego typu funkcja jest rzadko użyteczna w rzeczywistych program ach.) Rys. 7.7
Tak wygląda program zaraz p o pojawieniu się na ekranie. jg jg w g tjj
Rys. 7.8
A tak po kliknięciu p rzy cisku oznaczonego etykie tą ,,Przywołaj P I ”.
Poznajemy widgety Qt: Lekcja druga
127
Oczywiście, do stosu widgetów można dodać więcej niż dwa widgety. Należy tylko dla każdego z nich użyć funkcji QW idgetStack::addW idget(). Jak widać na listingu 7.5 (linie 45 i 46), funkcji tej trzeba podać dwa argumenty: wskaźnik do widgetu, który ma być dodany do stosu, oraz unikatowy numer ID (liczba całkowita), jaki widget ten ma mieć w tym sto sie. Takiego numeru ID będzie można u ż y ć jako argumentu dla funkcji Q W idgetStack::raiseWidget(), zamiast wskaźnika do widgetu.
Suwaki i pola przewijane W tej sekcji dowiesz się, jak używać klas Qt służących do tworzenia suwaków i pól prze wijanych. Suwak jest to widget, który pozwala użytkownikowi wybierać wartość num e ryczną przez przeciąganie gałki za pomocą myszy. Pole przewijane także służy do wybie rania wartości numerycznej; używa się go jednak w nieco inny sposób (w polu przewija nym wartość jest zmieniana nie przez przeciąganie gałki, a przez klikanie przycisków).
Używanie klasy QSIider W przypadku tworzenia suwaka należy skorzystać z klasy QSIider. Podobnie jak inne klasy Qt, klasa ta jest bardzo prosta w użyciu. Przykład podano na listingu 7.6.
L isting 7.6 Przykład użycia klasy QSlider 1: #include 2: #include 3: #include 4: 5: ciass MyMainW indow : public QWidget
6: { 7: public:
8:
MyMa¡nW¡ndow();
9: prívate: 10:
QS!ider *suwak;
11:}; 12: 13: MyMainW indow::MyMainW indow() 14: i 15:
setGeometry( 100, 100, 150, 50 );
16: 17:
suwak = new QSIider( 0, 100, 10, 50, Horizontat, this );
18:
suwak->setGeometry( 10, 15, 130, 20 );
19:
suwak->setTickmarks( QSIider:;Below );
128
Godzina 7
2 0 :} 21: 22: void main( int arge. char **argv ) 23: { 24:
QApplication a(argc, argv);
25:
MyMainW indow w;
26:
a.setMainW idget( &w );
27.
w.show();
28:
a.exec();
2 9 :}
Jak widać na tym listingu, konstruktor QSIider przyjmuje sporo argumentów (linia 17). Pierwszy argument ustawia minimalną wartość suwaka, a drugi wartość maksymalną. Trzeci argument ustawia liczbę kroków, o ja k ą skoczy suwak, gdy kliknie się na lewo lub na prawo od gałki. Czwarty argument ustawia domyślną wartość suwaka. Piąty argument ustawia orientację suwaka (Horizontal - pozioma - lub Vertical - pionowa), zaś ostatni ar gument jest wskaźnikiem do widgetu macierzystego suwaka (co było nietrudno zgadnąć). W linii 19 wywoływana jest funkcja QSIider::setTickmarks(). Ustawia ona znaczniki suwaka (pionowe kreseczki, które zwykle widać pod suwakiem). Dzięki tym znacznikom użytkow nikowi łatwiej jest zobaczyć, jak ą wartość ma aktualnie suwak. Rys. 7.9 pokazuje, ja k w y gląda ten program. Rys. 7.9 Suwak ze znacznika mi wartości.
Nie da się jednak zrobić większego użytku z suwaka bez metody, która informowałaby, j a ka jest jego bieżąca wartość. Na szczęście Qt udostępnia kilka funkcji ułatwiających to zdanie. Opisy tych funkcji przedstawiono w tabeli 7.1.
Tabela 7.1 Przydatne funkcje składowe klasy QSIider Funkcja
Opis
value()
Zwraca aktualną wartość suwaka
sliderMoved( int )
Jest to sygnał emitowany za każdym razem, gdy suwak ulega przesunię ciu o wielkość wystarczającą do zmiany jego wartości. Parametr zawiera nową wartość.
valucChanged( int )
Sygnał ten jest emitowany po tym, jak użytkownik zakończy przesuwanie gałki suwaka (tzn. gdy wybierze on nową wartość). Parametr zawiera nową wartość.
slider Pressed()
Sygnał ten jest emitowany ilekroć użytkownik klika gałkę suwaka.
Poznajemy widgety Qt: Lekcja druga
Funkcja
129
Opis
sliderRcleascdO
Sygnał ten jest emitowany wtedy, gdy użytkownik puszcza gałkę po tym. jak ją kliknął lub przeciągnął.
selValue( inl )
Ustawia wartość suwaka.
Suwaki można stosować do wielu zadań. Przy odrobinie wyobraźni z pewnością będziesz w stanie zaproponować jakieś interesujące pomysły. Prawdopodobnie widziałeś wiele pro gramów, w których suwaki wykorzystywane były do ustawiania różnych wartości numerycznych. Powinieneś korzystać z suwaków wszędzie tam, gdzie uznasz je za bardziej odpowiednie od pól przewijanych, np. gdy zakres wartości do wyboru jest duży.
Używanie klasy QSpinBox Pole przewijane (spin box) jest to widget, który pozwala użytkownikowi wybrać wartość numeryczną za pomocą myszy lub klawiatury. Zajmuje ono mniej miejsca niż suwak i jest, w niektórych przypadkach, łatwiejsze w użyciu. Przykład prostego pola przewijanego przedstawiono w programie na listingu 7.7. Input
Listing 7.7 Przykład użycia klasy QSpinBox
1: #include 2: ^include 3; #include 4: 5: class MyMainW indow : public QWidget
6:{ 7: public: 8:
MyMainWindowQ;
9: private: 10:
QSpinBox ‘ spinbox;
11:}; 12 : 13: MyMainWindow::MyMainWindowsetGeometry( 50, 10, 50, 30 );
1 9 :}
20 : 21: void main( int argc, char **argv ) 22 : { 23:
QApplication a(argc, argv);
24:
MyMainWindow w;
130
Godzina 7
25 26 27 28
a.setM ainW idget( &w ); w.show(); a.exec();
Na rys. 7.10. pokazano okno powyższego programu. Rys. 7.10 Proste p o le przew ijan e. A k tualnie w ybraną w artością je s t 48.
Konstruktor QSpinBox przyjmuje cztery argumenty (linia 17). Pierwszy i drugi argument ustawiają m inim alną i m aksym alną wartość, jak ą może mieć pole przewijane. Trzeci argu ment jest w artością kroku, określającą, o ile zmieni się wartość pola przewijanego po klik nięciu któregoś z przycisków ze strzałkami. Ostatni argument jest, jak zwykle, widgetem macierzystym. Klasa QSpinBox udostępnia także kilka przydatnych funkcji. Opisy tych funkcji przedsta wiono w tabeli 7.2.
Tabela 7.2 Przydatne funkcje składowe klasy QSpinBox Funkcja
Opis
value()
Zwraca aktualną wartość pola przewijanego.
setValue( int )
Ustawia wartość pola przewijanego.
setSuffix()
Ustawia napis, jaki ma być pokazywany za wartością numeryczną. Może to być np. Dni, Miesięcy, Lat lub coś podobnego.
setPrefix()
Za pomocą tej funkcji można ustawić napis, jaki będzie wyświetlany przed wartością pola przewijanego.
setSpecialValueText()
Za pomocą tej funkcji można określić tekst, który zostanie pokazany zamiast minimalnej wartości pola przewijanego. Na przykład, mógłby to być tekst „Musisz wybrać większą wartość".
setW rapping()
Jeśli klikniesz któryś z przycisków strzałki po tym, jak osiągnięta została najniższa lub najwyższa wartość, to nic się nie wydarzy. Jeśli jednak wy wołasz setWrapping(true), to gdy klikniesz jedną ze strzałek po osiągnię ciu najwyższej (lub najniższej) wartości, licznik wartości przewinięty zostanie do wartości najniższej (lub najwyższej).
stepUp()
Symuluje kliknięcie myszą na przycisku „do góry”.
stepDown{)
Symuluje kliknięcie myszą na przycisku „na dół”.
Poznajemy widgety Qt: Lekcja druga
131
Pola przewijane bardzo przydają się do ustawiania wartości numerycznej, gdy zakres warto ści nie jest zbyt duży. Z drugiej strony, jeśli zakres jest duży (powiedzmy, od 1 do 100), trze ba się będzie bardzo naklikać! W takim przypadku lepszy wybór stanowi suwak. Jednakże, jak już powiedzieliśmy, do ustawiania wartości numerycznych, gdzie zakres liczbowy jest mniejszy (np. przy ustawianiu bieżącej daty), pola przewijane nadają się doskonale!
Podsumowanie W tej godzinie dowiedziałeś się, jak używać widgetów wyboru. Przy pracy z widgetami wyboru musisz się orientować co do metod udostępnianych przez ich klasy. Umieszczenie kilku widgetów wyboru w oknie nie jest trudne; jednak najprawdopodobniej będziesz też chciał, aby te widgety spełniały w Twoim programie jakieś funkcje. Nie będziesz w stanie tego dokonać, jeśli nic będziesz wiedzieć, jaki sygnał jest emitowa ny, gdy zachodzi określone zdarzenie, lub jaką funkcję należy wywołać, aby zmienić dany widget w określony sposób. Zapamiętanie tych wszystkich informacji jest prawie niemoż liwe, ale powinieneś przynajmniej mieć podstawowe zrozumienie tego, jak działają widge ty wyboru - czego, mamy nadzieję, nauczyłeś się w tej godzinie. Pamiętaj też, że gdy po trzebujesz informacji na temat jakiejś metody, możesz je łatwo znaleźć w dokumentacji Qt. W godzinie tej dowiedziałeś się także o aranżerach. Aranżery są to widgety służące do organizowania innych widgetów. Mimo że zaimplementowanie aranżerów w swoim pro gramie wymagać będzie od Ciebie trochę dodatkowej pracy, powinieneś używać ich jak najczęściej. Widgety te, użyte we właściwy sposób, mogą przyczynić się do poprawy wy glądu aplikacji i ułatwienia jej obsługi.
Pytania i odpowiedzi Pracuję nad jednym z widgetów opisanych w tej godzinie. Jest on u mnie niewidoczny lub widoczny tylko częściowo. Dlaczego? Jest to typowy problem wśród początkujących programistów Qt. Rozwiązanie jest równie proste jak sam problem Wszystkie widgety Qt maja formę prostokątną, choć nie zawsze to widać. Dlatego widgety często zajmują więcej miejsca, niżby się to mogło wydawać. Kiedy jeden lub więcej Twoich widgetów nic pojawia się na ekranie lub gdy są widoczne tylko częściowo, problemem jest najprawdopodobniej to, że niektóre wid gety są przykryte innymi (widgetami, które z wyglądu zajmują mniej miejsca niż w rzeczywistości). Przy próbie kompilacji programu z listingu 7.5 otrzymuję od kompilatora mnóstwo kom u nikatów o błędach. Dlaczego? Musisz podzielić ten kod na dwie części: jeden plik .cpp i jeden plik .h (plik nagłówko wy). Musisz także użyć narzędzia Meta Object Compiler. Trzeba to zrobić, ponieważ kod zawiera gniazda niestandardowe. Bardziej szczegółowy opis znajdziesz w Godzinie 4. „Sprawiamy, że coś się dzieje: Gniazda i sygnały” .
132
Godzina 7
K iedy m ógłbym użyć w sw oim program ie fu n k c ji QSpi n B ox:: setSpecia l Va lueText(j? Czy mogę p ro sić o p rzykład? Jeśli implementujesz w swoim now ym procesorze tekstów funkcję, która pozwala użyt kownikowi zmieniać wielkość czcionki, funkcja Q SpinBox::setSpecialValueText() może Ci się bardzo przydać. Jak wiesz, wielkość czcionki nie może być wartością 0. Jest jednak bardzo praw dopodobne, że użytkownik nie będzie się nad tym zastanawiać i spróbuje ustawić wielkość na najm niejszą wartość. Gdybyś w tym m omencie nie użył funkcji setSpecialValueText(), użytkow nik ustawiłby wielkość czcionki na 0, co spow odow ałoby ja kieś bardzo dziwne problemy. Z drugiej strony, jeśli użyjesz funkcji setSpecialValueText() i ustawisz tekst na coś w rodzaju M usi być 1 lufy w ięcej, problem najprawdopodobniej się nie pojawi.
Warsztaty Przerób quiz i ćwiczenia znajdujące się w tej sekcji, aby sprawdzić, czy zrozumiałeś wszystko, o czym m ówiliśm y w tej godzinie.
Quiz 1. 2. 3. 4. 5.
Co to jest widget wyboru? Jakie dwa typy widgetów wyboru tekstowego udostępnia Qt? Do czego służy klasa QSplitter? Do czego m ożna wykorzystać klasę QW idgetStack? Kiedy byłoby użyteczne zastosowanie całkowitoliczbowego ID zam iast wskaźnika do widgetu przy pracy ze stosem widgetów? 6 . Chociaż nie odwoływaliśm y się do nich jaw nie jako widgetów wyboru, poznałeś w tej godzinie dwa widgety wyboru dla wartości numerycznych. Potrafisz je wym ienić? 7. Jaką przewagę m a suw ak nad polem przewijanym?
Ćwiczenia 1. Napisz prosty program zawierający pole listy lub pole kombi. Użyj pętli for do wstawie nia kilku pozycji do pola listy lub pola kombi. 2. Poeksperymentuj z klasą QSplitter. Czy jest możliwe wstawienie innego aranżera do roz dzielacza? Czy m ożesz wstawić widgety posiadające widgety potomne? 3. Napisz program zawierający jeden suwak i jedno pole przewijane. Połącz te dwa widge ty tak, by przy przeciąganiu suwaka wartość pola przewijania stosownie się zmieniała.
G o d z in a
8
Poznajemy widgety Qt: Lekcja trzecia Jest to ostatnia lekcja tej sekcji. W godzinie tej poznasz kilka nowych (ypówr widgetów. Tak jak zwykle, godzina ta w żadnym wypadku nie obejmuje wszystkich aspektów om aw ia nych w niej klas i funkcji. Właśnie dlatego bardzo ważna w procesie nauki Qt jest doku mentacja Qt Reference Documentation (jako materiał referencyjny). W tej godzinie nauczysz się używać trzech nowych widgetów; pól do wprowadzania te kstu, widoków listy oraz pasków postępu. Pola do wprowadzania tekstu są to widgety, które potrafią obsługiwać dane wejściowe typu tekstowego pochodzące od użytkowników. Widok listy jest bardzo interesującym widgetem, który można wykorzystywać do efektyw nej prezentacji danych. Paski postępu są to widgety informujące użytkownika o stanie za dania wykonywanego przez program. Widgety te są uważane za podstawowe, a więc naj prawdopodobniej będziesz ich potrzebować (prędzej czy później) w swoich programach.
Godzina 8
134
Używanie pól do wprowadzania tekstu Pola do wprowadzania tekstu są to widgety, do których można wpisywać tekst. Przykładem pola do wprowadzania tekstu jest biały obszar w edytorze tekstów, w którym można wpi sywać i czytać tekst. Qt udostępnia dwie klasy do tworzenia pól do wprowadzania tekstu: OLineEdit i QMultiLineEdit. Obydwie omawiamy w tej sekcji.
OLineEdit Obiekt OLineEdit tworzy jednoliniowe pole do wprowadzania tekstu. Można (i powinno się) go używać do pobierania od użytkownika krótkich napisów, takich jak nazwa użytkowni ka i hasło. Na listingu 8.1 przedstawiono program używający obiektu OLineEdit.
Listing 8.1 Przykład użycia klasy QLineEdit
Input
1: #include
2: #include 3: #include 4: 5: class MyMainWindow : public QWidget
6: { 7: public: 8:
MyMainWindow();
9: private: 10:
O Line E dit‘ edit;
11:}; 12 : 13: MyMainWindow::MyMainWindow() 14: { 15:
setGeometry( 100, 100, 200, 50 );
16: 17:
edit = new QLineEdit( this );
18:
edit->setGeometry( 10, 10, 180, 30 );
19: }
20 : 21: void main( int argc, char **argv )
22 :
{
23:
QApplication a(argc, argv);
24:
MyMainWindow w;
25:
a.setMainWidget( &w ),
26:
w.show();
Poznajemy widgety Qt: Lekcja trzecia
27 :
135
a.exec();
28 : }
Tak naprawdę, to listing 8.1 nie prezentuje niczego nowego. Widgety są w tym programie tworzone i rozmieszczane tak jak zwykle. Niemniej jednak mamy tu prezentację użycia no wego widgetu OLineEdit. Program ten pokazano na rys. 8.1. Rys. X.1 Prosty program 2 obiektem QLineEdit,
Tekst obiektu OLineEdit można ustawić ręcznie, używając funkcji OLineEdit: :setText(). Jeśli chcesz pobrać tekst aktualnie wpisany w obiekcie OLineEdit, wywołujesz funkcję OLineEdit::text(). Za każdym razem, gdy tekst się zmienia, emitowany jest sygnał QLineEdit::valueChanged.
Typowym zastosowaniem obiektu OLineEdit jest pobieranie hasła od użytkownika. Stąd kla sa OLineEdit udostępnia funkcję sprawiającą, że tekst wpisywany w polu pojawia się w po staci gwiazdek. Jest to typowy sposób ukrywania hasła; prawdopodobnie widziałeś go w wielu innych aplikacjach. Dodając dwie poniższe linie do konstruktora z listingu 8.1 sprawisz, że tekst będzie się pojawiać jako gwiazdki oraz ustawisz maksymalną długość dla wpisywanego tekstu na osiem znaków: edtt->setEchoMode( QLineEdit::Password ); edit->setMaxLength( 8 );
Jeśli teraz wpiszesz tekst do pola, będzie on wyglądać jak na rys. 8.2.
gwiazdki.
Zauważ, że po wprowadzeniu ośmiu znaków nie pojawiają się już dalsze gwiazdki. Ozna cza to, że nie można wprowadzić więcej znaków. Pracując z obiektami klasy OLineEdit powinieneś także wiedzieć o sygnałach returnPressed() i textC hanged( ). Sygnał returnPressed() jest emitowany, gdy naciskany jest klawisz Return lub Enter. Sygnał textChanged() jest emitowany za każdym razem, gdy zmienia się tekst obiektu. textChanged() zawiera również nowy tekst.
OMultiLineEdit jest drugim polem do wprowadzania danych, jakie ma do zaoferowania Qt. Używaliśmy go już w tej książce w jednym z wcześniejszych przykładów. Jak zapewne pa
OMultiLineEdit
136
Godzina 8
miętasz, OMultiLineEdit stanowi prostokątny, wielowierszowy obszar, w którym m ożna albo wyświetlić tekst, albo pozwolić go wpisać użytkownikowi. Z obiektem O M ultiLineEdit postępuje się prawie tak samo, ja k z OLineEdit, choć OMultiLineEdit zawiera kilka dodatkowych funkcji do edycji tekstu z poziomu kodu programu. Za pom o cą funkcji insertA t() m ożna wstawić tekst na określonej pozycji w obiekcie OMultiLineEdit. OMultiLineEdit bierze trzy argumenty: Pierwszy jest napisem, jaki chcemy wstawić, drugi to numer linii, w której tekst ma być wstawiony, a trzeci to numer znaku, za którym tekst ma się pojawić. Zatem poniższy kod wstawiłby napis Hej! w linii 12, za znakiem 37: obiekt->insertAt( „Hej!". 12, 37 );
Tekst można wstawiać także przy użyciu funkcji Q M ultiLineEdit::insertLine(). Jest to prostsza funkcja, przyjmująca jeden lub dwa argumenty. Oto przykład: obiekt->insertLine( „Hej!". 5 );
Powyższa linia wstawiłaby napis Hej! w linii 5. Jeśli drugi argument tej funkcji zostanie pominięty, to tekst będzie dodany w nowej linii, poniżej ostatniej zapisanej linii. Za pom ocą funkcji O M ultiLineEdit.:rem oveLine() można usunąć linię tekstu. Funkcji tej nale ży podać jako argument numer linii.
Z a ró w n o O L in e E d it, jak i O M u ltiL in e E d it m o g ą p ra c o w a ć z s y s te m o w y m sc h o w k ie m . O d byw a się to za p o śre d n ic tw e m fu nkcji cu t(), co py() i paste().
Po więcej informacji, jak zwykle zajrzyj do dokumentacji Qt Reference Documentation. W tym przypadku okaże się ona dla Ciebie bardzo pomocna, ponieważ klasa OMultiLineEdit zawiera wiele użytecznych funkcji. Są wśród nich takie funkcje jak: setR eadO nly() - do ustawiania obiektu O M ultiLineEdit tylko do odczytu (przydatna w sytuacji, gdy obiekt w yko rzystywany jest tylko do wyświetlania tekstu); text() do pobierania bieżącego tekstu z obiektu OM ultiLineEdit; oraz clear() do czyszczenia tekstu w obiekcie.
Używanie widoków listy Widok listy jest jednym z moich ulubionych widgetów. Jest to widget potrafiący prezen tować dane w bardzo atrakcyjny i łatwy do śledzenia sposób. Mimo że widok listy jest dość skomplikowanym widgetem, to jednak dzięki Qt zadanie zaimplementowania go we własnym programie jest łatwe. Klasą reprezentującą w Qt widok listy jest QListView. Prosty przykład, pokazujący, w jaki sposób można użyć obiektu QListView, przedstawiono na listingu 8 .2 .
Poznajemy widgety Qt: Lekcja trzecia
Listing 8.2
137
Przykład użycia klasy QListView
1: #include 2: #include 3: #include 4: 5: class MyMainW indow : public QWidget
6: { 7: public: 8:
MyMainWindowQ;
9: private: 10:
QListView ’ widoklisty;
11:
QListViewltem ‘ kategoria 1;
12:
QListViewltem *kategoria2;
13:
QListViewltem *kategoria3;
14:
QListViewltem *pozycja;
15: }; 16: 17: MyMainW indow::MyMainWindow() 18: { 19:
setGeometry( 100, 100, 300, 300 );
20 : 21: 22: 23:
widoklisty->setGeometry( 0, 0, 400, 400 );
24:
// Uwidocznij strzałkę w dół:
25:
widoklisty->setRootlsDecorated( true );
26: 27:
II Dodaj trzy kolumny: widoklisty->addColumn( „Książka” );
28:
widoklisty->addColumn( „Sprzedane egzemplarze" );
29:
widoklisty->addColumn( „C e n a ");
// Utwórz widok listy: widoklisty = new QListView( this );
30: 31: 32: 33: 34:
II Dodaj trzy pozycje: kategoria 1 = new QListViewltem( widoklisty, „Kategoria 1" ); kategoria2 = new QListViewltem( widoklisty, „Kategoria 2” ); kategoria3 = new QListViewltem( widoklisty, „Kategoria 3 ");
35: 36:
// Do każdej pozycji dodaj trzy podpozycje:
37:
pozycja = new QListViewltem( kategorial, „Książka 1", „21 000”, „29,99 zł” );
38:
pozycja = new QListViewltem( kategorial, „Książka 2", „19 000", „24,99 zł” );
39:
pozycja = new QListViewltem( kategorial, „Książka 3", „14 000”, „39,99 zł" );
40: 41:
pozycja = new QListViewltem( kategoria2, „Książka 4 ”, „38 000", „34,99 zł” );
42:
pozycja = new QListViewltem( kategoria2, „Książka 5”, „16 000”, „19,99 zł” );
43:
pozycja = new QListViewltem( kategoria2, „Książka 6”, „9000", „29,99 zł" );
138
Godzina 8
44 45
pozycja = new
QUstViewltem( kategoria3, „Książka 7”, „32 000", „39,99 zł" );
46
pozycja = new
QListViewltem{ kategoria3, „Książka 8", „25 000", „37,99 zł" );
47
pozycja = new QListViewltem( kategoria3, „Książka 9” , „13 000”, „44,99 zł" );
48
}
49 50 void main( int argc, char **argv ) 51
{
52
QApplication a(argc, argv);
53
MyMainWindow w;
54
a.setMainWidget( &w );
55
w.show();
56 57
a.exec();
}
Proces dodawania pozycji jest dość podobny do procesu tworzenia menu. Najpierw, w li niach 22-29, tworzony jest sam widok listy. Wywołanie QListView::setRootlsDecorated( TRUE ) w linii 25 ma na celu zapewnienie widoczności strzałki na lewo od pozycji naj wyższego poziomu, tak aby użytkownik mógł zobaczyć podpozycje. Następnie, w liniach 27, 28 i 29, przy użyciu funkcji QListView::addColumn() tworzone są trzy kolumny. Argu ment podawany tej funkcji reprezentuje nazwę kolumny. W liniach 32, 33 i 34 tworzone są trzy pozycje najwyższego poziomu. Wykorzystywana jest do tego klasa QListViewltem. Konstruktor QListViewltem bierze trzy argumenty; pierwszy jest obiektem QListView, do którego pozycje te mają być wstawione. Drugi argument reprezentuje nazwę pozycji. W li niach 37^47 do każdej z pozycji najwyższego poziomu dodawane są trzy podpozycje. Tu taj do konstruktora QListViewltem dodawane są jeszcze dwa argumenty. Te dwa argumenty reprezentują drugą i trzecią kolumnę podpozycji. Wynik działania tego programu pokaza no na rys. 8.3.
Rys. 8.3 Widok listy’ przedstaw iający kilka książek posortow anych według kategorii.
Z w ró ćm y uw agę, że nie je s t p otrzebne w yw ołan ie funkcji in se rtlte m () ani innych podob nych fu nkcji. W ysta rczy o prze ć się na hierarchii w id g e t m a cie rzysty-w id g e t potomny.
Poznajemy widgety Qt: Lekcja trzecia
139
Jeśli klikniesz nagłówek którejś z kolumn, widok listy zostanie posortowany według tej kolumny.
Klasa QListView udostępnia wiele innych funkcji, nie wykorzystanych w ostatnim przykła dzie. Niektóre z nich zostały opisane w tabeli 8.1. Aby móc w pełni opanować i wykorzysty wać klasę QListView, musisz wiedzieć, w jaki sposób użyu'ać tych funkcji. Prawdopodobnie nie będziesz potrzebować wszystkich z nich w każdym projekcie, niemniej jednak dobrze jest być świadomym ich istnienia, aby wiedzieć, jakie możliwości są do dyspozycji.
Tabela 8.1 Użyteczne funkcje składowe klasy QListView Funkcja
Opis
setColumnsW idthMode()
Metoda ta określa, w ja k i sposób ma być ustawiana szerokość kolumny. Należy je j podać dwa argumenty: Pierwszy jest wartością całkow itą re prezentującą kolumnę, o którą chodzi, a drugi to wartość typu enuin, którą można ustawić na M axim um lub Manual Jeśli ustawioną w arto ścią jest M axim um , kolumna otrzym uje szerokość najszerszej pozycji w tej kolumnie. Jeśli ustawioną warlościąjest Manual, szerokość kolum ny ustawia się poprzez funkcję setColumnWidth().
setMultiSelection()
Określa, czy użytkow nik może zaznaczyć jedną, czy kilka pozycji naraz. Funkcji tej należy podać ja ko argument wartość typu bool ( TRUE ozna cza zaznaczenie wielokrotne, a FALSE zaznaczenie pojedyncze).
setAIIColumnsShowFocusO Funkcja ta może przyjąć argument TRUE lub FALSE. Jeśli funkcja ta jest ustawiona na TRUE, we wszystkich kolumnach będzie pokazywany fokus. Przetestuj ją, a zobaczysz! setTreeStepSize()
Wartość całkowita podawana tej funkcji określa, o ile pikseli jest przesu nięta pozycja względem swojego widgetu macierzystego. N ic rozu miesz? W ypróbuj i zobacz!
setSortingO
Funkcja la określa, ja k ma wyglądać sortowanie. Przyjm uje ona dwa ar gumenty: wartość całkow itą reprezentującą kolumnę, o którą chodzi, oraz wartość typu bool (TRUE lub FALSE). Jeśli funkcja ta jest ustawio na na TRUE, sortowanie będzie rosnące. Jeśli jest ustawiona na FALSE. sortowanie będzie malejące.
itemAtO
Funkcja ta bierze jako argument wskaźnik do obiektu OPoint. Zwraca zaś wskaźnik do obiektu QListViewltem znajdującego się na tej pozycji.
firstChild()
Zwraca pierwszą pozycję w w idoku listy.
itemBelow()
Zwraca pozycją znajdującą się bezpośrednio pod tą pozycją.
itemAbove()
Zwraca pozycję znajdującą się bezpośrednio nad tą pozycją.
setSelected()
Funkcja ta określa, czy pozycja jest zaznaczona. Wymaga dwóch argu-
Godzina 8
140
Opis
Funkcja
m entów: Pierwszy to wskaźnik do obiektu QListViewitem, a drugi pow i nien być wartością typu bool (TRUE lub FALSE). TRUE powoduje za znaczenie pozycji. setCurrentltem()
Ustawia fokus kla w iatu ry na pozycją wskazywaną przez argument (wskaźnik).
currentltem()
Zwraca wskaźnik do aktualnie zaznaczonej pozycji.
selectionChanged()
Funkcja ta jest sygnałem em itowanym , gdy zmienia się zaznaczenie (tj. gdy zaznaczana jest inna pozycja lub odznaczana bieżąca). W ysyła ona także wskaźnik do nowo zaznaczonej pozycji.
currentChanged()
Ten sygnał jest emitowany, gdy zmienia się bieżąca pozycja. Wysyła on rów nież wskaźnik do nowej pozycji.
doubleClicked()
Sygnał ten jest em itowany, gdy użytkow nik dw ukrotnie klika jakąś pozycją. Przesyłany jest także wskaźnik do dw ukrotnie klikniętego obiektu QListViewltem.
returnPressedO
Ten sygnał jest emitowany, gdy użytkow nik naciska klaw isz Enter lub Return. W ysyłany jest także wskaźnik do pozycji posiadającej fokus klawiatury.
rightButtonClickedO
Sygnał ten jest emitowany, gdy zostaje zw olniony praw y przycisk myszy (po tym , ja k został naciśnięty). Sygnał ten wysyła także trzy argumenty do swoich gniazd: wskaźnik do kliknięte j pozycji (może być U), współrzędne klikniętej pozycji oraz wartość typu integer reprezentującą kolumnę, której dotyczy to zdarzenie.
Po przestudiowaniu tej tabeli prawdopodobnie zastanawiasz się. jaka jest różnica mię dzy pozycją bieżącą, a pozycją zaznaczoną. Pozycją bieżącą może być w danym mo mencie tylko jedna pojedyncza pozycja; jest to ta pozycja w otoczce (zwanej też fokusem). Jeśli jednak włączyłeś wielokrotne zaznaczanie za pomocą wywołania setMultiSelection(TRUE), możesz mieć zaznaczonych wiele pozycji jednocześnie, W takim przypadku masz jedną pozycję bieżącą i wiele pozycji zaznaczonych. Pozycja bieżąca jest jedną z zaznaczonych pozycji, a jedna wybrana konkretnie pozycja może być po zycją bieżącą, ale może być też tylko pozycją zaznaczoną
A teraz przyjrzymy się przykładowi, który nieco bardziej rozwija program z listingu 8.2. Przypuśćmy, że chcesz zaimplementować nową funkcję, która wyświetla opis książki po dwukrotnym kliknięciu jej pozycji w widoku listy. W tym celu powinieneś utworzyć nowe gniazdo i połączyć je z sygnałem doubleClicked(). Na listingu 8.3 zaprezentowano prostą implementację tej funkcji. W tym przykładzie implementowane jest gniazdo MyMainWindow::PokazOpis(). Gniazdo to po prostu przywołuje okno informacyjne za każdym razem, gdy dwukrotnie klikana jest jakaś pozycja. Okno informacyjne jest tworzone przez klasę QMessageBox, omawianą w Godzinie 10, „Okna dialogowe Qt” .
Poznajemy widgety Qt: Lekcja trzecia
141
L isting 8.3 Widok listy z funkcją informacyjną 1: flinclude 2: #include 3: #include 4: #include 5: 6: // Pamiętaj o utworzeniu osobnego pliku .h 7: // z deklaracją klasy, a następnie 8: // użyciu na nim MOC-a. 9: class M yMainW indow : public QWidget 10 : { 11: Q OBJECT 12: public: 13:
MyMainWindowQ;
14: private: 15:
Q ListV iew 'w idoklisty;
16:
QListViewltem 'k a te g o ria l;
17:
QListViewltem *kategoria2;
18:
QListViewltem *kategoria3;
19:
QListViewltem 'pozycja;
20:
QMessageBox 'okienko;
21: public slots: 22:
void PokazOpisQ;
23: }; 24: 25: // Oto nasze nowe gniazdo: 26: void MyMainW indow::PokazOpis() 27: { 28:
okienko = new QMessageBox( „Informacje o książce", „Tutaj można by wyświe-
tlić jakiś 29:
krótki tekst z informacją na temat książki, którą właśnie
30
dwukrotnie kliknięto.", QMessageBox::lnformation, QMessageBox::Ok, 0, 0 );
31
okienko->show();
32 33
}
34 35 MyMainW indow::MyM ainW indow() 36 37
{ setGeometry( 100, 100, 300, 300 );
38 39
widoklisty = new QListView( this );
40
widoklisty->setGeom etry( 0, 0, 400, 400 );
41
widoklisty->setRootlsDecorated( true );
42
142
Godzina 8
43
widoklisty->addColumn( „Książka” );
44
widoklisty->addColumn( „Sprzedane egzem plarze");
45
widoklisty->addColumn( „Cena" );
46 47
kategorial = new QUstViewltem( widoklisty, „Kategoria 1" )
48
kategoria2 = new QListViewltem( widoklisty, „Kategoria 2" )
49
kategoria3 = new QListViewltem( widoklisty, „Kategoria 3" )
50 pozycja = re w QUstViewltem( kategorial, „Książka 1", „21 000", „29,99 zł" )
51 52
pozycja = new QListViewltem( kategorial, „Książka 2". „19 000", „24,99 zł” )
53
pozycja = new QListViewltem( kategorial, „Książka 3", „14 000", „39,99 zł" )
54
pozycja = new QListViewltem( kategoria2, „Książka 4", „38 000", „34,99 zł" )
55
pozycja = new QListViewltem{ kategoria2, „Książka 5", „16 000", „19,99 zł" )
56
pozycja = new QListViewltem( kategoria2, „Książka 6", „9000", „29,99 zł” );
57
pozycja = new QListViewltem( kategoria3, „Książka 7”, „32 000” , „39,99 zł” )
58
pozycja = new QUstViewltem( kategoria3, „Książka 8”, „25 000” , „37,99 zł” )
59
pozycja = new QListViewltem( kategoria3, „Książka 9”, „13 000”, „44,99 zł" )
60 connect( widoklisty, SIGNAL( doubleClicked{ QUstViewltem * )),
61 62 63
this, SLOT( PokazOpis{) ) );
}
64 65 void main( int argc, char **argv )
66 { 67
QApplication a(argc, argv);
68
MyMainWindow w;
69
a.setMainWidget( &w );
70
w.show();
71
a.exec();
72
}
W linii 22 deklarowane jest gniazdo PokazOpis(). Jego implementacja znajduje się w li niach 26-33, Jak widzisz, klasa QMessageBox jest wykorzystywana (w liniach 28-31) do utworzenia małego okienka informacyjnego, wyskakującego po dwukrotnym kliknięciu ja kiejś pozycji. Jest to jedna z klas dialogowych Qt (będziemy j ą omawiać w Godzinie 10). Rys. 8.4 pokazuje ten program w akcji. Sekcja ta powinna Ci dać pewne pojęcie o tym, jak możesz wykorzystywać widoki listy we własnych programach.
Praca z paskami postępu Pasek postępu jest to widget, który dostarcza użytkownikowi informacji o aktualnym stanie programu. Wyświetlenie paska postępu jest użyteczne np. w sytuacji, gdy Twój program
Poznajemy widgety Ql: Lekcja trzecia
143
ma właśnie wykonywać czasochłonne zadanie i chciałbyś poinformować użytkownika, ile czasu przypuszczalnie będzie to trwać (i zapewnić użytkownika, że program wciąż działa). Do tworzenia pasków postępu służy w Qt klasa QProgressBar. (Do zadań, takich jak to, m oż na również wykorzystywać klasę OProgressDialog. Klasę tę omawiamy w Godzinie 10.) Obiekt OProgressBar tworzy się i wyświetla tak samo, ja k obiekty każdej innej klasy Qt. Jest jednak kilka innych zadań, które trzeba wykonać, by sprawić, że pasek postępu rzeczywi ście będzie zachowywać się jak pasek postępu (np. trzeba określić, kiedy pasek postępu bę dzie aktualizowany). Na listingu 8.4. znajduje się prosty przykład. Rys. 8.4 Pozycja oznaczona ja k o "Książka 4 ’’ została kliknięta w celu w yśw ie tlenia okna inform acyjnego. Kliknij przycisk O K w tym oknie, aby usu nąć j e z ekranu.
Input
L isting 8.4 Suwak sterujący paskiem postępu
1: #include 2: #include 3: #include 4: #include 5: 6: class MyMainW indow : public QWidget 7 :{ 8: public: 9:
MyMainWindowQ;
10: private: 11:
QProgressBar *pasek;
12:
QSIider *suwak;
13: }; 14: 15: MyMainW indow::MyMainW indow() 16: { 17:
setGeometry( 100, 100, 200, 90 );
18: 19:
pasek = new QProgressBar( 100, this );
20:
pasek->setGeometry( 10, 10, 180, 30 );
21: 22:
suwak = new QSIider{ 0, 100, 10, 0, Horizontal,
23:
suwak->setGeometry( 10, 50, 180, 30 );
24: 25:
// Połącz pasek postępu z suwakiem tak,
Poznajemy widgety Ql: Lekcja trzecia
143
ma właśnie wykonywać czasochłonne zadanie i chciałbyś poinformować użytkownika, ile czasu przypuszczalnie będzie to trwać (i zapewnić użytkownika, że program wciąż działa). Do tworzenia pasków postępu służy w Qt klasa QProgressBar. (Do zadań, takich jak to, m oż na również wykorzystywać klasę OProgressDialog. Klasę tę omawiamy w Godzinie 10.) Obiekt OProgressBar tworzy się i wyświetla tak samo, ja k obiekty każdej innej klasy Qt. Jest jednak kilka innych zadań, które trzeba wykonać, by sprawić, że pasek postępu rzeczywi ście będzie zachowywać się jak pasek postępu (np. trzeba określić, kiedy pasek postępu bę dzie aktualizowany). Na listingu 8.4. znajduje się prosty przykład. Rys. 8.4 Pozycja oznaczona ja k o "Książka 4 ’’ została kliknięta w celu w yśw ie tlenia okna inform acyjnego. Kliknij przycisk O K w tym oknie, aby usu nąć j e z ekranu.
Input
L isting 8.4 Suwak sterujący paskiem postępu
1: #include 2: #include 3: #include 4: #include 5: 6: class MyMainW indow : public QWidget 7 :{ 8: public: 9:
MyMainWindowQ;
10: private: 11:
QProgressBar *pasek;
12:
QSIider *suwak;
13: }; 14: 15: MyMainW indow::MyMainW indow() 16: { 17:
setGeometry( 100, 100, 200, 90 );
18: 19:
pasek = new QProgressBar( 100, this );
20:
pasek->setGeometry( 10, 10, 180, 30 );
21: 22:
suwak = new QSIider{ 0, 100, 10, 0, Horizontal,
23:
suwak->setGeometry( 10, 50, 180, 30 );
24: 25:
// Połącz pasek postępu z suwakiem tak,
Poznajemy widgety Qt: Lekcja trzecia
145
Paski postępu są prostymi, ale bardzo użytecznymi widgetami. Jeśli zamierzasz wykony wać w swoim programie bardzo czasochłonne zadanie, to jest prawie wymagane, abyś do łączył doń pasek postępu w celu poinformowania użytkownika o tym, co się dzieje i jak długo to potrwa.
Podsumowanie Zarówno pola do wprowadzania tekstu, jak i paski postępu, to zupełnie nieskomplikowane widgety i jasne jest, do czego można ich używać. Z drugiej strony m am y widoki listy, z którymi rzecz nie wygląda ju ż tak prosto. Klasa QListView jest równie bogata w m ożliwo ści co złożona. Aby w pełni opanować to bogactwo możliwości, musisz tę klasę dogłębnie przestudiować. Dzięki temu odkryjesz zupełnie nowe sposoby używania widoków listy. QListView jest klasą pasjonującą (jeśli uważasz, że klasy C++ m ogą być pasjonujące). N a wet jeśli początkowo wyda Ci się, że ciężko będzie ją zrozumieć, to chociaż spróbuj! Niniejszym zakończyłeś poznawanie widgetów Qt. Nauczyłeś się używać wszystkich widgetów Qt. Studiowanie tej sekcji pozwoliło Ci także zrozumieć to, jak działają widgety i do czego można je zastosować. Widgety Qt stanowią kompletny zestaw obiektów graficz nych, wystarczający do skonstruowania dowolnego typu GUL
Pytania i odpowiedzi D laczego w program ie z listingu 8.3 trzeba wywoływać m etodę show () dla obiektu QMessageBox? Nie robi się tego w przypadku żadnych innych obiektów. Jest tak dlatego, że obiekt QMessageBox (okienko) nie jest widgetem potomnym klasy MyMainWindow. Stąd wywołanie M yM ainW indow::show() w main() nie ma wpływu na okienko. P rzy p ró b ie kom pilacji program u z listingu 8.3 otrzym uję od kom pilatora m nóstw o kom u nikatów o błędach. Co je s t nie tak? Musisz podzielić ten kod na dwie części: jeden plik cpp i jeden plik h (plik nagłów ko wy). Musisz także użyć narzędzia Meta Object Compiler. Trzeba to zrobić, ponieważ kod zawiera gniazda niestandardowe. Bardziej szczegółowy opis znajdziesz w Godzinie 4, „Sprawiamy, że coś się dzieje: Gniazda i sygnały”.
Warsztaty Tak jak zwykle, zachęcamy Cię do przerobienia poniższych pytań i ąuizu. W ten sposób sprawdzisz, czy zrozumiałeś wszystko, o czym mówiliśmy w tej godzinie. Co więcej, m o żesz zrozumieć coś, co wcześniej wydawało Ci się niejasne.
146
Godzina 8
Quiz Jaka je s t różnica między QLineEdit a Q MultiLineEdit? 2. Jakiej klasy należy użyć w celu pokazania użytkownikowi zawartości pliku tekstowego? 3. Jaka jest najistotniejsza różnica między Q LineEdit a QM ultiLineEdit, jeśli patrzeć tylko na funkcje składowe? 4. Jaka jest alternatywna m etoda dla wstawiania pozycji do widoku listy za pom ocą funkcji 1.
insertltem O?
5. Jaki sygnał jest em itowany po dwukrotnym kliknięciu pozycji w widoku listy? 6 . Jaki sygnał jest em itowany po naciśnięciu klawisza Return lub Enter w widoku listy? 7. Co to jest pasek postępu? 8 . Kiedy powinieneś zaimplementować pasek postępu w swojej aplikacji?
Ćwiczenia 1. Poszukaj w dokumentacji Qt funkcji składowej klasy QM ultiLineEdit, która potrafi uczynić obiekt Q M ultiLineEdit obiektem tylko do odczytu. Jak się nazywa ta funkcja i jak byś j ą wywołał, aby ustawić obiekt QMultiLineEdit w tryb tylko do odczytu? 2. Napisz program z widokiem listy. Widok listy powinien zawierać trzy wiersze - Kraj, Stolica i Ludność - od lewej do prawej. Następnie utwórz pozycję najwyższego pozio mu dla każdego kontynentu i dodaj podpozycje opisujące kilka krajów z każdego kon tynentu wraz z informacjami o stolicach i zaludnieniu. 3. Możliwe, że będziesz chciał użyć paska postępu, ale napotkasz pewne trudności przy je go implementacji. Może nie jest dla Ciebie jasne, kiedy należy wyw oływ ać funkcję setProgress(). Jedno z rozwiązań (które niekoniecznie musi być najlepsze) polega na zmierzeniu, jak długo będzie wykonywane zadanie, a następnie utworzeniu pętli for (lub czegoś podobnego) i przetwarzaniu w odstępach czasu (pomiędzy aktualizacjami paska postępu), jakie uznasz za stosowne dla tego zadania. Dla przykładu przypuśćmy, że Twój program będzie wykonyw ać zadanie, trwające około 30 sekund; spróbuj opracować pętlę for, która wywołuje funkcję setProgress() w odpowiednich momentach.
G
o d z in a
9
Tworzenie prostej grafiki Kiedy urucham iasz swój now y i w ypolerow any program GUI po raz pierwszy, m ożesz nie zdaw ać sobie spraw y z tego, że program ten w rzeczywistości składa się z dużej ilości niskopoziom ow ego kodu graficznego. Na szczęście kod ten jest generow any przez bibliote kę G U I (w tym przypadku Qt); dlatego nigdy nie m usisz się tym przejm ow ać. Być m oże zastanaw iasz się, co to je st niskopoziom ow y ko d graficzny. Jest to kod, który ry suje Twój program na ekranie. Kiedy tworzysz widget Qt, widget ten jest rysow any na ekranie przez Q t za p o m o cą najprostszych funkcji Twojego system u (funkcji rysujących j e dynie linie, prostokąty, itp.). Jak ju ż powiedzieliśm y, Qt zarządza niskopoziom ow ym kodem, który tw orzy predefinio w ane w idgety Qt. C zasam i jednak m ożesz zechcieć utworzyć niestandardow e obiekty gra ficzne, których Qt nie będzie m ogła za Ciebie utworzyć. W takim przypadku będziesz p o trzebow ać jakiegoś niskopoziom ow ego generatora grafiki, którego będziesz m ógł w yko rzystać do tw orzenia niestandardowej grafiki. Do tego celu Qt udostępnia klasę O Painter. W tej godzinie dow iesz się, jak rozpocząć pracę z klasą O Painter. D ow iesz się także, ja k z a im plem entow ać w sw oim program ie funkcje drukowania.
Godzina 9
148
Używanie klasy QPainter Jak stwierdzono wcześniej, klasa OPainterslnży do tworzenia niestandardowej grafiki w Qt. Jest ona bardzo prosta i nietrudna w użyciu. Rozpoczniemy tę sekcję poświęconą klasie OPainter od poznania sposobu tworzenia obiektu OPainter i rysowania prostego prostokąta.
Rozpoczęcie pracy z klasą OPainter Przy tworzeniu grafiki niestandardowej za pomocą klasy OPainter trzeba przedsięwziąć pewne środki ostrożności, aby nie przeszkodzić w rysowaniu samej bibliotece Qt. To co na leży zrobić, to umieścić kod rysujący w specjalnej funkcji o nazwie drawEvent(), jak rów nież rozpocząć i zakończyć rysowanie poprzez wywołanie funkcji O Painter::begin() i OPainter::end(). Na listingu 9.1 przedstawiono prosty przykład.
Listing 9.1 Rysowanie prostego prostokąta 1: #include 2: #include 3: #include 4: 5: class MyMainWindow : public QWidget
6: { 7: public:
8:
MyMainWindow{);
9: private: 10:
void paintEvent( QPaintEvent* );
11:
QPainter ‘ paint;
12: }; 13: 14: II Tutaj jest nasza implementacja funkcji paintEventQ: 15: void MyMainWindow::paintEvent( QPaintEvent* ) 16: { 17:
paint = new OPainter;
18:
// Rozpocznij rysowanie:
19:
paint->begin( this ); II Rysuj prostokąt: paint->drawRect( 20, 20, 160, 160 ); II Zakończ rysowanie: paint->end();
20: 21: 22: 23: 2 4 :}
25: 26: MyMainWindow:.MyMainWindow()
Tworzenie prostej graIIki
149
27: { 28:
setG eom etry( 100, 100, 200, 200 );
29: } 30: 31: void main( int arge, char **argv ) 32: { 33:
Q Application a(argc, argv);
34:
M yM ainW indow w;
35:
a.setM ainW idget{ &w );
36:
w.showQ;
37:
a.exec();
38: }
Najpierw, w linii ] 7. tw orzony jest obiekt QPainter. Następnie, w linii 19, w yw ołaniem QPain te r::b e g in ( ) zapoczątkow yw ane jest rysowanie. W linii 21 rysow any jest prostokąt. Jest to robione za pom ocą funkcji Q P ainter::draw R ect(). Funkcja ta bierze cztery argumenty. Pierw sze dwa określają pozycję lewego górnego rogu prostokąta (w zględem okna), a ostatnie dw a określają szerokość i wysokość prostokąta. Na koniec, rysow anie jest zakańczane w li nii 23 w yw ołaniem Q Painter::end(). Program ten utworzy okno o rozm iarach 200 x 200 pi kseli, z czarnym , niew ypełnionym prostokątem o rozm iarach 160 x 160 w jeg o wnętrzu (patrz rys. 9.1).
Rys. 9.1 Okno z narysowanym prostokątem.
Jak widzisz, rezultatem kodu z listingu 9.1 jest prosty, czarny prostokąt. To nie był żaden wy szukany przykład, ale zapoznał Cię on z klasą OPainter, bo taki był przecież cel tej sekcji.
Ustawianie stylu rysowania Zanim zaczniesz faktyczny proces rysowania, m usisz wybrać sposób, w jaki O P ainter ma rysować linie, prostokąty, itd. Dokonasz tego za pośrednictw em funkcji składow ych klasy OPainter.
150
Godzina 9
Wybór pióra Wywołując funkcję Q P a in te r ::s e tP e n () z odpowiednimi argumentami, możesz wybrać styl pióra, jaki chcesz zastosować. Wypróbujesz to teraz, zmieniając program z listingu 9.1 tak, by używał niebieskiego pióra o szerokości 4 pikseli, rysującego linie przerywane. Po pro stu dodaj poniższą linię kodu pomiędzy wywołaniami b e g in ( ) (linia 1 9 listingu 9.1) i e n d () (linia 23 listingu 9.1): paint->setPen( QPen( blue, 4, QPen::Dashl_ine ) );
Rezultat pokazano na rys. 9.1. Rys. 9.2 Zmiana typu pióra za pom ocą funkcji QPa intcr: :setPen().
Jak widzisz, styl rysowania można zmienić dość znacznie za pomocą jednej jedynej linii kodu.
Wybór stylu wypełniania Możesz postanowić wypełnić swój prostokąt jakimś wzorcem lub jednolitym kolorem. Ro bi się to za pomocą „pędzla” (ang. brush). Na przykład, jeśli chcesz wypełnić prostokąt z li stingu 9.1 jednolitym, czerwonym kolorem, to dodaj poniższą linię kodu pomiędzy wywo łaniami begin() (linia 19 listingu 9 . 1) i end() (linia 23 listingu 9 . 1 ): paint->setBrush( QBrush( red, SolidPattern ) );
Rezultat wywołania tej funkcji pokazano na rys. 9.3. Rys. 9.3 Ustawienie stylu w ypeł niania na jedn olity , czerwony kolor.
Zmieniając jednak wzorzec SolidPatern, możesz wypełniać prostokąt innymi sposobami. Na przykład, jeśli zamienisz go na Dense6Pattern, styl wypełniania zmieni się ze 1 0 0 % (Solid Pattern) na 12% (Dense6Pattern). Na rys. 9.4 pokazano przykład takiego wypełnienia.
Tworzenie prostej grafiki
151
Rys. 9.4 Zmiana stvlu wypełniania ze 100% na 12%.
i
< J • :•
t
i s1 m V , m m\ . '
: V # * MW:«*ir*m j y '* * \ & 't
Pełny opis różnych stylów wypełniania przedstawiono w Tabeli 9.1.
Tabela 9.1 Style wypełniania S tyl w ypełn ian iu
O pis
SolidPattern
W zorzec w ypełniania jednolitego (patrz rys. 9.3) .
D ensel Pattern
Wzorzec w ypełniania 94%.
Dense2Pattern
W zorzec w ypełniania 84%.
Dense3Pattern
W zorzec w ypełniania 63%.
Dense4Pattern
Wzorzec w ypełniania 50%.
DenseSPattern
W zorzec w ypełniania 37%.
Dense6Pattern
W zorzec w ypełniania 12%) (patrz rys. 9.4).
Dense7Pattern
W zorzec w ypełniania 6%.
HorPattern
W ypełnia figurę poziom ym i lin ia m i.
VerPattern
W ypełnia figurę pionow ym i liniam i.
CrossPattern
W ypełnia figurę przecinającym i się lin ia m i (wzorzec siatka).
BDiagPattern
Styl w ypełniania lin ia m i diagonalnym i zorientow anym i na praw y górny róg.
FDiagPattern
Linie diagonalne zorientowane na lewy górny róg.
DiagCrossPattern
Przecinające się lin ie diagonalne.
CustomPattern
Ten styl pow inno się stosować w przypadku użycia wzorca mapy pikselow ej
Zmiana czcionki Klasa Q Painter umożliwia również rysowanie tekstu. Przy rysowaniu tekstu może się oka zać, że trzeba zmienić czcionkę. Jest to bardzo proste - wystarczy tylko wywołać funkcję setFontf). Listing 9.2 przedstawia prosty program, pracujący z tekstem.
152
Godzina 9
Listing 9.2 Rysowanie tekstu czcionką niestandardową 1: #include 2: #include 3: #include 4: ^include 5: 6: class MyMainWindow : public QWidget
7: { 8: public: 9:
MyMainWindowQ;
10: private: 11: 12:
void paintEvent( QPaintEvent* ); QPainter ‘ paint;
13: }: 14:
15: void MyMainWindow::paintEvent( QPaintEvent* ) 16: { 17:
paint = new QPainter;
18
paint->begin( this );
19
// Ustaw wielkość czcionki i styl:
20 21 22
paint->setFont( QFont( "A rial”, 16, QFont::Bold ) ); // Rysuj tekst: paint->drawText( 20. 20. 260. 60. AlignCenter.
23 24
„Czcionka. Arial. Wielkość: 16. Styl: Pogrubienie" ); paint->end();
2 5 :} 26: 27: MyMainWindow::MyMainWindow() 28: { 29:
setGeometry( 100. 100, 300, 100 );
3 0 :} 31: 32: void main( int argc, char **argv ) 33: { 34:
QApplication a(argc, argv);
35:
MyMainWindow w;
36:
a.setMainW idgeti &w );
37:
w.show();
38:
a.exec();
39: }
W powyższym programie, w liniach 15-25 widzimy definicję funkcji paintEvent(). Defini cja ta rozpoczyna się od utworzenia obiektu QPainter (linia 17). Następnie, w linii 18, roz poczyna się rysowanie. W linii 19 ustawiane są czcionka i styl (poprzez wywołanie funk-
Tworzenie prostej gratlki
153
cji QPainter;:setFont()). W liniach 22 i 23 rysowany jest tekst - przy użyciu funkcji OPainter::drawText(). Funkcji tej podaje sit; sześć argumentów. Pierwsze dwa określają lewy gór ny róg prostokąta, na którym będzie rysowany tekst. Następne dwa argumenty reprezentu ją szerokość i wysokość prostokąta. Za pomocą piątego argumentu ustawia się wyrówna nie tekstu. Ostatni argument reprezentuje (oczywiście) tekst, który ma być narysowany. Program ten tworzy okno. a następnie rysuje w jego środku następujący tekst: Czcionka: Arial, Wielkość: 16. Styl: Pogrubienie
Rys. 9.5 pokazuje ten program w akcji. Rys. 9.5 Tekst uatysow any przy użyciu klasy OPainter.
To sam o m ożna by bez trudu uzyskać za p om ocą etykiety. Lekcja ta je d n a k dotyczy grafiki i w zw iązku z tym m usisz poznać także funkcje do rysow ania tekstu u d o stę p n ia ne przez klasę OPainter.
Przy pracy z kla są O P ainter m asz do w yboru takie sam e m ożliw ości w yró w nyw a nia te kstu, jak przy pracy z O Label.
Poznawanie funkcji rysujących klasy OPainter Klasa OPainter udostępnia dużo więcej funkcji do rysowania tekstu i prostokątów. W tej sekcji omawiamy parę innych, interesujących funkcji rysujących (choć nie wszystkie). Kompletne zestawienie funkcji składowych klasy OPainter można znaleźć w sekcji OPain ter dokumentacji Qt Reference Documentation,
Pam iętaj, że przykłady kodu z poniższych sekcji zaw sze trzeba w sta w ić m ię dzy w y w o łania begin() i end() w funkcji paintEvent().
Rysowanie okręgów i elips Do rysowania okręgów i elips służy w klasie OPainter funkcja drawEllipse(). Przyjmuje ona cztery argumenty całkowitoliczbowe. Pierwszy i drugi argument reprezentują liczbę pikse-
154
Godzina 9
li pomiędzy okręgiem/elipsą a, odpowiedno, lewym i górnym bokiem okna. Argumenty trzeci i czwarty reprezentują szerokość i wysokość okręgu/elipsy. Spójrzmy na poniższy przykład: paint->setPen( QPen( blue, 4, QPen::Solidl_ine )); paint->drawEilipse( 20, 20, 210, 160 );
Rezultat tego kodu pokazano na rys. 9.6. Rys. 9.6 Elipsa natysow ana ciągłą, niebieską linią.
Rysowanie zaokrąglonego prostokąta Aby narysować prostokąt z zaokrąglonymi rogami, należy użyć funkcji QPainter::drawRoundRect(). Jako przykład weźmy poniższy fragment kodu (patrz też rys. 9.7): paint->setPen( QPen( red, 4, QPen::SolidLine ) ); paint->drawRoundRect( 20, 20, 210, 160, 50, 50 );
Dwa ostatnie argumenty określają poziom zaokrąglenia rogów prostokąta. Może to być do wolna wartość z zakresu od 0 do 99 (99 reprezentuje maksymalne zaokrąglenie). Rys. 9.7 P rostokąt: zaokrąglony mi rogami.
Rysowanie wycinka koła Aby narysować jedynie wycinek koła, należy skorzystać z funkcji QPainter::drawPie(). Oto przykład: paint->setPen( QPen( green, 4, QPen::Solidl_ine ));
Tworzenie prostej grafiki
155
paint->draw Pie( 20, 20, 210, 160, 0, 500 );
Pierwsze cztery argum enty definiują koło (okrąg), tak sam o jak w przypadku funkcji drawEllipse(). Ostatnie dwa argum enty definiują styl okręgu. 0 jest kątem w yjściow ym (faktycz ną je d n o s tk ą je st 1/16 stopnia), a 500 (jednostka także wynosi 1/16 stopnia) jest długością łuku wycinka. M oże być Ci trudno to zrozum ieć, jeśli nie znasz trygonom etrii. W takim przypadku pow inieneś przetestow ać kilka różnych wartości. W krótce zrozum iesz, ja k to działa. Program ten pokazano na rys. 9.8. Rys. 9.8 Zielony wycinek koła.
Żaden z dwóch ostatnich argumentów nie reprezentuje całego stopnia, tylko jego szes nastą część. Zatem, w tym przypadku, cały okrąg (koło) jest reprezentowany przez 5760 (16x360).
Rysowanie odcinka koła Aby otrzym ać odcinek koła, należy w ew nątrz niego narysować prostą linię. Linia ta to cię ciwa. O dcinek koła jest to ten kaw ałek koła, który znajduje się na zew n ą trz cięciwy. Taką figurę narysuje w łaśnie O Painter, jeśli użyjesz funkcji Q P ainter::draw C hord(): paint->setPen( Q Pen( green, 4, Q Pen::SolidLine ) ) ; paint->draw C hord( 20, 20, 210, 160, 500, 1000 );
A rgum enty dla funkcji draw C h o rd () są dokładnie takie same, ja k dla funkcji dra w P ie (). Rys. 9.9 przedstaw ia rezultat tego kodu. Rys. 9.9 Zielony odcinek koła.
156
Godzina 9
Rysowanie łuku Rysowanie łuku za pomocą klasy QPainter jest łatwe - wystarczy użyć funkcji QPainter::drawArc(). Argumenty dla tej funkcji są takie same, jak dla funkcji drawPie() i drawChord(). Przy kład jest następujący: paint->setPen( QPen( green, 4, QPen::SolidLine ) ); paint->drawArc( 20, 20, 210, 160, 500, 1000 );
Rezultat tego kodu pokazano na rys. 9.10. Rys. 9.10 Zielony Ink okręgu.
Rysowanie krzywej Beżiera W celu narysowania krzywej Beżiera (krzywej opisywanej czterema punktami) należy użyć funkcji QPainter::drawQuadBezier(). Oto prosty przykład: paint->setPen{ QPen{ green, 4, Q Pen::SolidLine )); paint->drawQuadBezier( QPointArray( QRect(20, 20, 210, 1 6 0 )) );
Jedyny argument podawany tej funkcji reprezentuje prostokąt, w którym ma być naryso wana krzywa (pozostałe argumenty są predefiniowane i można je opuścić). Na rys. 9.11 przedstawiono przykład krzywej Beżiera. Rys. 9.11 Z ie lo n a k r z y w a B e ż ie ra .
Znasz już więc kilka funkcji rysujących z klasy OPainter. Klasa ta zawiera jednak jeszcze kilka innych takich funkcji, jak np. QPainter::drawPixm ap() (do rysowania map pikselowych) czy Q Painter::draw Polygon() (do rysowania wielokątów). Informacje o tych funkcjach zna jdziesz w dokumentacji.
Tworzenie prostej grafiki
157
Praca z kolorami Aby móc konstruować dobrze wyglądające aplikacje, musisz wiedzieć, jak zarządzać ko lorami. które zostaną w nich użyte. Ze względu na to, że istnieje wiele różnych typów sprzętu, zarządzanie kolorami może być trudne. Biblioteka Qt potrafi jednak nieco ułatwić Ci to zadanie.
Zarządzanie kolorami Przy dobieraniu kolorów dla swoich aplikacji musisz pamiętać o tym. że prawdopodobnie znajdzie się wielu użytkowników tych aplikacji, którzy nie będą mogli używać więcej niż 256 kolorów naraz (8-bitowa głębia koloru). Dlatego też powinieneś starać się nie przydzielać /byt wielu niestandardowych kolorów, jak również starać się używać kolorów już przydzielonych przez inne aplikacje. W ten sposób zostawiasz więcej wolnych komórek koloru (każdy kolor zajmuje jedną komórkę koloru). Oczywiście, nie możesz w żaden sposób dowiedzieć się, które kolory są już w' użyciu, a które nie. Powinieneś jednak wyrobić sobie nawyk używania predefiniowanych kolorów Ot - black, wbite, red, green, blue, cyan, yellow. magenta, gray, darkGray, ltghGray, darkRcd, darkGreen, darkBlue, darkCyan, darkMagcnta, darkYellow, colorO i colorl. Kolory te najprawdopodobniej są już w użyciu.
colorO i c o lo rl są sp ecjaln ym i koloram i do rysow ania w d w u koio ro w ych m apach b itow ych; gw a ra n tuje się, że b ę d ą one ze s o b ą d ob rze ko ntrastow a ć.
Inny sposób na uniknięcie zajęcia zbyt wielu kolorów polega na użyciu wzorca kolorów (ustalonego zestawu kolorów). Wzorzec kolorów można ustawić za pomocą funkcji QApplication::setColorSpec( ). Poniżej objaśniono kilka standardowych argumentów, jakie można przekazać do tej funkcji: Jest to argument domyślny. Należy go stosować w przypadku, gdy aplikacja korzysta głównie z kolorów standardowych. • QApplication::ManyColors. Tego argumentu należy użyć, gdy aplikacja korzystać będzie z dużej liczby kolorów. Zostanie użyta specjalna metoda (ułatwiająca współużytkowanie kolorów pomiędzy różnymi aplikacjami) w celu ustalenia, które kolory faktycznie zosta ną przydzielone. Opcja ta dotyczy tylko systemów UNIX-owych. • QApplication::CustomColors. Dotyczy tylko systemów opartych na Microsoft Windows. Jest to funkcja, która przydziela więcej kolorów dla aplikacji aktywnej, a mniej dla aplikacji pracujących w tle. Jeśli kiedykolwiek korzystałeś z Windows ustawionego na 256 kolorów, to prawdopodobnie widziałeś, jak zazwyczaj dziwne kolory otrzymują aplikac je, kiedy są nieaktywne. Jest to spowodowane właśnie przez tą metodę. • QApplication::Normal.
Godzina 9
158
Zanim utworzysz obiekt QApplication musisz wywołać funkcję QApplication: :setColorSpecQ!
Specyfikowanie kolorów Są trzy sposoby specyfikow ania kolorów w Qt: przy użyciu m odelu (Red/Green/Blue), modelu I1SV (Hue/Saturation/Value) lub nazwanych kolorów.
RGB
Model RGB RGB jest najczęściej stosowaną metodą specyfikowania kolorów i najprawdopodobniej słyszałeś już o niej wcześniej. W modelu RGB kolory specyfikuje się za pomocą trzech całkowitych wartości - po jednej dla każdego z kolorów czerwony, zielony i niebieski (ang. red, green. blue). Im wyższa wartość jednego z tych trzech kolorów, tym większa domina cja tego koloru w rezultacie. Wartość dla każdej ze składowych koloru musi być liczbą cał kowitą z zakresu od 0 do 255. Na przykład, (0, 0, 0) reprezentuje kolor czarny, a (255, 255, 255) reprezentuje kolor biały. W celu przydzielenia w Qt koloni z wykorzystaniem modelu RGB należy utworzyć obiekt OColor i przekazać trzy wartości RGB, jako argumenty, do jego konstruktora. Oto przykład: QColor mojCzarnyf 0, 0, 0);
Powyższa linia przypisuje obiektowi QColor kolor czarny. Jeśli chciałbyś mieć czystej barwy czerwony, użyłbyś poniższej: OColor mojCzerwony( 255, 0, 0);
Model HSV Model HSV (od ang. Hue Saturation Value - barwa, nasycenie, wartość) jest kolejnym spo sobem definiowania kolorów. W modelu HSV kolor jest rozbijany na jego barwę, nasyce nie i wartość. Zakresy możliwych do wyspecyfikowania wartości nieco się różnią. W Qt wygląda to tak, że barwa może być dowolną liczbą całkowitą spomiędzy -] a 360, zaś na sycenie i wartość m ogą być dowolnymi liczbami z zakresu od 0 do 255. Klasa QColor dopuszcza także użycie modelu HSV. W tym celu wystarczy dodać do kon struktora obiektu argument QColor::Hsv. Oto przykład: QColor kolorHSV( 150, 73. 213, QColor::Hsv );
Użycie nazwanych kolorów Wszystkie systemy oparte na X 11 (UNIX) posiadają bazę danych odwzorowującą nazwy kolorow na wartości RGB. Dzięki użyciu takich nazwanych kolorów szansa wybrania
Tworzenie prostej grafiki
159
koloru będącego już w użyciu jest dużo większa i prawdopodobnie będzie można również zaoszczędzić trochę komórek koloru. Nazwane kolory można również stosować wr przy padku obiektów QColor. Oto przykład: QColor INiebieski{ "SteelBlue" );
Qt udostępnia taką bazę również na systemach windowsowych.
Zmiana standardowej palety Jeśli nie podoba Ci się standardowa paleta kolorów, możesz zdefiniować niestandardową. Paleta składa się z trzech grup kolorów: active (aktywne; używane, gdy aplikacja posiada fokus), disabled (wyłączone; używane, gdy aplikacja jest niedostępna dla użytkownika) oraz normal (normalne; używane do wszystkich innych celów'). Każda grupa kolorów skła da się z pewnej liczby kolorów, których należy używać do określonych części aplikacji. Tak więc, jeśli chcesz utworzyć własną paletę kolorów, musisz utworzyć trzy grupy kolorów. Zrobisz to za pomocą klasy QColorGroup - kolory przekażesz jako argumenty do konstrukto ra. (Po opis tych argumentów zajrzyj do dokumentacji.) Następnie musisz utworzyć obiekt QPalette i przekazać utworzone wcześniej trzy grupy kolorów do konstruktora QPalette (jako argumenty). Także i na ten temat więcej informacji musisz poszukać w dokumentacji.
Drukowanie grafiki za pomocą Qt Drukowanie grafiki w Qt jest łatwym zadaniem. Do drukowania służy klasa QPrinter, a po nieważ jest to podklasa QPaintDevice (podobnie jak OWidget), więc można rysować za po mocą OPainter „po” obiektach OPrinter. Wszystko, co zostanie narysowane, będzie następ nie wydrukowane! Jedyną rzeczą, którą trzeba tak naprawdę kontrolować, jest rozpoczy nanie nowej strony. Robi się to poprzez wywołanie funkcji QPrinter::newPage(). Można też pozwolić użytkownikowi na samodzielną zmianę ustawień drukowania. W tym celu należy wywołać funkcję QPrinter::getPrinter(). Pojawi się wówczas okno dialogowa Print. Pokazano je na rys. 9.12.
W przypadku systemu Windows wygląd okna dialogowego Print (Drukuj) będzie zale żeć od typu posiadanej przez Ciebie drukarki.
Funkcja GPrinter::setup() zwróci wartość true, jeśli naciśnięty zostanie przycisk OK. Tak więc, gdy funkcja ta zwróci true, rozpocznie się drukowanie. Jeśli funkcja nie zwróci true, proces drukowania zostanie przerwany. A oto jak można to zrealizować w programie:
Godzina 9
160
icSHuecs
R vs. 9.12
wmm
Okno dialogowe Print.
j.rinfrr . ta c * )V C ir n fr r tft!
•rJCJ'C C .rm S Ć tS d
Aa a - m
* ję i!
i-i'.
QPrinter drukowanie; int kontynuuj = drukowanie.setup(); if( kontynuuj == true )
{ II Rozpocznij drukowanie // (tj. Rozpocznij rysowanie po // obiekcie QPrinter)
else { II Przerwij
} Jest to aż tak proste! Oczywiście, różne opcje drukowania można ustawiać też program o wo. Za pomocą funkcji Q Printer::setOrientation() można ustawić orientację (przekazując ar gument QPrinter::Portrait lub QPrinter::Landscape). Można też ustawić maksymalną i minimal ną liczbę stron do wydrukowania - za pomocą funkcji QPnnter::setMinM ax().
Podsumowanie Biblioteka Qt zawiera całe mnóstwo funkcji do rysowania, a w tej lekcji nie omówiliśmy ich wszystkich. Pozostałe zostaną omówione w lekcji 15. „Więcej o grafice”. W ostatniej sekcji tej lekcji dowiedziałeś się, jak zaimplementować w swoim programie funkcję do drukowania grafiki. Jednak, pomimo tego że Qt oferuje kilka znakomitych funkcji do drukowania, powinieneś pamiętać o tym, że jest to zadanie w bardzo dużym stopniu zależne od platformy systemowej. Dlatego musisz się upewnić, czy masz w swoim systemie zainstalowane odpowiednie sterowniki; inaczej drukowanie nie powiedzie się.
Tworzenie prostej grafiki
161
Pytania i odpowiedzi Kiedy dodaję jakąś grafikę do konstruktora mojej klasy, grafika ta po prostu nie pojaw ia się na ekranie. Dlaczego? Jak już wcześniej powiedziano, musisz umieścić kod rysujący w specjalnej funkcji o na zwie paintEvent(). Zapobiegnie to kolizji twojego kodu z wewnętrznym kodem rysującym biblioteki Qt. Możesz jednak umieszczać kod rysujący także w jakichś innych funkcjach, tylko nie w konstruktorze. Przy rysowaniu tekstu za pom ocą klasy QPainter, otrzymuję komunikat o błędzie, mówiący o brakującej czcionce. Co je s t nie tak ? Właściwie to odkryłeś już, co jest nie tak. Po prostu nie masz czcionki, którą wybrałeś, lub błędnie napisałeś jej nazwę. Dlaczego nic się nie dzieje, gdy próbuję drukować grafikę? Upewnij się, czy masz poprawnie zainstalowaną drukarkę. To najczęściej spotykana przyczyna. Sprawdź, czy Twój kod graficzny, wyprowadzający dane na drukarkę, nie za wiera błędów. Poza tym upewnij się, czy wywołałeś funkcję begin() z obiektem QPrinter jako argumentem.
Warsztaty Zachęcamy Cię do przerobienia poniższych pytań i ćwiczeń. Pomogą Ci one utrwalić so bie zdobytą w tej godzinie wiedzę oraz pozwolą upewnić się. czy dobrze rozumiesz, w ja ki sposób pracuje się z grafiką w Qt.
Quiz 1. 2. 3. 4.
Jaka klasa służy do tworzenia grafiki? Co robi funkcja setPenf)? Do czego służy pędzel (brush)? Czy istnieje więcej niż jeden styl wypełniania? 5. Dlaczego w celu pokazania te kstu należy użyć klasy QPainter? 6 . Co to jest RGB? 7. Co to jest paleta? 8. Co zrobiłbyś, aby wydrukować okrąg na kartce papieru?
r
Ćwiczenia /. U tw ór/ program rysujący okrąg (nie elipsę). Kontur powinien być koloru czerwonego, przeiywany i o grubości 5 pikseli. Wypełnij ten okrąg jednolitym kolorem niebieskim .*
162
Godzina 9
2. Przypuśćmy, że m asz urodziny. Twoja m am a upiekła dla Ciebie naprawdę ładny placek i wycinasz sobie z niego duży kawałek. Narysuj wycinek tego placka. 3. Napisz program z funkcją drukującą. Utwórz przycisk z etykietą „D rukuj” . Po kliknię ciu tego przycisku pow inno się pojawiać okno dialogowe Print (Drukuj). W ówczas, po kliknięciu OK, program ma drukować wycinek utworzony w poprzednim ćwiczeniu. Pod wycinkiem dodaj też tekst „Ten wycinek pochodzi z naprawdę ładnego placka!” .
~V*?3
G
o d z in a
10
Okna dialogowe Qt Jeśli chcesz w chodzić w jakiś sposób w interakcje z użytkow nikam i sw oich program ów np. chcesz, aby wybierali oni pliki do otwarcia w edytorze tekstów - to aby im to um ożli wić, m usisz zaim plem entow ać okno dialogow e. Biblioteka Q t zaw iera kilka predefiniow anych okien dialogow ych dla najczęściej w yko ny wanych zadań, takich ja k wybieranie plików. W wielu przypadkach predefiniow ane okna dialogowe w ykonają takie zadania za Ciebie i użycie ich pozwoli Ci zaoszczędzić sobie mnóstwo pracy. Tak naprawdę, w większości przypadków, do im plem entacji któregoś z predefiniow anych okien dialogow ych w ystarczy je d n a linia kodu. Oczywiście, jeśli potrzebujesz bardzo nietypow ego okna dialogow ego, będziesz musiał utworzyć je sobie sam. Jednak zaopatrzony w narzędzia do tw orzenia okien dialogowych, jakie udostępnia Qt, nie pow inieneś mieć z tym w iększych problemów. W tej lekcji dow iesz się zarów no tego, ja k korzystać z predefiniow anych okien dialogo wych, jak i tego, ja k tw orzyć swoje własne.
164
Godzina 10
Używanie predefiniowanych okien dialogowych Qt dostarczana jest wraz z kilkoma predefiniowanymi oknami dialogowymi. Są to QColorDialog, OFileDialog, OFontDialog, QMessageBox i QProgressDialog. Klasy te można wykorzy stywać do tworzenia większości typowych okien dialogowych, jak np. okien do wybiera nia plików, czcionek czy kolorów, ale także okien do zadawania użytkownikom pytań ty pu tak/nie oraz informowania ich o tym, co się aktualnie dzieje w aplikacji. Ostatnia klasa dialogowa, OProgressDialog, może być wykorzystywana do tworzenia okien dialogowych postępu, informujących użytkowników o aktualnym stanie aplikacji. Wszystkie te okna dialogowe należą do najczęściej spotykanych i dlatego zostały predefiniowane w bibliote ce Qt. W sekcji tej omawiamy te okna po kolei.
Używanie okna dialogowego Color (Kolor) Klasa QColorDialog udostępnia okno dialogowe do wybierania kolorów. W celu wyświetle nia tego okna dialogowego na ekranie należy wywołać jedyną funkcję składową klasy, getCo!or(). Funkcja ta zwraca wybrany kolor (a właściwie obiekt OColor, reprezentujący ten kolor). Na listingu 10.1 znajduje się przykład.
Listing 10.1 Okno dialogowe Color 1: #include 2: #include 3: #include 4: #include 5: 6: class MyMainWindow : public QWidget 7 :{ 8: public: 9:
MyMainWindow{);
10: private: 11:
OColorDialog *cdialog;
12:
QColor mojKolor;
13:}; 14: 15: MyMainWindow::MyMainWindow() 16: { 17: 18: 19: 20:
setGeometry( 100, 100, 200, 50 );
II Wybierz kolor i przechowaj go II w mojKolor do późniejszego użytku
Okna dialogowe Qt
21
22 :
165
mojKolor = cdialog->getColor( QColor( 0, 0, 0 )); }
23: 24; void main{ int argc, char **argv ) 25: { 26
QApplication a(argc, argv); MyMainWindow w;
27 28
a.setMainWidget( &w );
29
w.show();
30 31
a.exec():
W powyższym programie, wartość zwracana z funkcji QColorDialog::getColor() jest przecho wywana w mojKolor. Dzięki temu można w prosty sposób użyć tego koloru do czegoś uży tecznego. Na przykład, w programie do rysowania można by ustawić ten kolor jako kolor pióra. Argument podawany funkcji getColor() jest kolorem wybranym domyślnie. Na ry sunku 10.1 pokazano okno dialogowe do wybierania kolorów. Rys. 10.1 Okno dialogow e do w ybiera nia kolorów udostępniane przez Qt.
Wciąż jednak pozostaje jedna rzecz do zrobienia. Wynika to z tego, że jeśli użytkownik kliknie w oknie dialogowym przycisk Cancel (Anuluj), funkcja getColor() zwróci nieprawi dłowy kolor i zmienna mojKolor nie będzie tak naprawdę reprezentować żadnego koloru. Można jednak łatwo sprawdzić, czy coś takiego ma miejsce. Pokazano to w poniższym przykładzie: if( mojKolor.isVahd() == TRUE )
{ // mojKolor jest w porządku i
II gotowy do użycia.
} if( mojKolor.isValid() == FALSE )
{
166
Godzina 10
II mojKolor jest nieprawidłowy i // dlatego musimy przerwać.
} Jak widzisz, do sprawdzania prawidłowości wartości mojKolor wykorzystywana jest funk cja QColor::isValid(). Pierwsza instrukcja if sprawdza, czy wybrany kolor jest prawidłowy. Jeśli to prawda, program może kontynuować zadanie, używając w jakiś sposób tego kolo ru. Druga instrukcja if (mogłaby być ona zwyczajnie instrukcją else, ale dla przejrzystości użyto if) sprawdza, czy wybrany kolor jest nieprawidłowy. Jeśli tak jest, program musi przerwać operację. Jest to prosty sposób na uniknięcie problemów. Gdyby wybrany został nieprawidłowy kolor, program nie byłby w stanie go użyć, a w najgorszym przypadku m o głoby dojść do awarii programowej.
Używanie okna dialogowego File (Plik) Klasa OFileDialog udostępnia przyjemne okienko dialogowe do wybierania plików. Podob nie jak QCo!orDialog, okno to jest bardzo łatwe w użyciu i daje się zaimplementować przy użyciu jednej linii kodu. Przykład znajdziesz na listingu 10.2.
Listing 10.2 Okno dialogowe File 1. #include 2: #include 3: #include 4: #include 5: 6: class MyMainW indow : public QWidget 7 :{ 8: public: 9:
MyMainWindow();
10: private: 11:
OFileDialog ‘ fdialog;
12:
QString plik;
13 :}; 14: 15: MyMainW indow::MyMainW indow{) 16: { 17:
setGeometry( 100, 100, 200, 50 );
18:
// Wybierz plik i przechowaj go
19:
// w zm. plik do późniejszego użytku:
20:
plik = fdialog->getOpenFileName(
2 1 :} 22:
„
Okna dialogowe Qt
167
23: void main( int argc, char **argv ) 24: { 25:
QApplication a(argc, argv);
26:
MyMainWindow w;
27: 28:
a.setMainWidget( &w ); w.show{);
29:
a.exec();
30: }
W linii 1 1 powyższego programu przydzielana jest pamięć dla obiektu QFileDialog. Następ nie, w linii 20, wywoływane jest okno dialogowe (w tym momencie okno zostanie wyświe tlone na ekranie). Nazwa pliku wybrana w oknie dialogowym (wraz z jej pełną ścieżką wy szukiwania) jest umieszczana w obiekcie plik z klasy OString (utworzonym w linii 12). Po za tym, funkcji QFileDialog::getOpenFileName() podaje się dwa argumenty (linia 20). Pierw szy argument reprezentuje katalog wyjściowy w systemie plików (użytkownicy Windows powinni zmienić go na coś w rodzaju c:\), a drugi jest filtrem, który zostanie użyty. W tym przypadku ujrzysz tylko pliki, których nazwy kończą się na ,txt (pliki tekstowe). Na rys. 10.2 pokazano okno dialogowe z tego programu. Rys. 10.2 Okno dialogowe do w ybiera nia plików, udostępniane p rze: Qt.
I tw
j tai
__j i '.'ÆIMC.B i
_i tom. »¡rot
_j Wifl-Tbizul i nipt
tftip ut»
Także i tu użytkownik ma możliwość anulowania wyboru plików, poprzez klinięcie przy cisku Canccl (tak samo, jak w przypadku okna dialogowego do wybierania kolorów). Dla tego potrzebny będzie kod obsługujący tego typu sytuację: if( file.isNullO == FALSE )
{ // Znaleziono nazwę pliku i
II możemy kontynuować.
} if( file.isNullO == TRUE )
{ II Nazwą pliku jest NULL // i musimy przerwać.
} W powyższym fragmencie, do sprawdzania, czy wybrano plik, wykorzystuje się funkcję Q String::isNull().
168
Godzina 10
Klasa OFileDialog zawiera jeszcze dwie inne, interesujące funkcje. Funkcja QFileDialog::getExistingDirectory() pozwala użytkownikowi wybrać katalog, a funkcja QFileDialog::getOpenFileNames() pozwala użytkownikowi wybrać wiele plików. Po więcej informacji na temat tych funkcji zajrzyj do dokumentacji Qt Reference Documentation.
Używanie okna dialogowego Font (Czcionka) Klasa OFontDialog służy w Qt do implementowania okien dialogowych do wybierania czcionki. Funkcja Q FontDialog::getFont() odpowiada za pojawienie się okna dialogowego na ekranie. Funkcja ta zwraca potem obiekt QFont reprezentujący nowo wybraną czcionkę. Przykład podano na listingu 10.3.
Listing 10.3 Okno dialogowe Font 1: #include 2: #include 3: #include 4: #include
5: 6: class M yMainW indow : public QW idget 7 :{ 8: public:
9:
MyMainW indow();
10: private:
11:
Q FontDialog *fdialog;
12:
QFont mojaCzcionka;
13:}; 14: 15: MyMainW indow::MyM ainW indow() 16: {
17:
setGeometry( 100, 100, 200, 50 );
18: 19:
// ok będzie TRUE, jeśli użytkownik
20: 21: 22:
II wybrał czcionkę:
23: 24:
II W ybierz czcionkę i przechowaj ją // w zm. m ojaCzcionka do późniejszego użytku:
25:
mojaCzcionka = fdialog->getFont( &ok );
bool ok;
26: } 27:
28: void main( int argc, char **argv ) 29: {
Okna dialogowe Qt
30:
OApplication a{argc, argv);
31:
MyMainW indow w;
32:
a.setMainW idget( &w );
33:
w.show();
34:
a.exec();
169
35: }
W liniach ll i 12 przydzielana jest pamięć dla jednego o b ie k tu QFontDialog i jednego QFont. W linii 21 tworzona jest zmienna typu bool. Zmienna ta jest następnie używana w linii 25, gdzie za pomocą fu n k c ji G FontDialog::getFont() wywoływane jest okno dialogowe. Oprócz tego, w linii 25 umieszcza się wybraną czcionkę (zwróconą przez funkcją QFontDialog:;getFont()) w obiekcie mojaCzcionka z klasy QFont. Okno dialogowe z tego programu pokazano na rys. 10.3. W celu ustalenia, czy użytkownik wybrał czcionką, należy utworzyć zm ienną boole’owską (tak jak uczyniono w programie z listingu 10.3), a następnie przekazać adres pamięci tej zmiennej do funkcji Q FontDialog::getFont(). Zmienna ta (w tym przypadku ok) będzie w ów czas mieć wartość TRUE. jeśli użytkownik wybierze now ą czcionkę, a wartość FALSE, gdy kliknie on przycisk Cancel (Anuluj). Oto przykład pokazujący, jak można to zrealizować: if( ok == TRUE )
{ // W ybrano nową czcionkę, // możemy kontynuować.
} if( ok == FALSE )
{ II Użytkownik kliknął przycisk Cancel. // Powinniśmy przerwać operację.
} Jeśli użytkownik wybierze now ą czcionkę, to będzie ona zapisana w m ojaCzcionka i będzie ją można do czegoś wykorzystać - np. do określenia czcionki dla obiektu OLabel. Rys. 10.3
Okno dialogowe do wybierania czcionki, udostępniane przez Qt.
170
Godzina 10
Używanie okna komunikatów Okno komunikatów, udostępniane przez klasą QMessageBox, jest najprostszym z predefi niowanych okien dialogowych Qt. Można je wykorzystać do przedstawienia użytkowniko wi krótkiej informacji (co zademonstrowano w jednej z wcześniejszych lekcji) lub do za dania użytkownikowi prostego pytania, np. czy chce kontynuować. Okno dialogowe może zawierać ikoną i maksymalnie trzy przyciski. Przykład podano na listingu 10.4.
Listing 10.4 Okno komunikatów 1: #include
2 #include 3 #include 4 5 class MyMainW indow : public QWidget
6 { 7 public:
8
MyMainWindow();
9 private: QMessageBox *mbox:
10
11
};
12 13 MyMainW indow::MyMainWindow() 14
{
15
setGeometry{ 100, 100, 200, 50 );
16
mbox = new QMessageBox( „Kontynuować?”, „Czy chcesz kontynuować?",
17
QMessageBox::Critical,
18
QMessageBox::Ok | QMessageBox::Default,
19
QMessageBox::Cancel | QMessageBox::Escape,
20
0 );
mbox->show(); 21 22 } 23 24 void main( int argc, char **argv ) 25
{
26
QApplication a(argc, argv);
27
MyMainW indow w;
28
a.setMainW idget( &w );
29
w.show{);
30
a.exec();
31
}
W celu utworzenia okna komunikatów wywoływany jest konstruktor QMessageBox (linie 16-20). W linii 21 wywołuje się funkcję QM essageBox::show(), odpowiadającą za wyświe
Okna dialogowe Qt
171
tlenie okna komunikatów na ekranie. Jak widzisz, do konstruktora QMessageBox przekazy wanych jest sporo argumentów. Pierwszy argument (linia 16) reprezentuje łańcuch teksto wy, jaki ma być wyświetlany u góry okna (zwany także nagłówkiem okna). Drugi argu ment (linia 16) jest łańcuchem tekstowym, jaki będzie pokazywany w oknie komunikatów (treścią komunikatu). Trzeci argument (linia 17) jest ikoną, jaka ma być wyświetlana w oknie komunikatów. Są tutaj cztery możliwości do wyboru: • QMessageBox::Nolcon nie będzie w y ś w ie tla ć w o g ó le żadnej iko n y.
wyświetla ikonę informacyjną. • QMessageBox::Waming wyświetla ikonę odpowiadającą komunikatom ostrzegawczym. • QMessageBox::Critical należy użyć, jeśli zachodzi potrzeba wyświetlenia pewnych kryty cznych informacji lub jeśli użytkownik ma dokonać istotnego wyboru. • QMessageBox::lnformation
W tym przypadku użyto ikony QMessageBox;:Critical (linia 17). Trzeci argument (linia 18) definiuje pierwszy przycisk. W tym przypadku jest to QMessageBox::Ok. Argument ten jest łączony z QMessageBox::Default, co sprawi, że przycisk będzie przyciskiem domyślnym (zo stanie on „kliknięty”, jeśli użytkownik naciśnie klawisz Enter lub Return). Piąty argument (linia 19) definiuje drugi przycisk. W tym przypadku wybrano przycisk Cancel. Przycisk ten jest kombinowany z QMessageBox::Escape, dzięki czemu zostanie on „kliknięty”, jeśli użytkownik naciśnie klawisz Escape.
Nie ma żadnego przymusu łączenia jakichkolwiek przycisków z wartościami QMessageBox::Default lub QMessageBox::Escape.
Ostatni argument definiuje trzeci przycisk. Jednak przykład ten używa tylko dwóch, więc wprowadzono tu wartość 0. Rezultat działania tego kodu pokazano na rys. 10.4. Rys. 10.4 Okno komunikatów z dwoma przyciskami, krótkim zapytaniem oraz ikoną.
Oczywiście, do wyboru jest więcej przycisków niż tylko OK i Cancel Inne możliwości to QMessageBox::Yes, QMessageBox::No, QMessageBox::Abort, QMessageBox::Retry i QMessageBox::lgnore.
Używanie okna dialogowego Progress (Postęp) Okno dialogowe Progress służy do informowania użytkownika o bieżącym stanie aplikacji (tak jak pasek postępu). Okno dialogowe Progress tym się różni od paska postępu, że mo
Godzina 10
172
że ono wchodzić w interakcje z użytkownikiem (tzn. użytkownik może przerwać bieżące zadanie, jeśli zechce). Przykład znajdziesz na listingu 10.5.
Listing 10.5 Okno dialogowe Progress 1 #include 2 #inc!ude 3 #include 4 5 class MyMainW indow : public QW idget
6 { 7 public: MyMainWindow{);
8
9 private:
10
QProgressDialog *pdialog,
11 }; 12 13 MyMainW indow::MyMainW indow() 14
{ setGeometry( 100, 100, 200, 50 );
15 16 17
pdialog = new QProgressDialog( „Przetwarzam.
18
„Przerwij wykonywanie", 100,
19
this, „pdialog", TRUE );
20 21
pdialog()->show()
22
int x = 0;
23
int i = 0;
24
while{ x setProgress(x)
26 27 28
x++;
29
}
30
}
31 32 void main( int argc, char **argv ) 33
{
34
QApplication a(argc, argv);
35
MyMainW indow w;
36
a.setMainW idget( &w );
37
w.show{);
38
a.execQ;
39
}
Okna dialogowe Qt
173
Do konstruktora QProgressDialog przekazywanych jest w sumie sześć argumentów (linie 17, 18 i 19). Pierwszy argument (linia 17) reprezentuje tekst wyświetlany u góry okna dialo gowego postępu (nie nagłówek okna). Napis ten powinien poinformować użytkownika 0 tym, co się aktualnie dzieje. Drugi argument (linia 18) reprezentuje tekst na przycisku „anuluj”. Trzeci argument (linia 18) jest łączną liczbą kroków. W tym przypadku pasek po stępu osiągnie 100 % po wywołaniu QProgressDialog::setProgress(100). Ostatnie trzy argu menty mają predefiniowane wartości i tak naprawdę można je opuścić. Jeśli jednak chcesz, żeby okno dialogowe postępu podczas działania było odrysowywane, to musisz ustawić szósty argument na TRUE. W tym celu musisz określić także argumenty czwarty i piąty. Je śli nie ustawisz szóstego argumentu na TRUE, etykieta dla przycisku anulowania w ogóle nie będzie widoczna. Aby pokazać, w jaki sposób wykorzystać okno dialogowe postępu, utworzyłem pętlę, która wywołuje setProgress() za każdym razem z większą wartością. Zdecydowanie nie jest to przykład, który można by nazwać praktycznym. Pokazuje on jednak, w jaki sposób to wszystko działa (patrz rys. 10.5). Rys. 10.5 Tutaj pasek postępu je s t aktywny i w danym m omencie osiągnął 57 procent.
Tworzenie niestandardowych okien dialogowych Kiedy nie wystarczają Ci predefiniowane okna dialogowe, musisz stworzyć własne - nie standardowe okna dialogowe, specjalnie zaprojektowane do spełnienia Twoich potrzeb. Bi blioteka Qt zawiera dwie klasy ułatwiające tworzenie niestandardowych okien dialogo wych: QDialog (klasa bazowa dla wszystkich okien dialogowych) oraz QTabDialog (do two rzenia okien dialogowych z kartami).
Tworzenie okien dialogowych za pomocą klasy QDialog ODialog jest klasą bazową okien dialogowych - bazują na niej wszystkie inne klasy okien dia logowych. Klasa ta udostępnia kilka podstawowych funkcji do tworzenia okien dialogowych. Przy tworzeniu okien dialogowych masz do wyboru dwa typy: modalne okna dialogowe 1 niemodalne okna dialogowe. Modalne okno dialogowe uruchamia własną pętlę zdarzenio wą i w ten sposób blokuje resztę programu, dopóki nie zostanie zamknięte. Z drugiej stro ny, niemodalne okno dialogowe nie blokuje reszty aplikacji. To, czy okno dialogowe bę dzie modalne czy niemodalne, zależy od tego, jak ą wartość (boole’owską) przekażesz j a
174
Godzina 10
ko trzeci argument do konstruktora QDialog. Wartość TRUE oznacza okno modalne, a FAL SE niemodalne. Teraz przyjrzymy siq kilku ważnym funkcjom służącym do pracy z klasą QDialog. Funkcja Q Dialog::setCaption() służy do ustawiania nagłówka okna dialogowego. Funkcje QDialog::accept(), QDialog::reject i Q Dialog::done() usuwają okno dialogowe i zwracają odpowiednią war tość. Accept() zwraca stalą QDialog::Accepted( 1), a Reject() zwraca stałą Q Dialog::Rejected(0). Można także zdefiniować własną wartość zwracaną, przekazując tq wartość (typu integer) jako argument do funkcji done(). W rzeczywistości można wywoływać d o n e ( l) i done(O) zamiast używać accept() i rejectf); rezultat jest taki sam. inną interesującą cechą klasy QDialog jest to, że nie trzeba używać setG eom etry() ani resize() w celu określenia rozmiarów okna. Jeśli tylko umieścisz swoje widgety w oknie dialogo wym, klasa QDialog automatycznie dostosuje rozmiary tego okna, tak by pomieścić w nim wszystkie widgety potomne. Listing 10.6 przedstawia prosty przykład pokazujący, jak można utworzyć niestandardowe okno dialogowe przy użyciu klasy QDialog. Listing 10.6 Niestandardowe okno dialogowe utworzone za pom ocą klasy QDialog 1: #include 2: #include 3: #include 4: #include 5: 6: class Pytanie : public QDialog 7 :{ 8: public: 9:
PytanieQ;
10: private: 11:
QLabel ‘ etykieta;
12:
QPushButton *duze;
13:
QPushButton ‘ male;
14:};
15: 16: // W tym miejscu definiujemy okno dialogowe. Przekazujemy trzy 17: // argumenty do konstruktora QDialog. Pierwsze dwa (widget macierzysty 18: // i nazwa) są ustawiane na 0. Trzeci 19: // powoduje, że to okno dialogowe będzie modalne. 20: P ytanie::P ytanie(): QDialog( 0, 0, TRUE ) 21: { 22:
setCaption( „Duże czy małe?" );
23: 24:
etykieta = new QLabel( this );
25:
etykieta->setText( „Chcesz widzieć duże
26: 27:
etykieta->setGeometry( 10, 10, 300, 100 );
28:
etykieta->setFont( QFont( „Arial", 18, QFont::Bold ) );
czy małe okno?” );
Okna dialogowe Qt
29;
etykieta->setAlignm ent( A lig n C e n te r);
30: 31:
duze = new QPushButton( „DUŻE!", this );
32:
duze->setGeom etry( 50, 120, 90, 30 );
33:
duze->setFont( QFont( „Arial", 14, QFont::Bold ) );
34: 35:
male = new QPushButton( „małe!", this );
36:
male->setGeometry( 180, 120, 90, 30 );
37:
m ale->setFont( QFont{ „Arial", 14, QFont::Bo!d ) );
38: 39:
connect( duze. SIGNAL( clickedQ ), this, SLOT( acceptQ ));
40:
connect( male, SIGNAL( clickedQ ), this, SLOT( rejectQ ) ) ;
41: 42: 43: class MyProgram : public QWidget 44:
{
45: public: 46:
MyProgramQ;
47: private: 48: 49:
Pytanie *p;
};
50: 51: M yProgram::MyProgram() 52: 53:
{
54:
p = new Pytanie(); II Ponieważ Pytanie jest modalnym oknem dialogowym.
55:
II więc zamiast showQ wywołujem y exec():
56:
int i = p->exec();
57: 58:
// Jeśli użytkownik kliknie przycisk
59:
// z etykietą „DUŻE!", wyświetl duże okno:
60:
if( i == QDialog::Accepted )
61:
{
62: 63:
resize( 500, 500 );
}
64: 65:
II Jeśli użytkownik kliknie przycisk
66 :
// z etykietą „małe!", wyświetl małe okno:
67:
if( i == QDialog::Rejected )
68 :
{
69: 70:
resize( 50, 50 );
}
71: 72: 73: void main( int argc, char **argv )
175
176
Godzina 10
74 75
OApplication a(argc, argv);
76
MyProgram w;
77
a.setMainWidget( &w );
78
w.show();
79
a.exec{);
80
Jak widzisz, program ten składa się z dwóch klas: jednej opartej na QDialog (linie 6-41), a drugiej opartej na OWidget (linie 43-71). W konstruktorze Pytanie składane jest okno dia logowe - z etykietą (linie 24-29) i dwoma przyciskami (linie 3 1 37). W liniach 39 i 40 sy gnały clicked() przycisków są łączone z gniazdami accept() i reject() okna QDialog. Zapew nia to, że okno dialogowe zwróci właściwą stałą (która jest umieszczana w i w linii 56). Klasa oparta na OWidget (MyProgram) jest głównym widgetem i w jej konstruktorze tw o rzony jest obiekt klasy Pytanie (linie 48, 53 i 56). Następnie, w liniach 6 0-70 sprawdzana jest wartość zwrócona przez obiekt Pytanie (p) i ustawiane są odpowiednio rozmiary okna. Nie powinieneś mieć żadnych problemów ze zrozumieniem tego programu, jeśli przestu diowałeś i zrozumiałeś poprzednie lekcje. Komentarze umieszczone w kodzie stanowią dalsze objaśnienie. Kiedy uruchomisz ten program, pierwszą rzeczą, jaką ujrzysz, będzie okno dialogowe pokazane na rys. 10.6 . Rys. 10.6
Okno dialogowe utworzo ne przez klasę Pytanie z listingu 10.6.
i '««iJ
1
Jeśli teraz klikniesz przycisk „DUŻE!”, pojawi się dość duże okno. Z drugiej strony, jeśli klikniesz przycisk „małe!”, pojawi się małe okno. Okna te pokazano, odpowiednio, na rys. 10.7 i 10.8. Powinieneś już teraz dobrze rozumieć, w jaki sposób można wykorzystywać klasę ODialog. Przykład z listingu 10.6 można było utworzyć równie dobrze za pomocą klasy OMessageBox. Jednak teraz, kiedy wiesz, jak korzystać z ODialog, z łatwością będziesz mógł tworzyć okna dialogowe odpowiadające Twoim własnym, konkretnym potrzebom. Powinieneś jed nakże, tak często, jak tylko możesz, używać predefiniowanych okien dialogowych dla za oszczędzenia sobie pracy i czasu. Jeśli jednak takie okna dialogowe nie są w stanie w yko nać dla Ciebie żądanego zadania, to musisz sporządzić je sam, wykorzystując do tego kla sę QDialog.
Używanie klasy QTabDialog Drugą klasą Qt, przy użyciu której można tworzyć niestandardowe okna dialogowe, jest OTabDialog. Z jej pomocą można tworzyć tzw. okna dialogowe z kartami. Okno dialogowe
Okna dialogowe Qt
177
z kartami jest to widget składający się z kilku stron. Prawdopodobnie widziałeś już ten typ okna dialogowego w wielu aplikacjach. Okno dialogowe z kartami przydaje się wtedy, kiedy aplikacja ma mieć dużo widgetów, których umieszczenie na jednej stronie mogłoby doprowadzić do dużego nieładu. Użycie okna dialogowego z kartami umożliwia podziele nie zawartości aplikacji na kategorie (każda kategoria ma wówczas własną stronę w oknie dialogowym). Dzięki temu aplikacja wygląda dużo ładniej i jest łatwiejsza w użyciu. Rys. 10.7 Okno, ja k ie pojaw i się, gdy klikniesz przycisk DUŻE!.
Rys. 10.8 Okno, ja k ie pojaw i się, gdy klikniesz przycisk małe!.
Przykład z listingu 10.7 pokazuje, jak wygląda okno dialogowe z kartami w swej pierwot nej postaci (kiedy nie dodano do niego jeszcze żadnych kart).
Listing 10.7 Obiekt QTabDialog w swojej pierwotnej postaci 1: #include 2: #include 3: #include 4: 5: class MyMainWindow : public OWidget
6: { 7: public: 8: 9: private:
MyMainWindow();
178
Godzina 10
10:
Q TabD ialog‘ tdialog;
11:}: 12: 13: MyMainWindow::MyMainWindow() 14: { 15:
selGeometry( 100, 100, 200, 50 );
16: 17:
tdialog = new QTabDialog();
18:
tdialog->resize( 300, 250 );
19:
tdialog->show();
20 : } 21 : 22: void main( int argc, char *‘ argv ) 23: { 24: QApplication a(argc, argv); 25: MyMainWindow w; 26: a,setMainWidget( &w ); 27: w.show(); 28: a.exec(); 2 9 :}
Okno dialogowe z powyższego programu pokazano na rys. 10.9. Rys. 10.9 Puste okno dialogow e z kar tami utworzone przez klasę QTahDialog. Jeśli klikniesz przycisk OK, okno zostanie zamknięte.
Jeśli chcesz dodać widgety do okna dialogowego z kartami, to musisz utworzyć kilka obiektów QWidget z umieszczonymi na nich widgetami potomnymi, a następnie dodać ta kie obiekty OWidget do okna dialogowego za pomocą funkcji QTabDialog::insertTab(). Przy kład podano na listingu 10.8.
Listing 10.8 Obiekt QTabDialog z trzema stronami 1: #include 2: tfinclude 3: #include
Okna dialogowe Qt
4: tfinclude 5: 6: class MyMainW indow : public QWidget 7 :{ 8: public: 9:
MyMainWindow{);
10: private: 11:
QTabDialog ‘ tdialog;
12:
Q W id g e t‘ stro n a l;
13;
QWidget *strona2;
14:
QWidget *strona3;
15:
Q L a b e l‘ etykieta;
16 :}; 17: 18: MyMainW indow::MyMainWindowQ 19: { 20:
setGeometry( 100, 100, 200, 50 );
21 :
22:
tdialog = new QTabDia!og();
23:
tdialog->resize( 300, 250 );
24: 25:
strona 1 = new QWidgetQ;
26:
strona1->resize( 280, 180 );
27:
etykieta = new QLabel(
„To jest strona 1,", stron al );
28:
etykieta->setGeometry(
20, 20, 240, 140 );
29: 30:
etykieta->setAlignment( A lig n C e n te r);
31:
sirona2 = new QWidgetQ;
32:
strona2->resize( 280, 180 );
33:
etykieta = new QLabel( „To jest strona 2.” , strona2 );
34:
etykieta->setGeometry( 20, 20, 240,140 );
35:
etykieta->setAlignment( A lig n C e n te r);
36: 37:
strona3 = new QWidgetQ;
38:
strona3->resize( 280, 180 );
39:
etykieta = new QLabe!( „To jest strona 3.", strona3 );
40:
etykieta->setGeometry(
41:
etykieta->setAlignment( A lig n C e n te r);
20, 20, 240, 140 );
42: 43:
tdialog->insertTab( stro n a l, „Strona 1" );
44:
tdialog->insertTab( strona2, „Strona 2” );
45:
tdialog->insertTab( strona3, „Strona 3" );
46:
tdialog->show();
47: 48:
179
180
Godzina 10
49: void main( int argc, char **argv ) 50: { 51 52
QApplication a(argc, argv);
53
a.setMainWidget( &w );
54
w.show();
55
a.exec();
MyMainWindow w;
56
W programie powyższym okno dialogowe z kartami tworzone jest w liniach 22 i 23. Trzy obiekty OWidget, które będą reprezentować każdą z kart okna dialogowego są tworzone w li niach 25-41. Do każdego obiektu OWidget dodawana jest jedna etykieta. Następnie, w liniach 43, 44 i 45, obiekty OWidget są dodawane do okna dialogowego za pomocą funkcji OTabDialog::insertTab(). W linii 46 wywoływana jest funkcja QTabDialog::show( ) w celu uwidocznienia utworzonego okna dialogowego z kartami. Program ten pokazano na rys. 10.10. Rys. 10.10 Okno dialogowe z kartami zawierające trzy strony. Na każdej ze stron znajdu j e się etykieta.
F5TT) |p*«*rjPł|«s j
I to tyle, jeśli chodzi o ten typ okna dialogowego. Tak więc wystarczy utworzyć widgety, tak jak zwykle, i wstawić je za pomocą funkcji QTabDialog::msertTab().
Przy wstawianiu stron za pomocą funkcji insertTab(), możesz dodać znak ampersand (&) na początku etykiety (lub przed dowolnym jej znakiem, z którym chcesz skojarzyć skrót), aby automatycznie utworzyć skrót klawiaturowy. Spójrzmy na przykład na poniższą linię-
W tym przypadku można będzie się dostać do strony Opcje poprzez naciśnięcie Ctrl+O na klawiaturze. Takie skróty klawiaturowe mają zastosowanie również w przypadku wielu innych widgetów Qt (np. takich jak menu).
Podsumowanie Okna dialogowe grają ważną rolę w każdej poważnej aplikacji. Nie bądź zaskoczony, jeśli przyjdzie Ci utworzyć 30 lub więcej okien dialogowych dla średniej wielkości aplikacji, a możliwe, że nawet setkę, w przypadku dużego projektu.
Okna dialogowe Qt
181
Predefiniowane okna dialogowe często będą wszystkim, czego Ci potrzeba. Jeśli jednak stwierdzisz, że to za mało, będziesz mógł wówczas użyć klas Qt do konstruowania niestan dardowych okien dialogowych. Co więcej, dużą część pracy wykonają one za Ciebie. W tej lekcji nauczyłeś się pracować z predefiniowanymi oknami dialogowymi biblioteki Qt, jak również nauczyłeś się tworzyć niestandardowe okna dialogowe. Z taką wiedzą po winieneś być w stanie używać Qt do tworzenia dowolnego rodzaju okien dialogowych dla swoich programów, niezależnie od tego, czy są to powszechnie wykorzystywane okna dia logowe czy Twoje własne produkcje.
Pytania i odpowiedzi Widgety położone u dołu mojego okna dialogowego z kartami są widoczne tylko częścio wo. Co je s t nie tuk? Jak widzisz, obszar dla stron w oknie dialogowym z kartami nie zajmuje całego okna. Wokół niego znajduje się wolna przestrzeń. Jeśli myślałeś, że strona jest takich samych rozmiarów jak okno, to niektóre z twoich widgetów mogą być niewidoczne lub widocz ne tylko częściowo. Na moim oknie dialogowym postępu nie widzę etykiety ani przycisku „cancel". Co je s t nie tak? Musisz uczynić swoje okno dialogowe modalnym. Dokonasz tego, przekazując wartość boole’owską TRUE jako szósty argument do konstruktora QProgressBar. Czy w swoim oknie komunikatów muszę mieć trzy przyciski? Chciałbym mieć tylko jeden lub dwa! Nie, wcale nie musisz mieć trzech przycisków. Po prostu przekaż do konstruktora QMessageBox wartość 0 w miejscu zarezerwowanym dla definicji trzeciego przycisku.
Warsztaty Pytania i ćwiczenia z tej sekcji pomogą Ci utrwalić wiedzę o oknach dialogowych, zdoby tą w niniejszej lekcji.
Quiz 1. Co to jest okno dialogowe? 2. Czy biblioteka Qt oferuje jakieś okno dialogowe do wybierania plików? 3. Czy istnieje możliwość wybrania wielu plików? 4. W jakim celu można by pozwolić użytkownikowi dokonać wyboru koloru? 5. Jakiej klasy należy użyć w celu utworzenia okna dialogowego do wybierania czcionki? 6 . Jakiego okna dialogowego powinieneś użyć, jeśli chcesz zadać użytkownikowi proste pytanie?
182
Godzina 10
7. Jaką wartość powinieneś ustawić jako maksymalną wartość postępu, gdybyś miał wła śnie do otworzenia 50 plików? 8. C z y d o u tw o rz e n ia w ła s n e g o okn a d ia lo g o w e g o z k a rta m i m o żn a w y k o rz y s ta ć b a z o w ą klasę QDialog?
Ćwiczenia 1. Utwórz program z oknem dialogowym, umożliwiający użytkownikowi wybranie czcion ki. Po dokonaniu wyboru czcionki, wyświetl jakiś tekst napisany z jej użyciem. 2. W programie z ćwiczenia 1 zaimplementuj okno dialogowe do wybierania koloru. Po zwól użytkownikowi wybrać zarówno kolor, jak i czcionkę; następnie użyj klasy Q P a i n ter do wyświetlenia jakiegoś tekstu w wybranym kolorze i z użyciem wybranej czcion ki. 3. Utwórz niestandardowe okno dialogowe, w którym prosisz użytkownika o podanie imie nia. Użytkownik powinien mieć możliwość wpisania swojego imienia w polu do w pro wadzania tekstu, a następnie naciśnięcia przycisku OK (lub podobnego przycisku) w ce lu przedłożenia odpowiedzi. Program powinien odpowiedzieć na to wyświetleniem no wego okna z komunikatem Cześć , jak się dziś masz? 4. Utwórz okno dialogowe z kartami. Dodaj do niego kilka stron, a następnie dodaj do tych stron parę przycisków radiowych, przycisków pola wyboru i inne widgety. Jeśli masz j a kiś inny program, który używa okna dialogowego z kartami, to spróbuj skopiować w y gląd tego okna dialogowego, używając widgetów Qt. (Dobrym przykładem jest okno dialogowe Opcje z programu Microsoft Word.)
CZĘSC TRZECIA Poznajemy bardziej bibliotekę Qt G od zin a
11 Używanie menedżerów układu 12 Praca z plikami i katalogami 13 Przetwarzanie tekstu i wyrażenia regularne 14 Używanie klas pojemników 15 Więcej o grafice 16 Komunikacja między programami
G
o d z in a
11
Używanie menedżerów układu Jak dotąd, obiekty Qt rozm ieszczałeś w swoich program ach podając bezw zględne w spółrzędne funkcjom Q W id g e t::re size ( ) i Q W id get::setG eom etry( ). Problem z tą m etodą jest taki, że gdy zm ienisz rozm iary okna m acierzystego, będzie ono albo za małe, albo za duże do tego, by w łaściw ie pom ieścić swoje widgety potomne. Po prostu, Twój p ro gram nie będzie ju ż dobrze wyglądać. I tu właśnie na scenę w kraczają m enedżery układu. Menedżery układu są zbiorem klas Qt kontrolujących to, jak i kiedy zmieniane są rozmia ry głównego okna. Jeśli zarejestrujesz swoje widgety w menedżerze układu i nie nadasz im bezwzględnych współrzędnych położenia, menedżer układu będzie zmieniać rozmiary tych widgetów lub je przesuwać, gdy tylko zajdzie taka potrzeba (tzn. gdy użytkownik zmieni rozmiary głównego okna). Dzięki temu Twoja aplikacja będzie łatwiejsza w użyciu i wizualnie sprawiać będzie znacznie ciekawsze wrażenie. Menedżery układu stanowią także znakomitą pomoc, gdy zachodzi potrzeba rozmieszczę-
186
Godzina 11
nia wielu widgetów. Proces ten często jest bardzo czasochłonny. Dzięki m enedżerom ukła du można to zrobić dużo szybciej.
Zrozumienie menedżerów układu Aby pomóc Ci lepiej zrozumieć koncepcję menedżerów układu, prześledzimy teraz pewien praktyczny przykład (chociaż bardzo elem entarny), pokazujący, kiedy m enedżery układu mogą okazać się przydatne. Rys. 11.1 p rz e d s ta w ia o k n o z d w o m a w id g e ta m i QPushButton. Rys. 11.1 Okno za w iera ją ce dw a widget}' QPushButton. Nie je s t ono po łą czo n e z ż a d nym m enedżerem układu. Co się zatem stanie, je ś li zmienimy je g o ro zm ia ry?
Powiedzmy, że chcesz powiększyć to okno; rezultat będzie mniej więcej taki, jak widać na rys. 11.2 . Rys. 11.2 Tak będzie, g d y zm ienisz rozm iary okna nie korzysta jącego z m en edżerów układu. W większości p rzyp a d k ó w będziesz chcieć, że b y rozm ia ry w idgetów (tutaj p izy c isków) także się zm ien iły i/lub żeby w idgety zo sta ły p rzesu nięte w celu dopasow an ia do głów nego okna.
Z drugiej strony, jeśli w przykładzie zilustrowanym na rys. 11.1 użyjesz menedżera układu, efekt zmiany rozm iarów okna będzie taki, jak widać na rys. 11.3. Jak wspomnieliśm y wcześniej, z m enedżerów układu m ożna skorzystać także wtedy, gdy zachodzi potrzeba rozmieszczenia w aplikacji wielu widgetów. Na przykład, gdybyś chciał rozmieścić widgety OPushButton. to dużo czasu musiałbyś poświęcić na samo w prow adza nie bezwzględnych współrzędnych dla każdego z tych widgetów. Zamiast tego możesz utworzyć te przyciski i, nie wprowadzając dla nich żadnych bezwzględnych w spółrzęd nych, zarejestrować je wszystkie w menedżerze układu.
Używanie menedżerów układu
187
Rys. 11.3 Tutaj użyto menedżera układu, któiy kontroluje pozycję p rzy cisków. Kiedy zmienisz rozmialy okna, pozycje przycisków zostaną zmienione tak, by p a sowały do nowych rozmiarów okna.
Używanie menedżerów układu Wiesz już teraz, czym są menedżery układu oraz ja k można ich użyć. Dlatego przejdziem y teraz do om ówienia tego, co należy zrobić w celu zaimplementowania ich w swoim pro gramie. Przede wszystkim musisz wiedzieć, jakie menedżery układu dołączono do Qt oraz spośród czego będziesz mógł wybierać. W tabeli 11.1 podano listę menedżerów układu dołączo nych do Qt 2.0 wraz z opisem tego, co robią.
Tabela 11.1 Menedżery układu w Qt M enedżer układu
Opis
OLayout
Jest to klasa bazowa m enedżerów układu. W szystkie inne menedżery układu dziedziczą z lej klasy. Jeśli chcesz utw orzyć niestandardow y me nedżer układu, to powinieneś to zrobić w oparciu o tę klasę.
QGridLayout
Tego menedżera układu należy użyć w przypadku rozmieszczania w idgeló w w siatce (tabeli).
QBoxLayout
Jest to klasa bazowa dla klas QHBoxLayout i QVBoxLayout. Pow inno się je j używać ty lk o wtedy, gdy w czasie ko m p ila cji nie m ożna zdecydować, czy w id g e ly m ają być rozmieszczane w wierszach, czy kolum nach.
QHBoxLayout
Tego menedżera pow inieneś użyć, gdy chcesz, aby w idge ty b y ły ro zm ie szczane w wierszu.
QVBoxLayout
Tego menedżera pow inieneś użyć, gdy chcesz, aby w idge ty b y ły rozm ie szczane w kolum nie.
Pierwsza klasa w ym ieniona w powyższej tabeli jest klasą bazową dla czterech pozostałych. Rzadko będziesz m usiał korzystać z tej klasy, gdyż większość (choć pewnie nie wszystkie) problemów dotyczących układu możesz rozwiązać poprzez połączenie O G ridLayout, QBoxLayout, QHBoxLayout i QVBoxLayout (przykład pokazujący, jak połączyć te menedżery ukła du w celu uzyskania bardziej złożonych układów znajduje się na listingu 11.5).
188
Godzina 11
Rozmieszczanie widgetów w wierszach i kolumnach W przykładach z sekcji „Zrozumienie menedżerów układu”, dwa widgety QPushButton by ły rozmieszczane w kolumnie. W pierwszym przykładzie widgety były umieszczane ręcz nie. W drugim przykładzie użyty został menedżer QVBoxLayout. Kod źródłowy przykładu zilustrowanego na rys. 11.1 przedstawiono na listingu 11. 1. Listing 11.1 Ręczne umieszczanie widgetów 1: #inc!ude 2: #include 3: #include 4: #include 5: 6: class MyWidget : public QWidget 7 :{ 8: public: 9:
MyWidgetO;
10:}; 1V. 12: MyWidget::MyWidget{) 13: { 14:
setMinimumSize( 200, 200 );
15: 16:
QPushButton *b1 = new QPushButton( „Przycisk 1", this );
17:
b1->setGeometry( 0, 0, 200, 100 );
18:
b1->setFont( QFont( „Times”, 18, QFont::Bold ) );
19:
20'.
QPushButton *b2 = new QPushButton( „Przycisk 2", this );
21
b2->setGeometry( 0, 100, 200, 100 );
22
b2->setFont( QFont( „Times” , 18, QFont::Bold ));
2 3 :} 24: 25: int main(int arge, char **argv ); 26: { 27
QApplication a( arge, argv );
28
MyWidget w:
29
w.setGeometry( 100, 100. 200, 200 );
30
a.setMainWidget( &w );
31
w.show();
32
return a.exec();
33: }
Jak widzisz, listing l l.l nie prezentuje niczego nowego. Ale dla pewności, czy rozumiesz ten kod, prześledźmy z grubsza, co się w nim dzieje. Najpierw tworzona jesr nowa fcfasa,
Używanie menedżerów układu
189
która dziedziczy z klasy bazowej OWidget. Następnie, w konstruktorze MyWidget tworzone są dwa przyciski. 1 wreszcie ustawiane są minimalne rozmiary obiektu MyWidget (200 x 200 pikseli). Jest to aż lak proste! Jednakże, jak już wcześniej nadmieniono, pro blem z tym przykładem jest taki, że przyciski b l i b2 nie zostaną przeskalowane (przesu nięte), jeśli zmienią się rozmiary ich widgetu macierzystego (MyW idget). W programie przedstawionym na listingu 11.2 (a zilustrowanym na rys. 11.3) problem tez został rozwią zany. MyWidget,
Listing 11.2 Rozmieszczanie widgetów za pomocą menedżera układu QVBoxLayout 1: #include 2: #include 3: #include 4: #include 5: #include 6: 7: class M yW id g e t: public OWidget 8:
{
9: public:
10:
MyWidget();
11:}; 12 :
13: MyWidget::MyWidget() 14: { 15
setMinimumSize( 200, 200 );
16 17
OPushButton *b1 = new QPushButton( „Przycisk 1” , this );
18
b1->setMinimumSize( 200, 100 );
19 20
b1->setFont( QFont( „Times”, 18. QFont::Bold ) );
21
22
OPushButton *b2 = new QPushButton( „Przycisk 2", this ); b2->setMinimumSize( 200, 100 );
23
b2->setFont( QFont( „Times”, 18, QFont::Bold ) );
24 25
QVBoxLayout *vbox = new QVBoxLayout( this );
26 27
vbox->addWidget( b2 );
vbox->addWidget( b1 );
28: } 29: int main(int argc, char **argv ); 30: { 31
OApplication a( argc, argv );
32
MyWidget w:
33
w.setGeometry( 100, 100, 200, 200 );
34
a.setMainWidget( &w );
190
Godzina 11
35:
w .s h o w ();
36:
re tu rn a .e x e c ();
37: }
Ta wersja programu wykorzystuje menedżera układu (vbox, opartego na QVBoxLayout) i dla tego wygląda nieco inaczej niż poprzednia. Przyjrzyjmy się kolejno różnicom: • Pierwsza różnicą jest dołączenie pliku nagłówkowego z biblioteki Qt, o nazwie q la y o u t.h . Plik ten zawiera definicje klas menedżerów układu. W tym przypadku, plik q la y o u t.h jest dołączany w celu uzyskania dostępu do klasy Q V B o x L a y o u t. • Druga różnica, jaką zauważysz, jest taka, że nie używa się tutaj funkcji Q W id g e t::s e tG e o m e tr y ( ) w celu zmiany rozmiarów i pozycji przycisków. Zamiast tego, przy użyciu funk cji Q W id g e t::s e tM in im u m S iz e ( ) ustawia się najmniejsze rozmiary, jakie może mieć przycisk (200 x 100 pikseli, w obydwu przypadkach). Przyciski otrzymają takie rozmiary przy pierwszym uruchomieniu programu, ale nie są to wielkości bezwzględne. • I wreszcie trzecia różnica jest taka, że do programu dodano zupełnie nowy obiekt. Jest to obiekt klasy Q V B o x L a y o u t, o nazwie v b o x . Ten obiekt jest właśnie menedżerem układu w tym programie. Aby powiadomić obiekt vbox o przyciskach (bl i b2) i polecić mu za jęcie się ich rozmieszczeniem, przyciski te m uszą zostać zarejestrowane w menedżerze układu. W programie jest to robione w liniach 26 i 27, za pomocą funkcji Q V B o x L a y o u t::a d d W id g e t( ) . W przypadku używania menedżerów układu wszystkie widgety należy rejestrować w ten sposób.
Nie tylko widgety OPushButton można rejestrować i powierzać kontroli menedżera układu. W rzeczywistości, przy użyciu menedżera układu można kontrolować rozmie szczenie dowolnych widgetów Qt.
Nie było to trudne, prawda? Jeśli chcesz uporządkować swoje widgety w wierszu zamiast w kolumnie, po prostu użyj Q H B o x L a y o u t zamiast Q V B o x L a y o u t.
Używanie klasy QGridLayout Jeśli chcesz rozmieścić swoje widgety w siatce, powinieneś użyć klasy O G r id L a y o u t (m ógł byś także użyć Q H B o x L a y o u t i Q V B o x L a y o u t w celu utworzenia poszczególnych wierszy i ko lumn, ale łatwiej jest skorzystać z O G r id L a y o u t) . Spójrzmy na prosty przykład wykorzystu jący klasę O G r id L a y o u t do rozmieszczenia sześciu obiektów O P u s h B u tto n w trzech wierszach i dwóch kolumnach. Kod źródłowy do tego przykładu przedstawiono na listingu 11.3.
Listing 11.3 Rozmieszczanie widgetów za pomocą klasy QGridLayout 1: # in c lu d e < q a p p lic a tio n .h > 2: # in c lu d e < q w id g e t.h >
Używanie menedżerów układu
3: # in c lu d e < q p u s h b u tto n .h > 4: # in c lu d e < q fo n t.h > 5: # in c lu d e < q la y o u t.h >
6: 7: c la s s M y W id g e t : p u b lic Q W id g e t
8: { 9: p u b lic :
10:
MyWidgetO;
11:}; 12: 13: M y W id g e t::M y W id g e t( ) 14: { 15:
s e tM in im u m S iz e ( 2 0 0 , 2 0 0 );
16: 17;
Q P u s h B u tto n *b1 = n e w Q P u s h B u tto n ( „ P r z y c is k 1” , th is );
18:
b 1 - > s e tM in im u m S iz e ( 2 0 0 , 1 00 );
19:
b 1 - > s e tF o n t( Q F o n t( „T im e s ", 18, Q F o n t::B o ld ) ) ;
20 : 21:
Q P u s h B u tto n *b 2 = n e w Q P u s h B u tto n ( „P r z y c is k 2 ", th is );
22:
b 2 - > s e tM in im u m S iz e { 2 0 0 , 1 0 0 );
23:
b 2 - > s e tF o n t( Q F o n t( „T im e s " , 18, Q F o n t::B o ld ) ) ;
24: 25:
Q P u s h B u tto n *b 3 = n e w Q P u s h B u tto n ( „ P r z y c is k 3 ” , th is );
26:
b 3 - > s e tM in im u m S iz e ( 2 0 0 , 1 0 0 );
27:
b 3 - > s e tF o n t( Q F o n t( „ T im e s ” , 18, Q F o n t::B o ld ) );
28: 29:
Q P u s h B u tto n *b 4 = n e w Q P u s h B u tto n ( „ P r z y c is k 4 ” , th is );
30:
b 4 - > s e tM in im u m S iz e ( 2 0 0 , 1 0 0 );
31:
b 4 - > s e tF o n t( Q F o n t( „T im e s ", 18, Q F o n t::B o ld ) );
32: 33:
Q P u s h B u tto n *b 5 = n e w Q P u s h B u tto n ( „P r z y c is k 5", th is );
34:
b 5 - > s e tM in im u m S iz e ( 2 0 0 , 1 0 0 );
35:
b 5 - > s e tF o n t{ Q F o n t( „T im e s " , 18, Q F o n t::B o ld ) ) ;
36: 37:
Q P u s h B u tto n *b 6 = n e w Q P u s h B u tto n ( „ P r z y c is k 6 ", th is );
38:
b 6 - > s e tM in im u m S iz e ( 2 0 0 , 1 0 0 );
39:
b 6 - > s e tF o n t( Q F o n t( „T im e s ", 18, Q F o n t::B o ld ) );
40: 41:
Q G r id L a y o u t *g rid = n e w Q G r id L a y o u t( th is , 3, 2 );
42:
g rid - > a d d W id g e t(
b 1, 0, 0 );
43:
g rid - > a d d W id g e t(
b 2 , 1, 0 );
44:
g rid - > a d d W id g e t(
b 3, 2, 0 );
45:
g rid - > a d d W id g e t(
b 4, 0, 1 );
46:
g rid - > a d d W id g e t(
b 5, 1, 1 );
47:
g rid - > a d d W id g e t(
b 6, 2,
1 );
191
192
Godzina 11
48: } 49: 50: int main(int argc, char **argv ); 51: { 52:
QApplication a( argc, argv );
53:
MyWidget w:
54:
w.setGeometry( 100, 100, 200, 200 );
55:
a.setMair\W idget( &w );
56:
w.show();
57:
return a.exec();
58: }
Przykład ten zilustrowano na rys. 11.4. Rys. 11.4 IV tym przykładzie użyto klasy QGridLavout do rozmieszcze nia sześciu przycisków siatce.
Button 4
B u lio n 1
I
^ B u tto n S
,
B u tton 3
Button 6
Tym razem układ przycisków jest kontrolowany przez klasę OGridLayout. Składnia dla tw o rzenia i używania tej klasy jest nieco inna od składni dla klas QHBoxLayout i QVBoxLayout. Zacznijmy od tego, że konstruktorowi OGridLayout należy podać trzy argumenty, a nie j e den. Zrobiono to w poniższej linii: OGridLayout *grid = new QGridLayout( this, 3, 2 );
Pierwszy argument, this, jest jak zwykle wskaźnikiem do nie utworzonego obiektu MyWidget. Jednak drugi i trzeci argument stanowią dla Ciebie nowość. Drugi argument, 3, wska zuje, ile wierszy ma mieć siatka. Trzeci argument, 2. wskazuje, ile kolumn ma mieć siatka. W tym przypadku mają być trzy wiersze i dwie kolumny. Następnie, tak jak w przypadku klas QVBoxLayout i QHBoxLayout, przy użyciu funkcji QLayout::addW idget() dodawane są widgety (w tym przypadku przyciski) do menedżera układu (grid). Jak widać, dodawane są tutaj jeszcze dwa argumenty. Oprócz wyspecyfikowania wskaźnika this, podawanego jako pierwszy argument, funkcji Q Layout::addW idget() mówi się, w jakim wierszu i kolumnie ma być wstawiony dany przycisk. Spójrzmy na poniższą linię: grid->addWidget( b1, 0, 0 );
Używanie menedżerów układu
193
Wstawiany jest tutaj obiekt (b l) do pierwszego wiersza i pierwszej kolumny siatki. Obiekt ten reprezentuje lewy górny przycisk siatki pokazanej na rys. 11.4. Tak więc, w przykła dzie z listingu 11.3, (0, 1) reprezentuje przycisk 4, (2, 1) reprezentuje przycisk 6 , itd. Rys. 11.5 pozwoli Ci lepiej to sobie unaocznić. Teraz wiesz już, jak utworzyć siatkę widgetów za pomocą klasy QGridLayout. Po więcej in formacji na ten temat zajrzyj do dokumentacji Qt Reference Documentation oraz do wcze śniejszej sekcji z tej godziny, „Zrozumienie menedżerów układu” . Rys. 11.5
Tak identyfikuje się komórki w siatce.
Zagnieżdżone menedżery układu Jeśli znasz język programowania C (lub jakikolwiek inny język programowania), to być może stosowałeś coś takiego jak zagnieżdżanie istniejących cech języka w celu uzyskania pewnej in nej cechy. Na przykład, w języku C bardzo powszechne są zagnieżdżone instrukcje if. Zasadni czo, dzięki umieszczaniu jednych instrukcji if wewnątrz drugich uzyskuje się lepszą kontrolę nad programem. Zagnieżdżanie może być także użyteczne przy pracy z menedżerami układu. Dla przykładu przypuśćmy, że chcesz zmienić program z listingu 11.3 tak, by lewa kolum na miała trzy wiersze, zaś prawa tylko dwa. Dzięki użyciu zagnieżdżonych menedżerów układu można to całkiem prosto uzyskać.
Oczywiście, mógłbyś to także w prosty sposób zrealizować, rozmieszczając widgety ręcznie. Jednak wówczas nie mógłbyś korzystać udogodnień menedżerów układu.
Listing 11.4 przedstawia rozwiązanie tego problemu (na rys. 11.6 pokazano je w postaci graficznej). Listing 11.4 Rozmieszczanie widgetów za pomocą zagnieżdżonych menedżerów układu 1: #include 2: #include 3: #include
194
Godzina 11
4: #include 5: tfinclude
6; 7 class M yW idget: public QWidget 8
{
9 public: MyWidget();
10 11
};
12 13 MyWidget::MyWidget() 14 { 15
setMinimumSize( 200, 200 );
16 17
QPushButton *b1 = new QPushButton( „Przycisk 1", this );
18
b1->setMinimumSize( 200. 100 );
19
b1->setFont( QFont( „Times", 18, QFont::Bold ) );
20 21
QPushButton *b2 = new QPushButton( „Przycisk 2”, this );
22
b2->setMinimumSize( 200, 100 );
23
b2->setFont( QFont( „Times”, 18, QFont::Bold ));
24 25
QPushButton *b3 = new QPushButton( „Przycisk 3", this );
26
b3->setMinimumSize( 200, 100 );
27
b3->setFont( QFont( „Times”, 18, QFont::Bold ));
28 29
QPushButton *b4 = new QPushButton( „Przycisk 4”, this );
30
b4->setMinimumSize( 200, 100 );
31
b4->setFont( QFont( „Tmes", 18, QFont::Bold ));
32 33
QPushButton *b5 = new QPushButton( „Przycisk 5”, this );
34
b5->setMinimumSize( 200, 100 );
35
b5->setFont( QFont( „Times", 18, QFont::Bold ));
36 37
QHBoxLayout *hbox = new QHBoxLayout( this);
38
QVBoxLayout *vbox1 = new QVBoxLayout();
39
QVBoxLayout *vbox2 = new QVBoxLayout();
40 41 42
hbox->addLayout( vbox1 ); hbox->addLayout( vbox2 );
43 44
vbox1->addWidget( b1 );
45
vbox1->addWidget( b2 );
46
vbox1->addWidget( b3 );
47 48
vbox2->addWidget( b4 );
Używanie menedżerów układu
49:
195
vbox2->addWidget( b5 );
50: } 51: 52: int main(int argc, char **argv ); 53: { 54:
QApplication a( argc, argv );
55:
MyWidget w;
56:
w.setGeometry( 100, 100, 200, 200 );
57:
a.setMainWidget( &w );
58:
w.show();
59:
return a.exec();
60: }
Rys. U .6 Przyciski zostały rozmie szczone przy użyciu za gnieżdżonych menedżerów układu.
Część kodu z listingu 11.4 prawdopodobnie jest dla Ciebie czymś nowym. Nie jest to je d nak kod trudny do zrozumienia. W liniach 37, 38 i 39 tworzone są trzy menedżery układu - dwa QVBoxLayout (vbox1 i vbox2) oraz jeden QHBoxLayout (hbox). Dla obiektów QVBoxLayout nie podaje się widgetów macierzystych (wyjaśniają to linie 41 i 42). W liniach tych te dwa obiekty QVBoxLayout są wstawiane do menedżera układu QHBoxLayout; w ten sposób vboxl i vbox2 stają się widgetami potomnymi hbox. Zauważmy, że do tego celu nie jest wykorzystywana funkcja QLayout::addWidget(), tylko funkcja QLayout::addLayout(). W li niach 44—49, do vbox1 i vbox2 wstawianych jest pięć obiektów QPushButton.
Do dyspozycji masz parę naprawdę użytecznych funkcji, pozwalających rozmieszczać widgety dynamicznie, w zależności od wielkości ekranu i okna: • Wywołaj QApplication::desktop()->width() i QApplication::desktop()->height(), aby pobrać wysokość i szerokość ekranu, na którym aktualnie jest uruchomiony program, • Z konstruktora swojej klasy wywołaj this->height() i this->width(), aby pobrać sze rokość i wysokość swojego widgetu (najprawdopodobniej głównego okna).
Godzina 11
196
Na rys. 11.7 przedstawiono graficzny schemat programu z listingu 11.4. Rys. 11.7
HBOX
Tak z o rg a n iz o w a n e s ą m e n e c lż e iy u k ła d u w p r o g r a m ie z l i s t i n
VBOXl
VBOX2
g u I I . 4.
BI B4
B2 B5 B3
Praktyczny przykład Poprzednie przykłady użycia obiektów OPushButton są dobre do rozpoczęcia pracy z mene dżerami układu. Jednak Twoje prawdziwe programy będą najprawdopodobniej zawierać więcej niż tylko kilka przycisków; prawdopodobnie będą w nich obecne także inne widgety. Tak więc przyjrzymy się teraz bardziej realistycznemu programowi przykładowemu. Kod źródłowy tego programu przedstawiono na listingu 11.5. Listing 11.5 Praktyczny przykład z użyciem menedżerów układu 1: #include 2: #include 3: #include 4: #include 5: #include 6: #include 7: #include 8: #include 9: #include
10 : 11: class PrPrzyklad : public OWidget
12 : { 13: public:
Używanie menedżerów układu
14:
PrPrzyklad{);
15:
~PrPrzyklad();
197
16:}; 17: 18: PrPrzyklad::PrPrzyklad() 19: { 20: 21 :
QVBoxLayout ‘ zewnUklad = new QVBoxLayoutj this, 5 );
22:
QMenuBar ‘ pasekmenu = new QMenuBar( this );
23:
pasekmenu->setSeparator( QM enuBar::lnW indowsStyle );
24:
QPopupMenu* rozwijane;
25:
rozwijane = new QPopupMenu;
26:
rozwijane->insertltem( „&W yjście” , qApp, SLOT(quit()) );
27:
pasekmenu->lnsert!tem( „&Plik”, rozwijane );
28: 29:
zewnUklad->setMenuBar( pasekmenu );
30: 31:
QHBoxLayout ‘ przyciski = new QHBoxLayout( zew nllklad );
32:
int i;
33: 34:
for ( i = 1; i addW idget( przyc );
47:
przyc = new QPushButton( „Przycisk 6", this );
48:
przyciski2->addW idget( przyc );
49:
przyciski2->addStretch( 10 );
50: 51:
QMultiLineEdit ‘ duzyW idget = new QMultiLineEdit( this );
52:
duzyWidget->setText( „Ten widget otrzyma całą pozostałą przestrzeń” );
53:
duzyW idget->setFrameStyle( QFrame::Panel | QFrame::Plain );
54:
zewnUklad->addW idget( du zyW id g e t);
55: 56:
const int liczWrs = 3:
57:
const int kolEtykiety = 0:
58:
const int kolLined = 1;
198
Godzina 11
59:
const int kolMulti = 2;
60: 61: 62:
QGridLayout ‘ siatka = new QGridLayout( zew nllklad, 0, 0, 10 ); int wiersz;
63: 64:
for{ wiersz = 0; wiersz < ticzWrs; wiersz++ )
65:
{
66:
Q LineEdit ‘ ed = new QLineEdit( this );
67:
siatka->addW idget( ed, wiersz, kolLined );
68:
69:
QLabel ‘ etykieta = new QLabel( this );
70:
QString s;
71:
s.sprintf( „Linia &%d", wiersz+1 );
72:
etykieta->setText( s );
73:
siatka->addW idget( etykieta, wiersz, kolEtykiety );
74:
etykieta->setBuddy{ ed );
75:
}
76: 77:
QMultiLineEdit *med = new QMultiLineEdit( this );
78:
siatka->addMultiCellW idget( med, 0, -1, kolMulti, kolMulti );
79:
siatka->setColStretch( kolLined. 10 );
80:
siatka->setColStretch( kolMulti, 20 );
81: 82:
QLabel ’ ps = new QLabel( this );
83:
ps->setText(„Przypuśćmy, że to jest pasek stanu”);
84:
ps->setFrameStyle( QFrame::Panel | QFrame::Sunken );
85:
ps->setFixedHeight( ps->sizeHint().height() );
86:
ps->setAlignment( AlignVCenter | AlignLeft ); used
87: 88:
zewnUklad->addW idget{ ps );
89: } 90: 91: PrPrzyklad::-PrPrzyklad() 92: { 93:
// W szystkie wtdgety potomne są usuwane przez Qt
94: } 95: 96: int main( int argc, char “ argv ); 97: { 98:
QApplication a( argc, argv );
99:
PrPrzyklad ‘ w = new PrPrzyklad;
100:
a.setMainW idget(w);
101:
w->show();
102:
return a.exec();
1 0 3 :}
Używanie menedżerów układu
199
Polecam Ci dogłębne przestudiowanie tego kodu. Nie wahaj się przy tym zaglądać do do kumentacji Qt Reference Documentation, ilekroć napotkasz coś, czego jeszcze nie znasz. Zwróć uwagę, że nie wszystkie widgety w tym przykładzie mają taki sam współczynnik „rozciągnięcia" (ang. stretch). Oznacza to, że są one różnie przeskalowywane, zależnie od posiadanego współczynnika rozciągnięcia. Na przykład, widget klasy Q M ultiLineEdit, duzyWidget, otrzymuje całą nową wolną przestrzeń w pionie, podczas gdy wszystkie inne w id gety współdzielą nową przestrzeń w poziomie. Wizualne objaśnienie programu z listingu 11.5 znajdziesz na schemacie przedstawionym na rys. 11.8, zaś na rys. 11.9 pokazano zdję cie ekranu przestawiające ten program w akcji.
zewn. U kład
Rys. 11.8 Schemat przedstaw iający sposób organizacji me nedżerów układu iv pro gram ie z listingu ¡1.5.
przyciski przyc
przyc
przyc
przyc
przyc
przyciski 2 przyc
przyc
duży. W idget siatka ety k ieta
ed
etyk ieta
ed
ety k ieta |
ed
med
|)S
Rys. 11.9 Rezultat wykonania programu z listingu 11.5. Jak widać, menedżery układu potrafią dużo więcej poza roz mieszczaniem prostych przycisków.
200
Godzina 11
To by było wszystko, jeśli chodzi o ten przykład. Wiesz już teraz, jak funkcjonują zagnież dżone menedżery układu. Liczba kombinacji związanych z łączeniem różnych m enedże rów układu dla celów różnych zastosowań jest nieograniczona. W przypadku niektórych zadań nawet zagnieżdżone menedżery układu mogą okazać się niewystarczające. Wtedy do wyboru masz dwie możliwości: Możesz utworzyć układ ręczny (opisany w sekcji „Tworzenie układów ręcznych" w tej lekcji) lub możesz utworzyć swój własny, niestandardowy menedżer układu. Jest to opisane w dokumen tacji Qt Reference Documentation, w pliku customlayout.htm!.
Podsumowanie Menedżery układu są bardzo ważną częścią biblioteki Qt. W wielu przypadkach użycie menedżerów układu zamiast układu ręcznego pozwoli Ci zaoszczędzić godziny pracy. M o że Ci się wydawać, ze łatwiej będzie Ci trzymać się swoich zwykłych (i bardziej czaso chłonnych) metod rozmieszczania widgetów, ale powinieneś jednak sprawiedliwie dać szansę również menedżerom układu. Oczywiście, w lekcji tej nie omówiliśmy wszystkich aspektów dotyczących menedżerów układu. Wyczerpującym źródłem informacji na ten temat jest dokumentacja Qt Reference Documentation. Zajrzyj tam po dodatkowe informacje. (Znajdziesz tam wiele przydatnych funkcji, o których nie wspominaliśmy w tej lekcji.)
Pytania i odpowiedzi Czy jest jakaś różnica w sposobie używania m enedżerów układu m iędzy wersjami bibliotek Qt 2.x a Qt 1.4x? Właściwie tak. W starej wersji biblioteki Qt - 1.4x - aby aktywować menedżera układu, należało wywołać funkcję Q Layout::Activate(). Tworzę właśnie bardzo szczególny układ. M en ed żety układu po prostu nie są w stanie zro bić tego, czego od nich oczekuję. Co mam zro bić? Masz dwie możliwości: Możesz albo utworzyć swój własny menedżer układu - tworząc nową klasę w oparciu o klasę QLayout - albo przeimplementować funkcję Q W idget::ResizeEvent(). Obydw a z tych zadań są opisane w dokumentacji Qt Reference D ocum enta tion. Nad jakim i w idgetam i Qt mogą spraw ow ać kontrolę m enedżery układu? Menedżery układu m ogą sprawować kontrolę nad wszystkimi widgetami Qt. W tej lek cji używaliśmy głównie widgetów QPushButton ze względów przejrzystości. Pamiętaj tyl ko o użyciu właściwej funkcji, gdy będziesz wstawiać dany widget do menedżera ukła du.
Używanie m enedżerów układu
201
Warsztaty Zachęcam y Cię do przerobienia poniższych pytań i ćwiczeń. Pomogą Ci one utrwalić so bie zdobytą w tej lekcji wiedzę. Przerobienie poniższych pytań pozwoli Ci sprawdzić, czy dobrze rozumiesz, w jaki sposób funkcjonują menedżery układu.
Quiz 1. Co to jest menedżer układu? 2. W jaki sposób menedżery układu m ogą pomóc C\ w pracy? 3. W jaki sposób m enedżer układu QVBoxLayout organizuje swoje widgety potomne? 4. W ja k i s p o s ó b m e n e d ż e r u k ła d u QHBoxLayout o rg a n iz u je s w o je w id g e ty p o to m n e ? 5. W jaki sposób m enedżer układu QGridLayout organizuje swoje widgety potomne? 6 . Jakie dwie liczby reprezentują lewy górny widgei w menedżerze układu QGridLayout? 7. Kiedy powinieneś użyć zagnieżdżonycli m enedżerów układu? 8 . Kiedy m usisz wywołać funkcję Q Layout::Activate()?
Ćwiczenia 1. Zmień program z listingu 11.2 w taki sposób, by przyciski rozmieszczane były w wier szu, a nie w kolumnie. (Nie wolno Ci zmienić więcej niż dwie litery.) 2. Napisz program, który przy użyciu menedżera układu Q G ridLayout organizuje sześć przy cisków w dwóch wierszach i trzech kolumnach. 3. Napisz program wykorzystujący zagnieżdżone menedżery układu. Powinien on umie ścić pięć przycisków w trzech wierszach i dwóch kolumnach. Wiersze pierwszy i trzeci mają zawierać po dwa przyciski, podczas gdy wiersz drugi (środkowy ) ma zawierać tyl ko jeden.
—«a»
G
o d z in a
12
Praca z plikami i katalogami Czy kiedykolw iek zastanaw iałeś się nad tym, jakie faktycznie znaczenie m ają w k o m p u te rze pliki i katalogi? Bez tych dwóch elem entów nie byłbyś w stanie przechow ać niczego w sw oim kom puterze, a on sam nie byłby naw et w połowie tak użyteczny, ja k je st dzisiaj. M oże to zabrzm i głupio, ale napraw dę był taki okres, kiedy kom putery nie posiadały p o zornie nieograniczonej przestrzeni do zapisu informacji (tak ja k to jest w przypadku d z i siejszych kom puterów ). W tam tych czasach przechow yw anie informacji po w yłączeniu kom putera było zaw sze problem em , który ludzie usilnie starali się rozwiązać. Na szczęście nie taki je st stan dzisiejszej techniki. Dlatego też praw dopodobnie b ezpiecz nie będzie przyjąć, że m asz na sw oim dysku tw ardym przynajmniej kilka bajtów w olnych do celów naszych zajęć. W niniejszej lekcji dow iesz się, w jaki sposób w ykorzystać dysk tw ardy (znany także jak o p a m ięć w tórna) do zapisyw ania i odczytyw ania informacji. Innym i słowy, dow iesz się, ja k pracow ać z plikam i i katalogami. Jest to ważna kwestia, która będzie się pojaw iać za każdym razem, gdy nie będziesz chciał, by po wyjściu z program u i/lub w yłączeniu k o m putera Twoje inform acje bezpow rotnie znikały.
Godzina 12
204
Możliwe, że już wcześniej pracowałeś z plikami i katalogami z poziomu programu w C, a jeśli tak, to najprawdopodobniej korzystałeś z funkcji operujących na plikach i katalo gach, specyficznych dla swojego systemu operacyjnego. Jeśli jednak będziesz tak robić. Twoje programy w ogóle me będą przenośne; ciężko będzie ich użyć na platformach in nych niż Twoja. Z drugiej strony, jeśli użyjesz klas Qt, Twoje programy będą działać na wszystkich innych platformach z zainstalowaną biblioteką Qt. Co więcej, nawet jeśli prze nośność nie jest (i nigdy nie będzie) dla Ciebie ważną kwestią, użycie klas Qt ułatwi Ci pracę z plikami i katalogami.
Czytanie plików przy użyciu klas Qt Chyba najprostszą z operacji systemu plików, jaką można wykonać, jest czytanie pliku. Je śli na przykład chcesz wyświetlać użytkownikom zawartość pliku pomocy, to zamiast wszywać cały tekst pomocy w programie wygodniej będzie umieścić ten tekst w pliku. Prześledzimy teraz przykład pokazujący, w jaki sposób można to zrealizować. Użyjemy tu klas Qt w celu otwarcia pliku README dostarczanego w dystrybucji Qt, utworzymy do nie go strumień tekstowy, a następnie wyświetlimy jego zawartość w obiekcie QMultiLineEdit. Program ten przedstawiono na listingu 12.1.
Listing 12.1 Czytanie pliku tekstowego i wyświetlanie jego zawartości na ekranie 1: #include 2: #include 3: #include 4: #include 5: #include 6: #include 7: 8: class MyMainWindow : public OWidget
9: { 10: public: 11:
MyMainWindow();
12: private: 13:
OMultiLineEdit *medit;
14:}; 15: 16: MyMainWindow::MyMainWindow() 17: { 18:
setGeometry( 100, 100, 480, 400 );
19: 20: 21:
II Utwórz obiekt OMultiLineEdit, w którym // wyświetlimy zawartość pliku tekstowego:
Praca z plikami i katalogami
22:
medit = new QMultiLineEdit( this );
23:
medit->setGeometry( 10, 10, 460, 380 );
24:
medit->setReadOnly( TRUE );
205
25: 26: 27: 28:
II Tutaj przypisujemy plik README // na obiekt mojPlik. QFile mojPlik( ,,/usr/local/qt/README" );
29: 30:
// Ustaw tryb na tylko odczyt:
31: 32:
mojP!ik.open( lO R e a d O n ly );
33:
II Utwórz strumień tekstowy dla obiektu QFile: QTextStream mojStrumien( &mojPlik );
34: 35: 36:
// Utwórz obiekt QString i przy użyciu strumienia
37:
U tekstowego wczytaj do niego zawartość pliku: QString mojTekst;
38: 39: 40:
// Dopóki nie napotkamy końca pliku,
41: 42:
// wczytuj tekst po jednej linii naraz: while( mojStrumien.atEnd() == 0 )
43:
{
44:
// Wczytaj jedną linię z pliku:
45:
mojTekst = mojStrumien.readLine{);
46: 47:
II Wstaw tę linię do II obiektu QMultiLineEdit: medit->insertLine( m ojTekst);
48: 49: 50:
}
51: 52:
// Zamknij połączenie z plikiem:
53: 54: }
mojPlik.close();
55: 56: void main( int argc, char **argv ) 57: { 58:
QApplication a(argc, argv);
59:
MyMainWindow w;
60:
a.setMainWidget( &w );
61:
w.showQ;
62:
a.exec();
63: }
W programie powyższym stosowany jest standardowy schemat odczytywania plików. Naj pierw tworzony jest obiekt QFile (linia 28), który będzie reprezentował plik. Następnie usta-
206
Godzina 12
wiany jest tryb (w tym przypadku tryb tylko do odczytu) obiektu Q File (linia 31). Dalej two rzony jest obiekt klasy Q TextS tream (m ojS trum ien) (linia 34). Obiekt ten będzie czytał tekst z pliku. Następnie rozpoczyna się pętla while (linia 42), w której wczytywane są z pliku i wstawiane do obiektu C łM ultiLineE dit kolejne linie tekstu. Kiedy osiągnięty zostanie koniec pliku, pętla w hile zatrzyma się. Na koniec, poprzez wy wołanie funkcji Q F ile ::clo se () (linia 53), zamykane jest połączenie z plikiem.
Jeśli kiedykolwiek miałeś problemy z otwarciem pliku, to możliwe, że próbowałeś otwie rać go w trybie, do którego nie masz praw dostępu. Jeśli w powyższym przykładzie nie ustawisz trybu na tylko do odczytu (read-only), to plik najprawdopodobniej się nie otwo rzy, ponieważ domyślny tryb otwarcia daje Ci więcej praw dostępu niż faktycznie masz w systemie. Problem ten nie powinien jednak pojawiać się często w Windows 95 i 98, ponieważ sy stem ten nie posiada tak rygorystycznych praw dostępu dla plików.
W powyższym przykładzie otwierany jest plik tekstowy. Możliwe jednak, że kiedyś bę dziesz potrzebował otworzyć plik binarny. W takim przypadku, zamiast QTextStream powinieneś użyć klasy ODataStream. Jeśli do zapisywania plików binarnych użyjesz klasy ODataStream, pliki te będą prze nośne pomiędzy wszystkimi platformami z Qt!
Rys. 12.1 przedstawia ten program w akcji. Rys. 12.1 Obiekt QMulliLineEdit wyświetlający plik tekstowy.
Q T F R E E EDITIO N Z 0 2 S O U R C E C O D E DlSTRlBuTiON
Tbl* n um
s? i h t Qt Fr®« EdWton
2 C.2.
V sy u?« the Qt F ree Edition tor loffwar# se v ato p tfa n t fr** of on«y rf y c e Ff** (rfc»n~p^po#t