Cyfroteka.pl

klikaj i czytaj online

Cyfro
Czytomierz
00085 006755 13591669 na godz. na dobę w sumie
Biblioteki Qt. Zaawansowane programowanie przy użyciu C++ - książka
Biblioteki Qt. Zaawansowane programowanie przy użyciu C++ - książka
Autor: Liczba stron: 520
Wydawca: Helion Język publikacji: polski
ISBN: 978-83-246-8233-1 Data wydania:
Lektor:
Kategoria: ebooki >> komputery i informatyka >> programowanie >> inne - programowanie
Porównaj ceny (książka, ebook, audiobook).

Odkryj tajemnice biblioteki Qt!

Qt to popularny zestaw bibliotek pozwalający na tworzenie atrakcyjnego interfejsu użytkownika dla różnych platform, w tym dla systemów: Windows, Mac OS X i Linux. Pierwsza wersja ukazała się w 1992 roku i od tego czasu jest intensywnie rozwijana. Za pomocą najnowszej wersji Qt można tworzyć aplikacje internetowe i mobilne. Zakres jej możliwości jest tak szeroki, że nawet doświadczeni programiści wykorzystują zaledwie ich ułamek. To może się zmienić dzięki tej książce!

W trakcie lektury odkryjesz funkcje i możliwości, z których istnienia nie zdawałeś sobie sprawy. Ponadto nauczysz się pisać wydajne programy wielowątkowe, korzystać z silnika WebKit oraz współpracować z biblioteką Phonon. Dowiesz się również, jak sprawnie przy użyciu Qt tworzyć sformatowane dokumenty, a następnie eksportować je do różnych formatów (między innymi PDF, HTML i SVG). W książce znajdziesz wiele przykładów kodu, który został przetestowany przy użyciu Qt 4.6 zarówno na platformie Windows, jak i MacOS X oraz Linux. Wstęp do książki został napisany przez samego współtwórcę Qt - Eirika ChambeEnga. Sięgnij po doskonałe źródło informacji dla programistów!

Dzięki tej książce:

Wykorzystaj zaawansowane funkcje Qt!

Znajdź podobne książki Ostatnio czytane w tej kategorii

Darmowy fragment publikacji:

Tytuł oryginału: Advanced Qt Programming: Creating Great Software with C++ and Qt 4 Tłumaczenie: Radosław Meryk ISBN: 978-83-246-8233-1 Authorized translation from the English language edition, entitled: ADVANCED QT PROGRAMMING: CREATING GREAT SOFTWARE WITH C++ AND QT 4; ISBN 0321635906; by Mark Summerfield; published by Pearson Education, Inc; publishing as Prentice Hall. Copyright © 2011 Qtrac Ltd. All rights reserved. No part of this book may be reproduced or transmitted in any form or by any means, electronic or mechanical, including photocopying, recording or by any information storage retrieval system, without permission from Pearson Education, Inc. Polish language edition published by HELION S.A., Copyright © 2014. Wszelkie prawa zastrzeżone. Nieautoryzowane rozpowszechnianie całości lub fragmentu niniejszej publikacji w jakiejkolwiek postaci jest zabronione. Wykonywanie kopii metodą kserograficzną, fotograficzną, a także kopiowanie książki na nośniku filmowym, magnetycznym lub innym powoduje naruszenie praw autorskich niniejszej publikacji. Wszystkie znaki występujące w tekście są zastrzeżonymi znakami firmowymi bądź towarowymi ich właścicieli. Wydawnictwo HELION dołożyło wszelkich starań, by zawarte w tej książce informacje były kompletne i rzetelne. Nie bierze jednak żadnej odpowiedzialności ani za ich wykorzystanie, ani za związane z tym ewentualne naruszenie praw patentowych lub autorskich. Wydawnictwo HELION nie ponosi również żadnej odpowiedzialności za ewentualne szkody wynikłe z wykorzystania informacji zawartych w książce. Wydawnictwo HELION ul. Kościuszki 1c, 44-100 GLIWICE tel. 32 231 22 19, 32 230 98 63 e-mail: helion@helion.pl WWW: http://helion.pl (księgarnia internetowa, katalog książek) Pliki z przykładami omawianymi w książce można znaleźć pod adresem: ftp://ftp.helion.pl/przyklady/bibqtc.zip Drogi Czytelniku! Jeżeli chcesz ocenić tę książkę, zajrzyj pod adres http://helion.pl/user/opinie/bibqtc Możesz tam wpisać swoje uwagi, spostrzeżenia, recenzję. Printed in Poland. • Kup książkę • Poleć książkę • Oceń książkę • Księgarnia internetowa • Lubię to! » Nasza społeczność Spis tre(cid:258)ci S(cid:239)owo wst(cid:218)pne ................................................................................................................. 9 Wprowadzenie ............................................................................................................... 11 Rozdzia(cid:239) 1. Aplikacje hybrydowe desktopowo-internetowe .................................................. 17 Wid(cid:285)ety internetowe ................................................................................................... 18 Korzystanie z WebKit ................................................................................................. 32 Generyczny komponent przegl(cid:200)darki internetowej ..................................................... 33 Tworzenie aplikacji specyficznych dla witryny WWW ................................................ 41 Osadzanie wid(cid:285)etów Qt na stronach WWW .............................................................. 54 Rozdzia(cid:239) 2. Audio i wideo ................................................................................................ 63 Korzystanie z klas QSound i QMovie ............................................................................. 64 Framework obs(cid:239)ugi multimediów Phonon ...................................................................... 70 Odtwarzanie muzyki .............................................................................................. 74 Odtwarzanie wideo ............................................................................................... 89 Rozdzia(cid:239) 3. Modele tabel model-widok .............................................................................. 97 Architektura model-widok frameworka Qt ..................................................................... 98 Wykorzystanie modeli QStandardItemModel dla tabel .................................................. 100 Zmienianie modelu tabeli za po(cid:258)rednictwem interfejsu u(cid:285)ytkownika .......................... 101 Podklasa QStandardItemModel dla tabel ............................................................... 112 Model QSortFilterProxyModel do filtrowania duplikatów .......................................... 116 Model QSortFilterProxyModel do filtrowania po(cid:285)(cid:200)danych wierszy .............................. 118 Tworzenie w(cid:239)asnych modeli tabel ............................................................................... 122 Zmienianie modelu tabeli za po(cid:258)rednictwem interfejsu u(cid:285)ytkownika .......................... 122 Niestandardowa podklasa QAbstractTableModel dla tabel ....................................... 125 Rozdzia(cid:239) 4. Modele drzew w architekturze model-widok ................................................... 139 Wykorzystanie klasy QStandardItemModel dla drzew ................................................... 141 Zmienianie modelu drzewa za po(cid:258)rednictwem interfejsu u(cid:285)ytkownika ........................ 142 Podklasa QStandardItem dla elementów drzewa ..................................................... 151 Podklasa QStandardItemModel dla drzew .............................................................. 152 Tworzenie niestandardowych modeli drzew ................................................................. 160 Zmiana modelu drzewa za pomoc(cid:200) interfejsu u(cid:285)ytkownika ...................................... 161 Niestandardowa klasa opisuj(cid:200)ca element drzewa ................................................... 165 Niestandardowa podklasa klasy QAbstractItemModel dla drzew ............................... 168 Kup książkęPoleć książkę 6 Spis tre(cid:258) ci Rozdzia(cid:239) 5. Delegaty w architekturze model-widok ...........................................................193 Edytory specyficzne dla typów danych .........................................................................194 Delegaty specyficzne dla typów danych .......................................................................196 Delegat tylko do odczytu dla kolumn lub wierszy .....................................................197 Delegat dla kolumn lub wierszy, które mo(cid:285)na edytowa(cid:202) ...........................................201 Delegaty specyficzne dla modelu ................................................................................208 Rozdzia(cid:239) 6. Widoki w architekturze model-widok ..............................................................215 Podklasy klasy QAbstractItemView ..............................................................................216 Widoki wizualizacji specyficzne dla modelu .................................................................232 Wid(cid:285)et wizualizatora ............................................................................................233 Zagregowany wid(cid:285)et nag(cid:239)ówka w wizualizatorze ......................................................239 Zagregowany wid(cid:285)et widoku w wizualizatorze .........................................................243 Rozdzia(cid:239) 7. Wielow(cid:200)tkowo(cid:258)(cid:202) z wykorzystaniem przestrzeni nazw QtConcurrent ..................253 Uruchamianie funkcji w w(cid:200)tkach ................................................................................256 Zastosowanie metody QtConcurrent::run() ..............................................................260 Wykorzystanie podklasy klasy QRunnable ...............................................................265 Filtrowanie i mapowanie w w(cid:200)tkach ...........................................................................268 Wykorzystanie funkcji przestrzeni nazw QtConcurrent do filtrowania ..........................278 Wykorzystanie funkcji przestrzeni nazw QtConcurrent do filtrowania z redukcj(cid:200) ...........285 Wykorzystanie funkcji przestrzeni nazw QtConcurrent do mapowania ........................289 Rozdzia(cid:239) 8. Obs(cid:239)uga wielu w(cid:200)tków z wykorzystaniem klasy QThread ..................................295 Przetwarzanie niezale(cid:285)nych elementów .......................................................................296 Przetwarzanie wspó(cid:239)dzielonych elementów ..................................................................310 Rozdzia(cid:239) 9. Tworzenie edytorów tekstu sformatowanego ...................................................325 Klasa QTextDocument — wprowadzenie .....................................................................326 Tworzenie w(cid:239)asnych edytorów tekstu ...........................................................................328 Uzupe(cid:239)nianie w polach tekstowych oraz polach kombi .............................................329 Uzupe(cid:239)nianie i pod(cid:258)wietlanie sk(cid:239)adni dla edytorów tekstu .........................................330 Jednowierszowy edytor sformatowanego tekstu ............................................................350 Wielowierszowy edytor sformatowanego tekstu .............................................................361 Rozdzia(cid:239) 10. Tworzenie sformatowanych dokumentów .....................................................367 Jako(cid:258)(cid:202) obiektu QTextDocument wyeksportowanego do pliku ..........................................369 Tworzenie dokumentów QTextDocument .....................................................................372 Tworzenie dokumentów QTextDocument za pomoc(cid:200) HTML ......................................373 Tworzenie dokumentów QTextDocument za pomoc(cid:200) obiektów klasy QTextCursor ........375 Eksportowanie i drukowanie dokumentów ...................................................................379 Eksportowanie dokumentów QTextDocument ..........................................................380 Drukowanie i przegl(cid:200)danie dokumentów QTextDocument .........................................384 Rysowanie stron .......................................................................................................387 Rysowanie dokumentów PDF lub PostScript ...........................................................394 Rysowanie dokumentów SVG ................................................................................395 Rysowanie dokumentów z grafik(cid:200) rastrow(cid:200) .............................................................395 Rozdzia(cid:239) 11. Tworzenie okien w architekturze grafika-widok .............................................397 Architektura grafika-widok .........................................................................................398 Wid(cid:285)ety i uk(cid:239)ad w architekturze grafika-widok ..............................................................401 Wprowadzenie do elementów graficznych ....................................................................407 Kup książkęPoleć książkę Spis tre(cid:258) ci 7 Rozdzia(cid:239) 12. Tworzenie scen w architekturze grafika-widok .............................................. 417 Sceny, elementy i akcje ............................................................................................ 419 Tworzenie g(cid:239)ównego okna .................................................................................... 420 Zapisywanie, (cid:239)adowanie, drukowanie i eksportowanie scen ...................................... 423 Wykonywanie operacji na elementach graficznych .................................................. 431 Ulepszanie widoku QGraphicsView ............................................................................ 447 Tworzenie przyborników w postaci wid(cid:285)etów doku ....................................................... 448 Tworzenie w(cid:239)asnych elementów graficznych ................................................................ 454 Ulepszanie klasy QGraphicsTextItem ..................................................................... 455 Ulepszanie istniej(cid:200)cych elementów graficznych ...................................................... 463 Tworzenie w(cid:239)asnych elementów graficznych od podstaw ......................................... 466 Rozdzia(cid:239) 13. Frameworki obs(cid:239)ugi animacji i maszyn stanów ............................................. 475 Wprowadzenie do frameworka animacji ...................................................................... 476 Wprowadzenie do frameworka maszyny stanów .......................................................... 480 Po(cid:239)(cid:200)czenie animacji z maszynami stanów ................................................................... 487 Epilog .......................................................................................................................... 497 Wybrana bibliografia ..................................................................................................... 501 O autorze ..................................................................................................................... 505 Skorowidz .................................................................................................................... 507 Kup książkęPoleć książkę 8 Spis tre(cid:258) ci Kup książkęPoleć książkę ROZDZIA(cid:146)11 Tworzenie okien w architekturze grafika-widok W tym rozdziale: (cid:120) Architektura grafika-widok (cid:120) Widżety i układ w architekturze grafika-widok (cid:120) Wprowadzenie do elementów graficznych Poprzez utworzenie własnej implementacji procedury obsługi paintEvent() podklasy klasy QWidget i zastosowanie klasy QPainter możemy narysować wszystko, co chcemy. Metoda ta idealnie nadaje się do rysowania własnych widżetów, ale nie jest wygodna, gdybyśmy chcieli rysować wiele pojedynczych elementów, zwłaszcza gdyby zależało nam na zapewnieniu użytkownikom możliwości interakcji z elementami. W przeszłości nie- którzy programiści tworzyli na przykład aplikacje graficzne, korzystając dosłownie z tysięcy własnych widżetów spełniających funkcję elementów graficznych. Choć rysowanie wi- dżetów przebiega bardzo szybko, obsługa jednokrotnego kliknięcia myszą w takich sytu- acjach mogła z łatwością zużyć prawie całą moc obliczeniową procesora. Na szczęście w wersji 4.2 frameworka Qt wprowadzono architekturę grafika-widok, która doskonale wypełnia potrzeby wysokowydajnego rysowania i interakcji na poziomie elementów. Chociaż architektura grafika-widok pierwotnie była pomyślana jako następca klasy QCanvas z frameworka Qt w wersji 3., funkcjonalność architektury grafika-widok Qt w wersji 4. znacznie wykracza poza funkcjonalność klasy QCanvas. W rzeczywistości w nie- których aplikacjach obiekt QGraphicsView odgrywa rolę centralnego widżetu okna, w któ- rym są umieszczone wszystkie inne widżety. W ten sposób powstaje interfejs użytkownika wewnątrz widoku w postaci własnych elementów graficznych. Pierwszy podrozdział tego rozdziału rozpoczniemy od zwięzłego omówienia archi- tektury grafika-widok. Zamieścimy również ramkę opisującą znaczące zmiany wprowa- dzone w Qt 4.6. Następnie, w drugim podrozdziale, przeanalizujemy aplikację, w której centralnym widżetem w głównym oknie jest obiekt QGraphicsView zawierający zarówno widżety, jak i konwencjonalne elementy graficzne. Na koniec, w trzecim podrozdziale tego rozdziału, omówimy prostą podklasę klasy QGraphicsItem oraz opiszemy API klasy QGraphicsItem. Kup książkęPoleć książkę 398 Rozdzia(cid:239) 11. Tworzenie okien w architekturze grafika-widok W następnym rozdziale przyjrzymy się konwencjonalnej aplikacji w architekturze grafika-widok — prostemu programowi do rysowania. Omówimy większość klas archi- tektury grafika-widok i zaprezentujemy więcej przykładów tworzenia własnych elemen- tów graficznych. Nawiasem mówiąc, do przykładów przedstawionych w tym i w następ- nym rozdziale wrócimy w rozdziale 13., w którym utworzymy ich zmodyfikowane wersje, korzystające ze specyficznych własności frameworka Qt 4.6. Architektura grafika-widok Podobnie jak w architekturze model-widok frameworka Qt, w architekturze grafika- widok występuje niezwizualizowana klasa służąca do przechowywania danych w postaci modelu (QGraphicsScene) oraz klasa do wizualizacji danych (QGraphicsView). Jeśli jest taka potrzeba, to tę samą scenę można zwizualizować w wielu różnych widokach. Scena graficzna zawiera elementy, które wywodzą się z abstrakcyjnej klasy QGraphicsItem. Począwszy od pojawienia się architektury grafika-widok frameworka Qt po raz pierwszy, deweloperzy podejmowali olbrzymie wysiłki zmierzające do poprawienia za- równo szybkości działania, jak i możliwości tego mechanizmu. Sceny można skalować, obracać i drukować, a renderowanie można realizować za pomocą silnika renderowania frameworka Qt albo za pomocą OpenGL. Architektura pozwala także na tworzenie ani- macji oraz obsługuje technikę „przeciągnij i upuść”. Sceny graficzne można wykorzystywać do prezentowania dowolnej liczby elementów — od zaledwie kilku do dziesiątek tysięcy, a nawet więcej. Framework Qt dostarcza wielu predefiniowanych, gotowych do wykorzystania typów elementów graficznych. Wyszczególniono je na rysunku 11.1. Większość nazw klas nie wymaga dodatkowych objaśnień, ale omówimy kilka spośród tych, które nie są oczywi- ste. Klasa QGraphicsPathItem reprezentuje obiekt klasy QPainterPath — w istocie jest to dowolna figura składająca się z prymitywów, które framework Qt potrafi rysować. Obejmuje to łuki, krzywe Béziera, cięciwy (ang. chords), elipsy, linie, prostokąty i tekst. Klasa QGraphicsSimpleTextItem reprezentuje fragment zwykłego tekstu, natomiast klasa QGraphicsTextItem reprezentuje fragment sformatowanego tekstu frameworka Qt (może on być określony za pomocą HTML — zagadnienia związane z tekstem sformatowanym omawialiśmy w poprzednich dwóch rozdziałach). QGraphicsWidget odgrywa rolę klasy bazowej do tworzenia niestandardowych widżetów przeznaczonych do wykorzystania na scenach graficznych. Istnieje również możliwość osadzania na scenach graficznych stan- dardowych widżetów — pochodnych klasy QWidget — aby to zrobić, należy dodać widżet do obiektu QGraphicsProxyWidget, a następnie dodać widżet proxy do sceny. Używanie widżetów proxy (lub bezpośrednio obiektów QWidget) jest „wolne”, ale to, czy będzie to odczuwalne, zależy od aplikacji1. Klasę QGraphicsWebView wprowadzono w Qt w wersji 4.6. 1 Informacje dotyczące zagadnień związanych z wydajnością używania obiektów QWidget i obiektów proxy na scenach graficznych można znaleźć pod adresem labs.qt.nokia.com/blogs/2010/01/11/qt- graphics-and-performance-the-cost-of-convenience. Kup książkęPoleć książkę Architektura grafika-widok 399 Rysunek 11.1. Hierarchia klasy QGraphicsItem frameworka Qt Klasa ta dostarcza graficznej wersji klasy QWebView, którą omawialiśmy w rozdziale 1., i służy do prezentowania treści z internetu na scenach graficznych. W przypadku scen z małą liczbą elementów możemy skorzystać z obiektów QGraphicsObject wprowadzonych w Qt 4.6. Jeśli chodzi o Qt 4.5 lub wersje wcześniejsze, pod- stawą niestandardowych elementów mogą być zarówno klasa QObject, jak i QGraphicsItem. Powoduje to zwiększenie kosztów związanych z elementem (tzn. elementy zużywają wię- cej pamięci), ale gwarantuje wygodę korzystania z sygnałów i slotów oraz systemu wła- ściwości frameworka Qt. W przypadku scen zawierających bardzo dużo elementów za- zwyczaj lepsze efekty daje skorzystanie z lekkiej klasy QGraphicsItem jako podstawy niestandardowych elementów, natomiast obiekty QGraphicsObject stosuje się tylko w od- niesieniu do elementów mniej licznych. Klasy widoków graficznych w zasadzie są dwuwymiarowe, chociaż każdy element ma współrzędną z, przy czym elementy, które mają większą wartość współrzędnej z, są ry- sowane przed tymi o niższych wartościach współrzędnej z. Wykrywanie kolizji bazuje na pozycjach elementu określonych parą współrzędnych (x, y). Oprócz informacji na temat kolizji scena może poinformować nas, które elementy zawierają konkretny punkt lub znajdują się w danym obszarze oraz które są zaznaczone. Sceny mają również warstwę pierwszego planu, która przydaje się na przykład do narysowania siatki nałożonej na wszystkie elementy na scenie. Mają także warstwę tła rysowaną pod wszystkimi elemen- tami, która jest przydatna do określenia obrazu lub koloru tła. Elementy są albo dziećmi sceny, albo dziećmi innego elementu — tak samo jak w przy- padku zwykłych relacji rodzic-dziecko frameworka Qt. Kiedy do elementu zostaną zasto- sowane przekształcenia, będą one automatycznie zastosowane do wszystkich dzieci ele- mentu — rekurencyjnie, aż do najdalszego potomka. Oznacza to, że jeśli element zostanie przeniesiony — gdy użytkownik na przykład go przeciągnie — to wszystkie jego dzieci (i rekurencyjnie ich dzieci) będą przeciągnięte razem z nim. Aby element potomny igno- Kup książkęPoleć książkę 400 Rozdzia(cid:239) 11. Tworzenie okien w architekturze grafika-widok rował przekształcenia wykonywane na jego rodzicu, można wywołać metodę QGraphics (cid:180)Item::setFlag(QGraphicsItem::ItemIgnoresTransformations). Do innych, częściej uży- wanych flag można zaliczyć te, które włączają możliwości przemieszczania, zaznaczania i nadawania fokusu (wszystkie flagi wyszczególniono w tabeli 11.3). Elementy mogą być również grupowane. W tym celu powinny stać się dziećmi obiektu QGraphicsItemGroup. Jest to bardzo przydatny mechanizm tworzenia doraźnych kolekcji elementów. Klasy widoków graficznych wykorzystują trzy różne systemy współrzędnych, chociaż w praktyce uwzględniamy tylko dwa z nich. Widoki wykorzystują fizyczny układ współ- rzędnych. Sceny korzystają z logicznego układu współrzędnych, który definiujemy po- przez przekazanie do konstruktora obiektu QRectF. Framework Qt automatycznie od- wzorowuje współrzędne sceny na współrzędne widoku. W istocie sceny wykorzystują współrzędne „okien” (logiczne), natomiast widoki używają współrzędnych „wziernika” (fizyczne). Tak więc, gdy pozycjonujemy elementy, rozmieszczamy je w kontekście współrzędnych sceny. Trzeci system współrzędnych jest wykorzystywany przez elemen- ty. Jest to szczególnie wygodne, ponieważ jest to system współrzędnych logicznych, któ- rego centralnym punktem jest punkt o współrzędnych (0, 0). Punkt (0,0) każdego ele- mentu znajduje się w środkowym punkcie elementu na scenie (wyjątkiem są elementy tekstowe, dla których punktem (0,0) jest lewy górny róg tekstu). Oznacza to, że w prak- tyce zawsze możemy rysować elementy względem ich własnego punktu środkowego i nie musimy martwić się wszelkimi transformacjami, które zostały do nich zastosowane przez elementy-rodziców, ponieważ scena zrobi to za nas. Zwróćmy również uwagę na to, że we frameworku Qt współrzędne y wzrastają ku dołowi — na przykład punkt o współrzędnych (5, 8) jest o 6 pikseli powyżej punktu o współrzędnych (5, 14). Relacje zachodzące pomiędzy współrzędnymi sceny a współrzędnymi elementu zaprezentowano na rysunku 11.2. Rysunek 11.2. Elementy graficzne wykorzystują lokalne współrzędne logiczne Pewne elementy architektury grafika-widok frameworka Qt zmieniły się pomiędzy wersjami Qt 4.5 a Qt 4.6. Zestawiono je w ramce „Zmiany działania architektury grafika- widok wprowadzone w Qt 4.6” (patrz strona 402). Kup książkęPoleć książkę Wid(cid:285) ety i uk(cid:239)ad w architekturze grafika-widok 401 Wid(cid:285)ety i uk(cid:239)ad w architekturze grafika-widok W tym punkcie przeanalizujemy aplikację Szalka Petriego (petridish1). Zrzut ekranu z tej aplikacji pokazano na rysunku 11.3. Aplikacja zawiera klasę MainWindow, która dziedziczy po klasie QMainWindow i wykorzystuje obiekt QGraphicsView w roli centralnego widżetu. Szalka Petriego jest aplikacją symulującą komórki — rosną one, jeśli są zbyt zatłoczone, i kurczą się, jeśli są zbyt odizolowane, zbyt zatłoczone albo za duże. Komórki mogą losowo umierać. Nie będziemy mówili zbyt wiele na temat samej symulacji czy też logiki aplikacji, ponieważ tematem tego rozdziału jest architektura grafika-widok frameworka Qt. Rysunek 11.3. Aplikacja Szalka Petriego Aby pokazać, jak można utworzyć główne okno aplikacji na bazie sceny graficznej, poniżej przeanalizujemy właściwe metody głównego okna (lub fragmenty tych metod). Natomiast w następnym punkcie przeanalizujemy elementy Cell (pochodne klasy QGraphicsItem). Skoncentrujemy się na podstawach tworzenia niestandardowych ele- mentów graficznych oraz zaprezentowaniu interfejsu API klasy QGraphicsItem, nato- miast pominiemy nieistotną logikę związaną z symulacją (kod źródłowy aplikacji można znaleźć w podkatalogu petridish1). Aplikacja zawiera przyciski Start, Pauza/Wznów, Stop i Koniec, które pozwalają na sterowanie symulacją. Użytkownik może ustawić początkową liczbę komórek i określić, czy mają być wyświetlane identyfikatory komórek (są one przydatne w przypadku komórek, które bez wyświetlania identyfikatorów byłyby zbyt małe, aby można je było zobaczyć). Pole tekstowe początkowej liczby komórek w czasie działania symulacji jest zablokowane, co widać na zrzucie ekranu. W interfejsie użytkownika wykorzystano kilka obiektów QLCDNumbers, aby pokazać, ile komórek pozostało oraz ile iteracji symulacji wykonano. Kup książkęPoleć książkę 402 Rozdzia(cid:239) 11. Tworzenie okien w architekturze grafika-widok Zmiany dzia(cid:239)ania architektury grafika-widok wprowadzone w Qt 4.6 W klasach architektury grafika-widok wprowadzono znacz(cid:200)ce zmiany pomi(cid:218)dzy wersjami fra- meworka Qt 4.5 i Qt 4.6. W efekcie znacznie poprawi(cid:239)a si(cid:218) wydajno(cid:258)(cid:202). Jedn(cid:200) z konsekwencji tych wprowadzonych „pod mask(cid:200)” zmian by(cid:239)a konieczno(cid:258)(cid:202) dokonania pewnych zmian wi- docznych dla u(cid:285)ytkownika. By(cid:239)o to niezb(cid:218)dne dla osi(cid:200)gni(cid:218)cia najlepszej optymalizacji. Oto naj- wa(cid:285)niejsze zmiany w dzia(cid:239)aniu: (cid:120) Publiczna zmienna klasy QStyleOptionGraphicsItem — exposedRect typu QRectF — zawiera udost(cid:218)pniony prostok(cid:200)t elementu wyra(cid:285)ony we wspó(cid:239)rz(cid:218)dnych elementu. Zmienna ta jest jednak ustawiana tylko dla tych elementów graficznych, dla których ustawiono flag(cid:218) ItemUsesExtendedStyleOption. (cid:120) Zmienne klasy QStyleOptionGraphicsItem — levelOfDetail i matrix — s(cid:200) przestarza- (cid:239)e. Prawid(cid:239)owy sposób uzyskania poziomu szczegó(cid:239)ów w Qt 4.6 bazuje na statycznej metodzie QStyleOptionGraphicsItem::levelOfDetailFromTransform(). (cid:120) Obiekty klasy QGraphicsView nie wywo(cid:239)uj(cid:200) ju(cid:285) metod QGraphicsView::drawItems() i QGraphicsView::drawItem() — o ile nie ustawimy flagi „optymalizacji” QGraphics (cid:180)View::IndirectPainting (co jednak nie jest zalecane). (cid:120) Obiekty klasy QGraphicsItem nie emituj(cid:200) ju(cid:285) sygna(cid:239)u itemChange() w przypadku zmian pozycji i wykonanych przekszta(cid:239)ce(cid:241). Aby uzyska(cid:202) informacje o tych zmianach, nale(cid:285)y ustawi(cid:202) flag(cid:218) QGraphicsItem::ItemSendsGeometryChanges (ta flaga jest ustawiona domy(cid:258)l- nie dla obiektów klasy QGraphicsWidget oraz QGraphicsProxyWidget). (cid:120) Nawet gdy flaga ItemSendsGeometryChanges jest ustawiona, sygna(cid:239) itemChange() w przy- padku wykonanej transformacji jest emitowany tylko wtedy, gdy zostanie wykorzystana metoda setTransform(). Pocz(cid:200)wszy od wydania Qt w wersji 4.7, oczekuje si(cid:218), (cid:285)e je(cid:258)li b(cid:218)dzie ustawiona ta flaga, to sygna(cid:239) itemChange() b(cid:218)dzie tak(cid:285)e wywo(cid:239)any w przypadku wywo(cid:239)ania metod setRotation(), setScale() lub setTransformOriginPoint() (wszyst- kie wprowadzono w Qt 4.6). To, w jakim stopniu — a nawet czy w ogóle — te zmiany wp(cid:239)yn(cid:200) na konkretn(cid:200) aplikacj(cid:218), zale(cid:285)y od tego, z jakich w(cid:239)asno(cid:258)ci architektury grafika-widok korzysta aplikacja. W przypadku przyk(cid:239)adów przedstawionych w tej ksi(cid:200)(cid:285)ce na aplikacj(cid:218) Projektant stron z nast(cid:218)pnego roz- dzia(cid:239)u wp(cid:239)yn(cid:218)(cid:239)a ostatnia zmiana dzia(cid:239)ania z listy zamieszczonej powy(cid:285)ej. Omawianie przykładu rozpoczniemy od analizy konstruktora głównego okna. Na- stępnie przeanalizujemy kilka metod pomocniczych istotnych dla programowania w ar- chitekturze grafika-widok, która jest głównym tematem niniejszego rozdziału. MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), simulationState(Stopped), iterations(0) { scene = new QGraphicsScene(this); scene- setItemIndexMethod(QGraphicsScene::NoIndex); createWidgets(); createProxyWidgets(); createLayout(); createCentralWidget(); createConnections(); Kup książkęPoleć książkę Wid(cid:285) ety i uk(cid:239)ad w architekturze grafika-widok 403 startButton- setFocus(); setWindowTitle(QApplication::applicationName()); } Sposób utworzenia obiektu QGraphicsScene jest dość osobliwy, ponieważ nie podali- śmy wymiarów sceny. Chociaż znamy potrzebną wysokość (musi być wystarczająca do tego, żeby zmieścić szalkę Petriego, plus pewien margines), to szerokość zależy od szero- kości widżetów, dlatego wymiary ustawimy po utworzeniu i rozmieszczeniu widżetów. Kiedy elementy są dodawane, przesuwane bądź usuwane ze sceny, wymagane jest wykonanie obliczeń położenia. Na przykład kiedy dodajemy element w widocznej części sceny, musimy go narysować. Z kolei kiedy widoczny element zostanie przesunięty lub usunięty, trzeba narysować ten fragment sceny, który był zakryty, a teraz jest odkryty. W przypadku scen z dużą liczbą statycznych elementów obliczenia te można znacząco przy- spieszyć poprzez skorzystanie z metody indeksowania QGraphicsScene::BspTreeIndex (algorytm BSP — Binary Space Partitioning); ale w przypadku dynamicznych scen, gdzie wiele elementów jest dodawanych, przesuwanych bądź usuwanych, lepiej wyłączyć in- deksowanie (tak jak zrobiliśmy w tym przykładzie), ponieważ koszty wykorzystania in- deksów są zbyt wysokie w porównaniu z oszczędnościami, jakie one przynoszą. Zgodnie ze stylem kodowania, jaki został przyjęty w całej książce, wywołujemy meto- dy pomocnicze w konstruktorze w celu wykonania większości operacji związanych z ini- cjalizacją widżetu. Ponieważ używamy sceny graficznej jako głównego widżetu głównego okna, wszystkie metody pomocnicze są istotne. W związku z tym pokażemy i omówimy je wszystkie (pomijając w miarę możliwości powtarzające się fragmenty kodu). void MainWindow::createWidgets() { startButton = new QPushButton(tr( St art )); pauseOrResumeButton = new QPushButton(tr( Pa uza )); pauseOrResumeButton- setEnabled(false); stopButton = new QPushButton(tr( Stop )); quitButton = new QPushButton(tr( Koniec )); QString styleSheet( background-color: bisque; ); initialCountLabel = new QLabel(tr( Pocz(cid:200)tkowa liczba: )); initialCountLabel- setStyleSheet(styleSheet); ··· AQP::accelerateWidgets(QList QWidget* () startButton stopButton quitButton initialCountLabel showIdsCheckBox); } Aplikacja wykorzystuje standardowe widżety QWidget. W sposobie ich tworzenia nie ma żadnych niespodzianek. Jedyną niestandardową operacją, którą tu zastosowaliśmy, jest określenie dla widże- tów (z wyjątkiem przycisków) arkusza stylów zapewniającego jednolity kolor tła. Dla przycisków nie określono arkuszy stylów, ponieważ wolimy, aby zachowały one wygląd zgodny z platformą i użytym motywem. Kup książkęPoleć książkę 404 Rozdzia(cid:239) 11. Tworzenie okien w architekturze grafika-widok void MainWindow::createProxyWidgets() { proxyForName[ startButton ] = scene- addWidget(startButton); proxyForName[ pauseOrResumeButton ] = scene- addWidget( pauseOrResumeButton); ··· } Wszystkie widżety muszą być dodane do sceny, ponieważ widok sceny jest central- nym widżetem głównego okna. Z łatwością moglibyśmy zaadaptować inne podejście — na przykład wykorzystać w roli centralnego widżetu obiekt QWidget i przekazać do wi- dżetu obiekt QHBoxLayout. Ten obiekt zawierałby obiekt QVBoxLayout z przyciskami, obiekt QGraphicsView oraz inny obiekt QVBoxLayout z innymi widżetami. Ale żeby poka- zać, że można to zrobić, postanowiliśmy wykorzystać sam obiekt QGraphicsView jako centralny widżet i umieścić w nim wszystkie inne widżety, jak również elementy graficzne. Aby dodać standardowe obiekty QWidget na scenie, należy utworzyć obiekt QGraphicsProxyWidget dla każdego obiektu QWidget i dodać obiekt proxy do sceny. W po- wyższej metodzie skorzystaliśmy z metody QGraphicsScene::addWidget(), która tworzy obiekt QGraphicsProxyWidget reprezentujący widżet przekazany w roli argumentu. Me- toda zwraca wynik w postaci wskaźnika do widżetu proxy. Dla wygody utrzymujemy tablicę asocjacyjną, w której klucze są nazwami widżetu, a jej wartości wskaźnikami na widżety proxy. Każdy z utworzonych widżetów proxy dodajemy do tablicy asocjacyjnej (tablicę deklarujemy w pliku nagłówkowym jako QHash QString, QGraphicsProxyWidget* proxyForName). Po utworzeniu widżetów i ich widżetów proxy możemy rozmieścić je na scenie. Przypomina to korzystanie ze standardowych układów frameworka Qt, z tym że trzeba używać klas sterowania układem specyficznych dla architektury grafika-widok. Metodę createLayout() przeanalizujemy w dwóch częściach. Najpierw omówimy tworzenie ukła- dów, a następnie przyjrzymy się ustawianiu wymiarów sceny. const int DishSize = 350; const int Margin = 20; void MainWindow::createLayout() { QGraphicsLinearLayout *leftLayout = new QGraphicsLinearLayout( Qt::Vertical); leftLayout- addItem(proxyForName[ startButton ]); leftLayout- addItem(proxyForName[ pauseOrResumeButton ]); leftLayout- addItem(proxyForName[ stopButton ]); leftLayout- addItem(proxyForName[ quitButton ]); QGraphicsLinearLayout *rightLayout = new QGraphicsLinearLayout( Qt::Vertical); foreach (const QString name, QStringList() initialCountLabel initialCountSpinBox currentCountLabel currentCountLCD iterationsLabel iterationsLCD Kup książkęPoleć książkę Wid(cid:285) ety i uk(cid:239)ad w architekturze grafika-widok 405 showIdsCheckBox ) rightLayout- addItem(proxyForName[name]); QGraphicsLinearLayout *layout = new QGraphicsLinearLayout; layout- addItem(leftLayout); layout- setItemSpacing(0, DishSize + Margin); layout- addItem(rightLayout); QGraphicsWidget *widget = new QGraphicsWidget; widget- setLayout(layout); scene- addItem(widget); QGraphicsLinearLayout jest klasą sterowania układem architektury grafika-widok będącej odpowiednikiem klasy QBoxLayout, z której wywodzą się klasy QHBoxLayout i QVBoxLayout. Interfejsy API są bardzo podobne. Różnica polega na tym, że zamiast do- dawać widżety za pomocą metody QBoxLayout::addWidget(), korzystamy z metody QGraphicsLinearLayout::addItem(). Ta metoda dodaje do układu obiekt QGraphics (cid:180)LayoutItem (który jest jednym z obiektów QGraphicsWidget — a tym samym obiektem klasy bazowej dla QGraphicsProxyWidget). Istnieje również klasa QGraphicsGridLayout, będąca odpowiednikiem klasy QGridLayout. W Qt w wersji 4.6 wprowadzono klasę QGraphicsAnchorLayout, która implementuje nowe podejście do sterowania układami — takie, którego nie spotykano we wcześniejszych wersjach Qt. Podejście to bazuje na roz- mieszczaniu widżetów względem siebie oraz względem krawędzi i narożników prosto- kąta, które zajmuje układ. W tej metodzie tworzymy trzy obiekty QGraphicsLinearLayout. Pierwszy układ służy do utworzenia pionowej kolumny dla widżetów proxy przycisków z lewej strony, nato- miast drugi do utworzenia pionowej kolumny widżetów proxy po prawej stronie. Trzeci służy do utworzenia ogólnego poziomego układu składającego się z lewej kolumny, odstępu (aby zapewnić miejsce dla właściwej szalki Petriego) oraz prawej kolumny. Układ głównego okna aplikacji schematycznie przedstawiono na rysunku 11.4. Rysunek 11.4. Układ głównego okna aplikacji Szalka Petriego Kup książkęPoleć książkę 406 Rozdzia(cid:239) 11. Tworzenie okien w architekturze grafika-widok Po utworzeniu układów tworzymy nowy „pusty” obiekt QGraphicsWidget. Ta klasa nie ma wizualnej reprezentacji sama w sobie i jest specjalnie zaprojektowana zarówno do odgrywania roli klasy bazowej dla niestandardowych widżetów architektury grafika-widok, jak i do tego celu, do jakiego używamy jej tutaj — jest kontenerem jednego lub większej liczby widżetów-dzieci rozmieszczonych w układzie dokumentu. Po utworzeniu widżetu konfigurujemy ogólny układ okna i dodajemy widżet do sceny. W efekcie wszystkie obiekty zarządzania układem i widżety proxy otrzymują nowego rodzica — na przykład widżety proxy stają się dziećmi sceny (widżety są przyporządkowane do swoich proxy w wywołaniach QGraphicsScene::addWidget()). int width = qRound(layout- preferredWidth()); int height = DishSize + (2 * Margin); setMinimumSize(width, height); scene- setSceneRect(0, 0, width, height); } Scenę ustawiamy na taką szerokość, aby układ wyświetlał się w swojej preferowanej szerokości i wysokości, wystarczającej do tego, by wyświetlić szalkę Petriego, pozosta- wiając pewien margines w pionie. Ustawiamy także minimalny rozmiar głównego okna w taki sposób, by nigdy nie skurczyło się do takich wartości, które nie pozwalają na prawi- dłowe wyświetlanie szalki Petriego i jego widżetów. void MainWindow::createCentralWidget() { dishItem = new QGraphicsEllipseItem; dishItem- setFlags(QGraphicsItem::ItemClipsChildrenToShape); dishItem- setPen(QPen(QColor( brown ), 2.5)); dishItem- setBrush(Qt::white); dishItem- setRect(pauseOrResumeButton- width() + Margin, Margin, DishSize, DishSize); scene- addItem(dishItem); view = new QGraphicsView(scene); view- setRenderHints(QPainter::Antialiasing| QPainter::TextAntialiasing); view- setBackgroundBrush(QColor( bisque )); setCentralWidget(view); } Ta metoda jest wywoływana po utworzeniu sceny i wypełnieniu jej widżetami (a ści- ślej widżetami proxy). Tworzy ona szalkę Petriego i widok, co kończy konfigurację wy- glądu aplikacji. Zaczynamy od utworzenia nowego graficznego elementu elipsy — choć w tym przy- padku będzie to koło, ponieważ ustawiliśmy jego szerokość i wysokość na tę samą wartość. Dla elementu ustawiamy opcję obcinania elementów potomnych. Wszystkie symulowane komórki są tworzone jako dzieci szalki Petriego. To gwarantuje, że wszystkie komórki znajdujące się poza szalką Petriego nie są wyświetlane, a wszystkie komórki, które przekra- Kup książkęPoleć książkę Wprowadzenie do elementów graficznych 407 czają granice naczynia, mają widoczną tylko tę część, która mieści się w naczyniu. Pro- stokąt szalki Petriego ustawiamy w taki sposób, aby jego współrzędna x była równa sze- rokości jednego z przycisków w lewej kolumnie powiększonej o pewien margines, a jego współrzędna y zapewniała niewielki margines nad szalką. Po utworzeniu elementu szalki dodajemy go do sceny. Tworzymy standardowy obiekt QGraphicsView z włączoną opcją antyaliasingu oraz z takim samym kolorem tła, jaki ustawiliśmy w arkuszu stylów dla niektórych widżetów. Następnie ustawiamy go jako centralny widżet głównego okna. Na tym kończymy konfi- gurowanie wyglądu aplikacji. Pod względem struktury używanie architektury grafika-widok do ustawiania widże- tów głównego okna nie różni się zbytnio od bardziej konwencjonalnego podejścia. Jedy- na znacząca różnica polega na tym, że musimy utworzyć i dodać widżety proxy dla wła- ściwych widżetów oraz musimy korzystać ze specyficznych klas zarządzania układem architektury grafika-widok zamiast standardowych klas sterowania układem. Oczywiście gdybyśmy chcieli użyć obiektów wywodzących się z klasy QGraphicsWidget, nie musieli- byśmy tworzyć dla nich widżetów proxy, ponieważ można je bezpośrednio dodawać do sceny (w czasie, kiedy powstawała ta książka, jedyną dostępną podklasą klasy Graphics (cid:180)Widget oprócz klasy QGraphicsProxyWidget była klasa QGraphicsWebView, chociaż bez tru- du moglibyśmy utworzyć własne podklasy klasy QGraphicsWidget, gdybyśmy tego chcieli). void MainWindow::createConnections() { connect(startButton, SIGNAL(clicked()), this, SLOT(start())); connect(pauseOrResumeButton, SIGNAL(clicked()), this, SLOT(pauseOrResume())); connect(stopButton, SIGNAL(clicked()), this, SLOT(stop())); connect(quitButton, SIGNAL(clicked()), this, SLOT(close())); connect(showIdsCheckBox, SIGNAL(toggled(bool)), this, SLOT(showIds(bool))); } Ta metoda jest bardzo podobna do tych, z którymi wielokrotnie spotykaliśmy się we wcześniejszych rozdziałach — zawiera połączenia pomiędzy sygnałami clicked() wi- dżetów (rzeczywistych) a odpowiadającymi im slotami. Nie ma ona znaczenia dla jako takiego programowania w architekturze grafika-widok, ale została tutaj przedstawiona jako kontrast z wersją z Qt 4.6 z przykładu pokazanego w rozdziale 13. Tamta metoda korzysta z obiektu QStateMachine do zarządzania działaniem aplikacji, a dzięki temu zawie- ra mniejszą liczbę slotów i ma prostszą logikę. Wprowadzenie do elementów graficznych Klasa QGraphicsItem jest klasą bazową dla wszystkich elementów graficznych. Chociaż klasa ta zawiera bardzo wiele metod — ponad dwieście w Qt 4.6 — nie można tworzyć jej egzemplarzy, ze względu na istnienie dwóch czysto wirtualnych metod: boundingRect() Kup książkęPoleć książkę 408 Rozdzia(cid:239) 11. Tworzenie okien w architekturze grafika-widok i paint(). Metoda paint() jest odpowiednikiem metody QWidget::paintEvent() i trzeba ją zaimplementować, aby narysować element. Metoda boundingRect() przekazuje do ar- chitektury grafika-widok prostokąt okalający element — jest on wykorzystywany do de- tekcji kolizji oraz do tego, by zapewnić rysowanie elementu tylko wtedy, gdy jest on wi- doczny we wzierniku obiektu QGraphicsView. W przypadku tworzenia nieprostokątnych, niestandardowych elementów graficz- nych, najlepiej zaimplementować również metodę shape(). Metoda ta zwraca obiekt QPainterPath, który dokładnie opisuje obrys elementu. Jest to przydatne do dokładnego wykrywania kolizji oraz wykrywania kliknięć myszą. Istnieje wiele metod wirtualnych, które można zaimplementować włącznie z meto- dami advance(), boundingRect(), collidesWithItem(), collidesWithPath(), contains(), isObscuredBy(), opaqueArea(), paint(), shape() i type(). Wszystkie metody chronione (z wyjątkiem metody prepareGeometryChange()) są również wirtualne, a zatem można utworzyć własną implementację wszystkich procedur obsługi zdarzeń elementów gra- ficznych (włącznie z contextMenuEvent(), keyPressEvent oraz zdarzeniami obsługi myszy). Wszystkie je zwięźle opisano w tabeli 11.1. Aby utworzyć niestandardową figurę, najłatwiej skorzystać ze standardowych podklas klasy QGraphicsItem, takich jak QGraphicsPathItem lub QGraphicsPolygonItem. A jeśli dodatkowo chcemy, aby figura charakteryzowała się własnym zachowaniem, możemy utworzyć podklasę elementu i utworzyć własną implementację niektórych chronionych procedur obsługi zdarzeń, takich jak keyPressEvent() i mousePressEvent(). Jeśli wolimy rysować samodzielnie, możemy bezpośrednio utworzyć podklasę klasy QGraphicsItem i zaimplementować metody boundingRect(), paint() i shape() oraz wszystkie procedury obsługi zdarzeń potrzebne do zapewnienia działań, które nas interesują. Dla wszystkich podklas klasy QGraphicsItem najlepiej zdefiniować typ wyliczeniowy Type oraz własną implementację metody type(). Zagadnienie to omówimy za chwilę. W tym punkcie zwięźle omówimy te aspekty klasy Cell — bezpośredniej podklasy klasy QGraphicsItem — z aplikacji Szalka Petriego, które są związane z programowaniem w architekturze grafika-widok. Rozpoczniemy od definicji w pliku nagłówkowym, ale pominiemy sekcję prywatną. class Cell : public QGraphicsItem { public: enum {Type = UserType + 1}; explicit Cell(int id, QGraphicsItem *parent=0); QRectF boundingRect() const { return m_path.boundingRect(); } QPainterPath shape() const { return m_path; } void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); int type() const { return Type; } ··· }; Kup książkęPoleć książkę Wprowadzenie do elementów graficznych 409 Tabela 11.1. API klasy QGraphicsItem (wybrane metody) Metoda Opis advance() boundingRect() childItems() collidesWithItem(QGraphicsItem *,Qt::ItemSelectionMode) collidesWithPath(QPainterPath, Qt::ItemSelectionMode) collidingItems(Qt::Item (cid:180)SelectionMode) contains(QPointF) ensureVisible() group() hide() isObscuredBy(QGraphicsItem*) isSelected() isVisible() keyPressEvent(QKeyEvent*) mouseDoubleClickEvent(QGraphics (cid:180)SceneMouseEvent*) mouseMoveEvent(QGraphicsScene (cid:180)MouseEvent*) mousePressEvent(QGraphicsScene (cid:180)MouseEvent*) moveBy(qreal, qreal) Należy utworzyć własną implementację, aby wykonywać animacje. Można również stosować inne podejścia (przykłady można znaleźć w rozdziałach 12. i 13.). Własną implementację należy utworzyć w celu uzyskania prostokąta otaczającego element, wyrażonego we współrzędnych elementu — patrz sceneBoundingRect() i shape(). Zwraca listę bezpośrednich potomków elementu (Qt 4.4). Zwraca true, jeśli ten element koliduje z podanym elementem zgodnie z podanym trybem — patrz typ wyliczeniowy Qt::ItemSelectionMode (strona 414). Zwraca true, jeśli ten element koliduje z podaną ścieżką, zgodnie z podanym trybem. Zwraca listę wszystkich elementów, z którymi koliduje ten element, zgodnie z podanym trybem. Zwraca true, jeśli podany punkt należy do elementu. Wymusza od wszystkich widoków QGraphicsView powiązanych ze sceną i zawierających ten element, aby przewinęły się, jeśli zachodzi taka potrzeba, w celu wyświetlenia tego elementu. Zwraca obiekt QGraphicsItemGroup, do którego należy ten element, lub 0, jeśli nie należy on do żadnej grupy. Ukrywa element — patrz show() i setVisible(). Zwraca true, jeśli prostokąt otaczający tego elementu jest całkowicie zasłonięty przez kształt podanego nieprzezroczystego elementu. Zwraca true, jeśli podany element jest zaznaczony. Zwraca true, jeśli ten element jest logicznie widoczny (nawet gdy jest całkowicie zasłonięty albo znajduje się poza wziernikiem widoku). Należy zaimplementować tę metodę w celu obsługi naciśnięć klawiszy na elemencie. Metoda będzie wywołana tylko wtedy, gdy ustawiono flagę ItemIsFocusable. Należy zaimplementować tę metodę w celu obsługi dwukrotnych kliknięć. Należy zaimplementować tę metodę w celu obsługi ruchów myszą. Należy zaimplementować tę metodę w celu obsługi kliknięć przycisku myszy. Przesuwa element o podane wartości w pionie i w poziomie. Kup książkęPoleć książkę 410 Rozdzia(cid:239) 11. Tworzenie okien w architekturze grafika-widok Tabela 11.1. API klasy QGraphicsItem (wybrane metody) — ciąg dalszy Metoda Opis opaqueArea() paint(QPainter*, QStyleOptionGraphicsItem*, QWidget*) parentItem() pos() prepareGeometryChange() resetTransform() rotation() scale() scene() sceneBoundingRect() scenePos() Należy zaimplementować tę metodę w celu uzyskania ścieżki obiektu painter pokazującej miejsca, w których element jest niewidoczny. Ścieżka jest w takiej postaci, w jakiej jest używana w metodzie isObscuredBy(). Należy zaimplementować tę metodę w celu narysowania elementu — patrz boundingRect() i shape(). Zwraca rodzica elementu lub 0. Zwraca pozycję elementu wyrażoną we współrzędnych rodzica, a jeśli element nie ma rodzica — we współrzędnych sceny (patrz scenePos()). Tę metodę trzeba wywołać przed modyfikacją prostokąta otaczającego element. Metoda automatycznie wywoła metodę update(). Resetuje macierz transformacji elementu na macierz tożsamościową. Powoduje to eliminację obrotów, skalowania lub przycinania. Zwraca obrót elementu wyrażony w stopniach (–360.0°, 360.0°). Wartość domyślna wynosi 0.0° (Qt 4.6). Zwraca współczynnik skalowania elementu. Wartość domyślna wynosi 1.0, co oznacza, że element nie jest skalowany (Qt 4.6). Zwraca scenę, do której należy element, lub 0, jeżeli element nie został dodany do sceny. Zwraca prostokąt otaczający elementu wyrażony we współrzędnych sceny — patrz boundingRect(). Zwraca pozycję elementu wyrażoną we współrzędnych sceny — dla elementów bez rodzica wartość jest taka sama jak zwracana przez metodę pos(). setFlag(GraphicsItemFlag,bool) Włącza lub wyłącza flagę w zależności od wartości przekazanego setFlags(GraphicsItemFlags) setGraphicsEffect(QGraphics (cid:180)Effect*) setGroup(QGraphicsItemGroup*) setParentItem(QGraphicsItem*) parametru typu Boolean (domyślnie włączona). Ustawia flagi (z wykorzystaniem operatora OR) — zobacz typ wyliczeniowy QGraphicsItem::GraphicsItemFlag (patrz strona 414). Ustawia podany efekt graficzny dla elementu (usuwając efekty ustawione poprzednio). Dotyczy efektów QGraphicsBlur (cid:180)Effect, QGraphicsDropShadowEffect i QGraphicsOpacityEffect (Qt 4.6). Dodaje ten element do podanej grupy. Ustawia (lub zmienia) rodzica elementu na podany element. Kup książkęPoleć książkę Wprowadzenie do elementów graficznych 411 Tabela 11.1. API klasy QGraphicsItem (wybrane metody) — ciąg dalszy Metoda Opis setPos(QPointF) setRotation(qreal) setScale(qreal) setSelected(bool) setToolTip(QString) setTransform(QTransform, bool) setVisible(bool) setX(qreal) setY(qreal) setZValue(qreal) shape() show() toolTip() transform() type() update() x() y() zValue() Ustawia pozycję elementu wyrażoną we współrzędnych rodzica. Istnieje również przeciążona wersja, która akceptuje dwa argumenty typu qreal. Ustawia obrót elementu na podaną liczbę stopni (–360.0°, 360.0°) (Qt 4.6). Skaluje element. Wartość 1.0 oznacza brak skalowania (Qt 4.6). Zaznacza lub anuluje zaznaczenie elementu w zależności od argumentu typu Boolean. Ustawia tekst wskazówki ekranowej dla elementu. Ustawia macierz transformacji elementu na podaną wartość lub łączy ją z podaną wartością, jeśli argument typu Boolean ma wartość true (Qt 4.3). Istnieje również zupełnie inna metoda setTransformations(). Ukrywa lub pokazuje element w zależności od przekazanego argumentu typu Boolean. Ustawia pozycję x elementu we współrzędnych jego rodzica (Qt 4.6). Ustawia pozycję y elementu we współrzędnych jego rodzica (Qt 4.6). Ustawia wartość współrzędnej z elementu. Należy zaimplementować tę metodę w celu uzyskania ścieżki obiektu painter opisującej dokładny kształt elementu — patrz boundingRect() i paint(). Wyświetla element — patrz hide() i setVisible(). Zwraca wskazówkę ekranową powiązaną z elementem. Zwraca macierz transformacji elementu. Istnieje również metoda transformations(). Zwraca właściwość QGraphicsItem::Type elementu w postaci wartości int. Niestandardowe podklasy klasy QGraphicsItem powinny zawierać własną implementację tej metody oraz definicję typu wyliczeniowego Type. Inicjuje zdarzenie rysowania dla elementu. Zwraca pozycję x elementu wyrażoną we współrzędnych jego rodzica. Zwraca pozycję y elementu wyrażoną we współrzędnych jego rodzica. Zwraca wartość współrzędnej z elementu. Kup książkęPoleć książkę 412 Rozdzia(cid:239) 11. Tworzenie okien w architekturze grafika-widok Chociaż dostarczenie własnej implementacji metody type() lub typu wyliczeniowego Type nie jest obowiązkowe, zalecamy dostarczenie obu tych implementacji dla wszyst- kich podklas reprezentujących niestandardowe elementy graficzne. Dzięki temu w łatwy sposób zidentyfikujemy typy niestandardowych elementów graficznych, a poza tym umoż- liwimy ich działanie z metodą qgraphicsitem_cast () — która rzutuje wskaźniki QGraphicsItem na wskaźniki na odpowiednie podklasy klasy QGraphicsItem. (Funkcja qgraphicsitem_cast () obsługuje tylko operacje rzutowania ze wskaźników QGraphics (cid:180)Item na podklasy, a nie z podklas na wskaźniki QGraphicsItem. W przypadku operacji rzutowania z powrotem na wskaźniki QGraphicsItem trzeba wykorzystać inne techniki. Operacje rzutowania elementów graficznych omówimy w dalszej części tej książki — w na- stępnym rozdziale — patrz strona 431). W tym konkretnym przykładzie mamy prywatną zmienną składową m_path typu QPainterPath (która dynamicznie zmienia figurę w miarę postępów symulacji). Ponie- waż mamy tę ścieżkę, możemy ją wykorzystać do dostarczenia zarówno prostokąta ota- czającego element, jak i jego kształtu. Zwróćmy jednak uwagę, że obliczenie prostokąta otaczającego na podstawie ścieżki obiektu painter nie działa szczególnie szybko, choć jest wystarczająco szybkie dla aplikacji Szalka Petriego. W innych aplikacjach, które ko- rzystają ze ścieżki obiektu painter w taki sposób, mogą być wykorzystywane mechanizmy buforowania prostokąta otaczającego ścieżki. Metoda shape() jest trywialna do zaimplementowania, ponieważ jak zobaczymy za chwilę, ścieżki rysowane są nie za pomocą pióra, tylko za pomocą pędzla. Gdybyśmy ry- sowali ścieżkę za pomocą grubego pióra — na przykład w celu narysowania elementu o kształcie pączka na podstawie ścieżki w kształcie elipsy — to otrzymany kształt nie byłby dokładny, ponieważ nie uwzględniałby grubości obrysu. Mogłoby to znaczyć, że gdyby użytkownik kliknął obrys, nie byłoby żadnej reakcji, ponieważ jest on „poza” elipsą. W ta- kich przypadkach można utworzyć obiekt QPainterPathStroker, skonfigurować go za pomocą metod do manipulowania piórem (setWidth(), setJoinStyle() itp.), a następnie wywołać metodę QPainterPathStroker::createStroke(), przekazując w roli argumentu ścieżkę obiektu painter. Wartość zwracana przez metodę createStroke() jest nową ścieżką obiektu painter, która określa obrys pierwotnej ścieżki, ale z wykorzystaniem ustawień skonfigurowanych dla pióra. W przypadku klasy Cell działaniem konstruktora (którego tu nie pokazano) jest ustawienie pędzla oraz początkowego rozmiaru, a następnie wywołanie prywatnej metody (również jej nie pokazano) w celu utworzenia początkowej figury. W ten sposób metoda paint() staje się znacznie prostsza, niż byłaby w innej sytuacji, ponieważ jedyne jej zadania to narysowanie ścieżki i opcjonalnie identyfikatora elementu. void Cell::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget*) { painter- setPen(Qt::NoPen); painter- setBrush(m_brush); painter- drawPath(m_path); if (s_showIds) { Kup książkęPoleć książkę Wprowadzenie do elementów graficznych 413 QPointF center = m_path.boundingRect().center(); QString id = QString::number(m_id); center.setX(center.x() - (option- fontMetrics.width(id) / 2)); center.setY(center.y() + (option- fontMetrics.height() / 4)); painter- setPen(QPen()); painter- drawText(center, id); } } Zaczynamy od skonfigurowania pióra obiektu painter (Qt::NoPen oznacza, że obrys nie zostanie narysowany) oraz jego pędzla, a następnie rysujemy ścieżkę komórki (klasa Cell zawiera również statyczną zmienną Boolean s_showIds, z kilkoma statycznymi meto- dami dostępowymi, oraz zmienną składową ID — m_id typu int — żadnej z nich nie po- kazano). Jeśli trzeba wyświetlić identyfikator elementu, znajdujemy środek ścieżki i używa- jąc obiektu QPen(), rysujemy identyfikator wyrównany do środka w poziomie, a w pionie ustawiony w jednej czwartej wysokości, licząc od góry. Domyślny konstruktor klasy QPen generuje kosmetyczne pióro (ang. cosmetic pen) o czarnej ciągłej linii grubości 1 piksela. Pióro jest opisywane jako „kosmetyczne”, jeśli ignoruje transformacje. Na przykład parametr QStyleOptionGraphicsItem* przechowuje prostokąt udostęp- niony przez element, metryki czcionki — po to właśnie użyliśmy go w tym przykładzie — oraz paletę. Parametr QWidget* jest rzadko używany. Implementacja metody paint() jest wystarczająco szybka dla aplikacji Szalka Petriego, ale jest daleka od optymalnej. Wydaje się, że nie warto buforować prostokąta otaczającego ścieżkę, ponieważ obiekty Cell kurczą się lub rozrastają przy każdej iteracji symulacji. Natomiast identyfikatory komórek nigdy się nie zmieniają. W związku z tym możemy po- święcić niewielką ilość pamięci, by zyskać na szybkości i przechowywać w niej prywatną zmienną składową m_idString typu QString, którą tworzymy w konstruktorze. W ten spo- sób unikamy korzystania wewnątrz metody paint() z metody QString::number(), która przy każdym wywołaniu alokuje pamięć. Obliczanie szerokości i wysokości metryk czcionki również jest wolne. Z łatwością możemy obliczyć te wartości w konstruktorze i buforo- wać wyniki. Najlepszą zasadą jest po prostu uruchomić rysowanie, a następnie, jeśli okaże się zbyt wolne, znaleźć elementy, które można buforować. Naturalnie najlepiej mierzyć efekty wprowadzanych zmian, aby mieć pewność, że oczekiwane korzyści rzeczywiście zostały osiągnięte. W klasie Cell nie zaimplementowano żadnych procedur obsługi zdarzeń ani nie ustawiono żadnych flag (na przykład ItemIsMovable lub ItemIsSelectable), dlatego użytkownicy nie mogą bezpośrednio wykonywać działań na elementach typu Cell. Przy- kłady tego, w których miejscach ustawiamy te flagi oraz gdzie implementujemy procedu- ry obsługi zdarzeń, zaprezentujemy w następnym rozdziale. Ostatnią część tego roz- działu poświęcono na przedstawienie tabel prezentujących interfejs API klasy QGraphicsItem. W tabeli 11.1 zestawiono metody klasy QGraphicsItem, natomiast w tabelach 11.2 i 11.3 wymieniono najważniejsze typy wyliczeniowe wykorzystywane w tych metodach. Kup książkęPoleć książkę 414 Rozdzia(cid:239) 11. Tworzenie okien w architekturze grafika-widok Tabela 11.2. Typ wyliczeniowy Qt::ItemSelectionMode Typ wyliczeniowy Opis Qt::ContainsItemShape Qt::IntersectsItemShape Qt::ContainsItemBoundingRect Qt::IntersectsItemBoundingRect Zaznaczanie elementów, których kształty w całości mieszczą się w zaznaczonym obszarze. Zaznaczanie elementów, których kształty w całości mieszczą się w zaznaczonym obszarze albo przecinają ten obszar. Zaznaczanie elementów, których prostokąty otaczające w całości mieszczą się w zaznaczonym obszarze. Zaznaczanie elementów, których prostokąty otaczające w całości mieszczą się w zaznaczonym obszarze albo przecinają ten obszar. Tabela 11.3. Typ wyliczeniowy QGraphicsItem::GraphicsItemFlag Typ wyliczeniowy Opis QGraphicsItem::ItemAcceptsInputMethod QGraphicsItem::ItemClipsChildrenToShape QGraphicsItem::ItemClipsToShape QGraphicsItem::ItemDoesntPropagate (cid:180)OpacityToChildren QGraphicsItem::ItemHasNoContents QGraphicsItem::ItemIgnoresParentOpacity QGraphicsItem::ItemIgnoresTransformations QGraphicsItem::ItemIsFocusable QGraphicsItem::ItemIsMovable QGraphicsItem::ItemIsPanel QGraphicsItem::ItemIsSelectable QGraphicsItem::ItemNegativeZStacks (cid:180)BehindParent Element obsługuje metody wprowadzania (Qt 4.6). Element obcina wszystkie swoje dzieci (rekurencyjnie) do swojego własnego kształtu (Qt 4.3). Element jest obcinany do swojego własnego kształtu niezależnie od sposobu rysowania. Poza swoim kształtem nie może także odbierać zdarzeń (np. kliknięć myszą) (Qt 4.3). Element nie propaguje swojego pokrycia na potomków (Qt 4.5). Element nie rysuje niczego (Qt 4.6). Pokrycie elementu ma wartość, na jaką zostało ustawione, a nie wartość w połączeniu ze swoim rodzicem (Qt 4.5). Element ignoruje transformacje zastosowane do swojego rodzica (choć jego pozycja jest powiązana do rodzica). Przydatne dla elementów, które są wykorzystywane jako etykiety tekstowe (Qt 4.3). Element akceptuje naciśnięcia klawiszy. Element (oraz rekurencyjnie jego dzieci) może być przeniesiony poprzez kliknięcie i przeciągnięcie. Element jest panelem (Qt 4.6). Więcej informacji na temat paneli można znaleźć w dokumentacji online. Element można zaznaczyć poprzez kliknięcie, operację „spięcia gumką” (ang. rubber band) lub za pomocą wywołania QGraphicsScene:: (cid:180)setSelectionArea(). Jeśli wartość współrzędnej z jest ujemna, element automatycznie chowa się za swoim rodzicem. Kup książkęPoleć książkę Wprowadzenie do elementów graficznych 415 Tabela 11.3. Typ wyliczeniowy QGraphicsItem::GraphicsItemFlag — ciąg dalszy Typ wyliczeniowy QGraphicsItem::ItemSendsGeometryChanges QGraphicsItem::ItemSendsScenePosition (cid:180)Changes QGraphicsItem::ItemStacksBehindParent QGraphicsItem::ItemUsesExtendedStyle (cid:180)Option Opis Element wywołuje metodę itemChange() dla zmian pozycji i transformacji (Qt 4.6). Zobacz też ramka „Zmiany działania architektury grafika-widok wprowadzone w Qt 4.6” (patrz strona 402). Element wywołuje metodę itemChange() dla zmian pozycji (Qt 4.6). Element jest umieszczony za swoim rodzicem zamiast przed nim (co jest działaniem domyślnym). Przydatne do tworzenia efektu cienia. Element uzyskuje dostęp do dodatkowych atrybutów klasy QStyleOptionGraphicsItem. Na tym zakończyliśmy przegląd aplikacji Szalka Petriego oraz API klasy QGraphicsItem. W kodzie źródłowym przykładu jest kilka szczegółów mniejszego znaczenia, których nie omówiliśmy. Na przykład po każdej iteracji wykorzystujemy jednorazowy timer do za- inicjowania następnej iteracji. Nie możemy skorzystać z obiektu klasy QTimer o stałym interwale czasowym, ponieważ czas potrzebny na wykonanie obliczeń w każdej iteracji jest inny. Poza tym w momencie zatrzymania aplikacji całe okno staje się półprzezroczyste. Efekt ten najlepiej wygląda w systemie Windows. W następnym rozdziale przeanalizujemy aplikację, która w bardziej konwencjonalny sposób korzysta z architektury grafika-widok. Zaprezentujemy też więcej przykładów tego, jak tworzyć własne elementy graficzne, a także jak zapisać i załadować sceny do i z plików, jak manipulować elementami na scenach — na przykład wykonywać transformacje, a także kopiować, wycinać i wklejać. Kup książkęPoleć książkę 416 Rozdzia(cid:239) 11. Tworzenie okien w architekturze grafika-widok Kup książkęPoleć książkę Skorowidz Wszystkie funkcje nieglobalne i metody są wymienione w ramach swojej klasy (albo swojej klasy bazowej — na przykład QWidget lub QObject) oraz jako osobne pojęcia najwyższego poziomu. Tam, gdzie nazwa metody lub funkcja
Pobierz darmowy fragment (pdf)

Gdzie kupić całą publikację:

Biblioteki Qt. Zaawansowane programowanie przy użyciu C++
Autor:

Opinie na temat publikacji:


Inne popularne pozycje z tej kategorii:


Czytaj również:


Prowadzisz stronę lub blog? Wstaw link do fragmentu tej książki i współpracuj z Cyfroteką: