Qt rajzolás munkafüzet. Elemi Alkalmazások fejlesztése 3.

Hasonló dokumentumok
Elemi alkalmazások fejlesztése III.

Elemi alkalmazások fejlesztése III.

Elemi alkalmazások fejlesztése III.

Elemi alkalmazások fejlesztése III. A Qt assistant elindítása. Ajánlott ir odalom. A Qt assistant nyitó ablaka

bool _freehand = false; QPoint _lastpoint; // ebben a pontban volt az utolsó rajzolásnál az egérmutató

Elemi alkalmazások fejlesztése III

Alkalmazások fejlesztése III. Qt 4 /C++ alapú grafikus alkalmazás Bevezetés I.

3. Osztályok II. Programozás II

3D-s számítógépes geometria és alakzatrekonstrukció

Grafikus Qt programok írása segédeszközök nélkül

3D-s számítógépes geometria és alakzatrekonstrukció

QLabel *label = new Qlabel("Hello Qt!",0);

Elemi grafika. Stílusok, időzítő, képek

Programozás I. 5. Előadás: Függvények

Elemi alkalmazások fejlesztése III.

Budapest, március. ELTE Informatikai Kar

Objektumok és osztályok. Az objektumorientált programozás alapjai. Rajzolás tollal, festés ecsettel. A koordinátarendszer

Egységes és objektumközpontú adatbázis-kezelés (2. rész)

Eseménykezelés. Aszinkron kommunikáció

Java és web programozás

Eseményvezérelt alkalmazások fejlesztése I 4. előadás. Elemi grafika és egérkezelés

Rajz 01 gyakorló feladat

Statikus adattagok. Statikus adattag inicializálása. Speciális adattagok és tagfüggvények. Általános Informatikai Tanszék

A jobboldalon a pnlright egy Stacked Widget Állítsuk be az első lapot és nevezzük el pnldraw-ra:

Programozás C++ -ban 2007/4

Eseményvezérelt alkalmazások fejlesztése I 4. előadás. Elemi grafika és egérkezelés. Elemi grafika és egérkezelés Rajzolás grafikus felületen

BME MOGI Gépészeti informatika 7.

MySql elindítása. Elemi alkalmazások fejlesztése IV. Feladat. Az alkalmazás adatbázisa

Elemi alkalmazások fejlesztése IV.

Alkalmazások fejlesztése III. Qt 4 /C++ alapú grafikus alkalmazás - Memóriajáték 1/2

Tervezőeszközök, fejlesztőeszközök használata Qt alapú alkalmazásoknál. Saját vezérlő használata tervezőben (worldclocks)

Elemi alkalmazások fejlesztése III

Bevezetés a programozásba I.

Elemi alkalmazások fejlesztése III

Osztály és objektum fogalma

components : IContainer dx : int dy : int tmidőzítő : Timer toolstripseparator1 : ToolStripSeparator tsmikilépés : ToolStripMenuItem

Programozás C++ -ban

Osztályok. 4. gyakorlat

Elemi alkalmazások fejlesztése III.

Java és web programozás

C++ programozási nyelv Konstruktorok-destruktorok

Programozás II. 3. gyakorlat Objektum Orientáltság C++-ban

Pelda öröklődésre: import java.io.*; import java.text.*; import java.util.*; import extra.*;

Dinamikus csatolású függvénykönyvtár készítése és használata Plugin-szerű betöltés Egyszeű C++ osztályok készítése

C programozási nyelv

Elemi alkalmazások fejlesztése III

Programozás I gyakorlat

Elemi alkalmazások fejlesztése IV. Adatbázis-kezelő GUI alkalmazás készítése 3. Összetett tábla karbantartása

Szoftvertechnolo gia gyakorlat

Bevezetés a programozásba II 1. gyakorlat. A grafikus könyvtár használata, alakzatok rajzolása

Rajz 02 gyakorló feladat

Programozás. (GKxB_INTM021) Dr. Hatwágner F. Miklós április 4. Széchenyi István Egyetem, Gy r

Dr. Schuster György október 14.

Bevezetés a programozásba Előadás: Fordítási egység

A Paint program használata

Bevezetés a programozásba II. 8. Előadás: Osztályok, objektumok, osztályszintű metódusok

A Vonallánc készlet parancsai lehetővé teszik vonalláncok és sokszögek rajzolását.

Diagram formázása. A diagram címének, a tengelyek feliratainak, jelmagyarázatának, adatfeliratainak formázása

Programozás 6. Dr. Iványi Péter

Abstract osztályok és interface-ek. 7-dik gyakorlat

7. fejezet: Mutatók és tömbök

osztályok kapcsolata Származtatatás C++ Izsó Tamás március 19. Izsó Tamás Származtatatás/ 1

és az instanceof operátor

Elemi alkalmazások fejlesztése III.

Képfájlok beolvasása és megjelenítése

Java VIII. Az interfacei. és az instanceof operátor. Az interfészről általában. Interfészek JAVA-ban. Krizsán Zoltán

Visual C++ osztály készítése, adattagok, és metódusok, láthatóság, konstruktor, destruktor. Objektum létrehozása, használata, öröklés.

1. Alapok. Programozás II

A lista eleme. mutató rész. adat rész. Listaelem létrehozása. Node Deklarálás. Létrehozás. Az elemet nekünk kell bef zni a listába

Programozás C++ -ban

Virtuális függvények (late binding)

Programozás C nyelven FELÜLNÉZETBŐL elhullatott MORZSÁK. Sapientia EMTE

1. Template (sablon) 1.1. Függvénysablon Függvénysablon példányosítás Osztálysablon

Bevezetés a programozásba Előadás: A const

Java V. Osztályszint. lyszintű ű tagok. Példányváltozó. Osztályváltozó. Általános Informatikai Tanszék Utolsó módosítás:

Végeselem módszer 7. gyakorlat

Miután létrehoztuk, szeretnénk neki beszédesebb nevet adni. A név változtatásához a következőt kell tenni:

Függvény pointer. Feladat: Egy tömbben soroljunk fel függvényeket, és hívjuk meg valahányszor.

Objektumok inicializálása

Bisonc++ tutorial. Dévai Gergely. A szabály bal- és jobboldalát : választja el egymástól. A szabályalternatívák sorozatát ; zárja le.

Tájékoztató. Használható segédeszköz: -

C# osztálydeníció. Krizsán Zoltán 1. .net C# technológiák tananyag objektum orientált programozás tananyag

Bánsághi Anna 2014 Bánsághi Anna 1 of 33

Java és web programozás

Java II. I A Java programozási nyelv alapelemei

Szoftvertechnolo gia 7. gyakorlat

Számítástechnika II. BMEKOKAA Előadás. Dr. Bécsi Tamás

12. gyakorlat Enum; Tárolási osztályok Preprocesszor utasítások; Moduláris programozás

C++ referencia. Izsó Tamás február 17. A C++ nyelvben nagyon sok félreértés van a referenciával kapcsolatban. A Legyakoribb hibák:

Lakóház tervezés ADT 3.3-al. Segédlet

Objektumorientált programozás C# nyelven

Johanyák Zsolt Csaba: Ugráló gomb oktatási segédlet Copyright 2008 Johanyák Zsolt Csaba

Widget-ünket a festők vásznáról Canvas-nak nevezzük el. Mit kell a widgetnek tudnia?

Autodesk Inventor Professional New Default Standard.ipt

VII. Appletek, grafika

Lineáris egyenletrendszerek

Eseménykezelés. Aszinkron kommunikáció

RAJZ1. vezetett gyakorlat

SDI ALKALMAZÁS I. Workspace / ResourceView / Toolbar / IDR_MAINFRAME. Workspace / ResourceView / Menu / IDR_MAINFRAME

Átírás:

Qt rajzolás munkafüzet Elemi Alkalmazások fejlesztése 3.

1. fejezet Impresszum Qt rajzolás munkafüzet (C)2006 Zimler Attila Tamás <hijaszu@hlfslinux.hu> Visszajelzéseket szivesen fogadok. A munkafüzet online formában a következ címen található: http://people.inf.elte.hu/hijaszu/qtdrawing/index.html A dokumentum generálásának dátuma: 2006. május 10.

2 Impresszum

2. fejezet Bevezet Formátumok class Example { /* Ez egy példa kódrészlet */ ; # Egy parancssori utasítás így néz ki (a # a prompt jel). függvény() Ez a jelölésmód azonban nem a függvény szignatúra helyes írásmódja! (El fordulhat, hogy van paramétere a függvénynek, de ez nem kerül kiírásra.) változó Ez egy változó jelölése. Az állományok jelölése ezen a módon lesz megvalósítva. Megjegyzések ˆ El fordulhat, hogy a Qt környezet speciális beállításokat igényel az adott gépen, a.pro állományban. Ehhez további segítség: http://people.inf.elte.hu/hijaszu/eaf3_- exercise3.html. Amennyiben így kell használni a Qt-t, akkor az összes "qmake -project" parancs kiadása után újra be kell állítani ezeket a speciális dolgokat a.pro állományban. ˆ A hosszabb programrészletekben az alábbi formátumú megjegyzések lesznek, ezeknek a helyzete nem változik, miután belekerültek a kódba. (Tehát ezekhez képest lehet viszonyítani, hogy milyen kódot hová kell írni, és ezért a kód változatlan részletei elhagyhatóak.) /* határolósor */ ˆ A harmadik feladatsortól kezdve mindegyik feladat után le lehet fordítani a programot és meg lehet nézni a futását (ezért nincs is már odaírva a feladatok megoldásához, hogy tegyük ezt meg). A fordítást a következ paranccsal tehetjük meg: # make

4 Bevezet

3. fejezet A Qt grakai rendszere A Qt grakai rendszere több komponens együttm ködéséb l áll. A graka során nem közvetlenül a rajzfelületre rajzolunk, hanem egy logikai térbe. A logikai tér a rajzfelületre több lépcs ben képz dik, nem feltétlenül az alábbi sorrendben (viszont az eredmény ugyanaz lesz). 1. A logikai tér koordinátái átalakításra kerülnek, így tetsz leges helyre helyezhetjük a logikai térben az origót. 2. A logikai tér egy transzformációs mátrix segítségével átalakításra kerül, így az ábrát kirajzolás el tt forgathatjuk és eltolhatjuk. 3.1. ábra. A Qt rajzolási rendszere. Ennek a rendszernek több el nye is van: ˆ Fix koordinátákat rakhatunk a rajzunkba, és az ablak átméretezésénél ez nem fog problémát okozni. ˆ Eltolhatjuk a rajz közepére az origót, ha az nekünk úgy kényelmes. ˆ Elforgathatjuk (akár többször is) a rajzfelületet a rajzolás el tt. Ebb l következik, hogy egy kényelmetlen szögben rajzolás helyett, bármilyen állapotban megrajzolhatjuk az ábrát. Ezután elforgatva az ábrát az eredmény az lesz, mintha a kényelmetlen szögben rajzoltunk volna (persze nehézkes számítások nélkül). ˆ A leképezésnek a logikai és a zikai rajzfelület között nem szükséges, hogy vízszintes és függ leges arányban is ugyanolyan arányú legyen.

6 A Qt grakai rendszere

4. fejezet A feladatsorozat célja A munkafüzetben a feladatsorok folyamán egy grakus óra programot fogunk létrehozni. A program a következ tulajdonságokkal fog rendelkezni: ˆ Az aktuális id t fogja mutatni a program. ˆ Az ablak átméretezésekor arányosan nagyítjuk a rajzot. ˆ Kiküszöböljük a villogást az ábrákon. 4.1. ábra. A cél

8 A feladatsorozat célja

5. fejezet Alap Qt program létrehozása 1. Hozzunk létre egy main() függvényt és fordítsuk le! Tipp Ne felejtsük el, hogy a Qt alkalmazás elindításához a main() függvény két paraméteres formájára lesz szükségünk. (a) Hozzuk létre az alábbi tartalmú main.cpp állományt: int main(int argc, char* argv[]) { (b) Állítsuk el a qmake.pro állományát: # qmake -project (c) Fordítsuk le a programot: # qmake # make 2. Hozzunk létre egy f ablakot és jelenítsük meg a main() függvényb l! (A f ablak osztályának a munkafüzet a MainWnd nevet adja.) Tippek (a) A következ fejléc állományokra lesz szükség: ˆ qmainwindow.h: a f ablak származtatásához. ˆ qapplication.h: a Qt f program létrehozásához. (b) A f ablak osztályának deklarációját (.h) és denícióját (.cpp) mindenképpen két külön állományba kell rakni, mert különben a qmake nem fog rendesen m ködni, ha a meta object compiler-t (moc) kell futtatnia. (c) Ne felejtsük el a Q_OBJECT makrót a f ablak osztályából. (d) Jelenleg elég ha a f ablak csak egy üres konstruktort tartalmaz. (e) Könnyen elérhetjük, hogy a f ablak becsukására a program megálljon, ha használjuk a QApplication::setMainWidget() metódusát. (f) Mivel extra állományokat adtunk a projekthez, ezért a projekt állományt aktuálizálni kell. Ezt két módon tehetjük meg:

10 Alap Qt program létrehozása ˆ a HEADERS konstanshoz hozzáadjuk az új fejléc állományokat, a SOURCES konstanshoz hozzáadjuk az új.cpp állományokat. Amennyiben bármelyik nem létezik, létrehozzuk. ˆ Újrageneráljuk a.pro állományt: # rm -f *.pro # qmake -project Megjegyzés: Ne felejtsük el a Makele állományt újragenerálni. # qmake (a) Hozzuk létre az alábbi tartalmú mainwnd.h állományt: #ifndef MAINWND_H #define MAINWND_H #include <qmainwindow.h> class MainWnd : public QMainWindow { Q_OBJECT public: MainWnd(); ; #endif /* MAINWND_H */ (b) Hozzuk létre az alábbi tartalmú mainwnd.cpp állományt: #include "mainwnd.h" MainWnd::MainWnd() { (c) A main.cpp állományt módosítsuk, hogy a következ képpen nézzen ki: #include "mainwnd.h" #include <qapplication.h> int main(int argc, char* argv[]) { QApplication app(argc, argv); MainWnd mw; mw.show(); app.setmainwidget(&mw); app.exec(); (d) Generáljuk újra a.pro állományt: # rm -f *.pro # qmake -project (e) Fordítsuk le a programot. # qmake # make 3. Hozzunk létre a QWidget osztályból származtatással egy egyedi widget-et és azt helyezzük el a f ablakon! (Ez az osztály a munkafüzetben a Clock nevet viseli.) Tippek (a) Ne felejtsük el, hogy a QWidget nem rendelkezik nulla paraméterszámú konstruktorral, hanem alapértelmezett értékei vannak a konstruktorának.

11 (b) A f ablak adattagjai közé mutató formában vegyük fel az újonnan létrehozott widget típust. (c) A QMainWindow::setCentralWidget() metódus segítségével rakhatjuk a f ablakra az objektumot. (d) Ne felejtsük el a f ablakot kiegészíteni egy destruktorral, ahol az egyedi widget objektumot megsemmisítjük. (e) Ne felejtsük el a Q_OBJECT makrót. (f) Ne felejtsük el módosítani a.pro állományt. (a) Hozzuk létre az alábbi clock.h állományt: #ifndef CLOCK_H #define CLOCK_H #include <qwidget.h> class Clock : public QWidget { Q_OBJECT public: Clock(QWidget* parent = 0, const char* name = 0, WFlags f = 0); ; #endif /* CLOCK_H */ (b) Hozzuk létre az alábbi clock.cpp állományt: #include "clock.h" Clock::Clock(QWidget* parent, const char* name, WFlags f) : QWidget(parent, name, f) { (c) Vegyünk fel egy privát _clock adattagot a MainWnd osztályba és szerkesszük be a clock.h fejlécállományt. Ennek eredményeképpen a következ képpen kell kinéznie a mainwnd.h állománynak: #ifndef MAINWND_H #define MAINWND_H #include <qmainwindow.h> #include "clock.h" class MainWnd : public QMainWindow { Q_OBJECT Clock* _clock; public: MainWnd(); ~MainWnd(); ; #endif /* MAINWND_H */ (d) Helyezzük a f ablakra az objektumot. Ehhez módosítsuk a MainWnd osztály konstruktorát: MainWnd::MainWnd() { setcentralwidget(_clock = new Clock(this));

12 Alap Qt program létrehozása (e) Írjuk meg a MainWnd osztály 3. pontjában már bevezetett destruktorát: MainWnd::~MainWnd() { delete _clock; (f) Generáljuk újra a.pro állományt és fordítsuk le a programot: # rm -f *.pro # qmake -project # qmake # make

6. fejezet A rajzolást végz kód el készítése 1. Hozzunk létre egy _draw() metódust a Clock osztály számára! (a) Módosítsuk a clock.h állományt, hogy a következ képpen nézzen ki: #ifndef CLOCK_H #define CLOCK_H #include <qpainter.h> #include <qwidget.h> // új sor class Clock : public QWidget { Q_OBJECT void _draw(qpainter* painter); // új sor public: Clock(QWidget* parent = 0, const char* name = 0, WFlags f = 0); ; #endif /* CLOCK_H */ (b) A clock.cpp állományban hozzuk létre a következ metódust _draw() metódust: void Clock::_draw(QPainter* painter) { /* Változók deklarálása */ /* Az alap megrajzolása */ /* A vonalak megrajzolása */ /* A számok elhelyezése az óralapon */ /* A nagymutató megrajzolása */ /* A kismutató megrajzolása */ /* A másodperc mutató megrajzolása */ /* Újabb frissítés ütemezése */ Megjegyzés: A _draw() implementációját a következ fejezetekben adjuk meg, most csak a gerincét hozzuk létre. (c) Fordítsuk le a programot. # make 2. Deniáljuk felül a Clock osztályban a QWidget::paintEvent() metódusát, és ebb l hívjuk meg a _draw() metódust! Tippek

14 A rajzolást végz kód el készítése (a) Hozzuk létre a QPainter objektumot. (b) Válasszuk ki a kisebbik méretet, hogy arányosan tudjuk megjeleníteni a rajzot. (c) Állítsuk be a koordinátarendszert. (d) Hívjuk meg a rajzolást végz rutint (_draw()). (a) Módosítsuk a clock.h állományt úgy, hogy a következ képpen nézzen ki: #ifndef CLOCK_H #define CLOCK_H #include <qpainter.h> #include <qwidget.h> class Clock : public QWidget { Q_OBJECT void _draw(qpainter* painter); void paintevent(qpaintevent* event); // új sor public: Clock(QWidget* parent = 0, const char* name = 0, WFlags f = 0); ; #endif /* CLOCK_H */ (b) Valósítsuk meg a következ Clock::paintEvent() metódust: void Clock::paintEvent(QPaintEvent*) { /* Kett s pufferelés el készítés */ /* A QPainter objektum létrehozása */ QPainter painter(this); /* A rajzoló rutin meghívása */ int side = QMIN(width(), height()); painter.setviewport( (width() - side) / 2, (height() - side) / 2, side, side ); painter.setwindow(-50, -50, 101, 101); _draw(&painter); /* A kett s pufferelés ábrájának kihelyezése */ (c) Fordítsuk le a kódot: # make

7. fejezet A rajzolást megvalósító kód 1. Rajzoljuk meg az óra alapját! Tippek (a) Állítsuk be a ceruzát fehérre. (b) Állítsuk be a kitöltést fehérre. (c) Rajzoljuk meg a kört a QPainter::drawEllipse() metódussal. (a) Írjuk át a Clock::_draw() metódus fejlécét a clock.cpp állományban, hogy a következ módon nézzen ki: void Clock::_draw(QPainter* painter) (b) Adjuk hozzá a Clock::_draw() metódushoz a következ részletet: /* Az alap megrajzolása */ painter->setpen(qpen(white, 1, SolidLine)); painter->setbrush(qbrush(white, SolidPattern)); painter->drawellipse(-50, -50, 101, 101); /* A vonalak megrajzolása */ 2. Húzzuk meg a 12 óra értékhez tartozó függ leges vonalat! Tippek (a) Állítsuk a ceruzát feketére. (b) Húzzuk meg a vonalat a QPainter::drawLine() metódussal. Illesszük a következ kódot a Clock::_draw() metódusba: /* A vonalak megrajzolása */ painter->setpen(qpen(black, 1, SolidLine)); painter->drawline(0, -50, 0, -47); /* A számok elhelyezése az óralapon */

16 A rajzolást megvalósító kód 3. Rajzoljuk meg az összes vonalat! Tippek (a) Vegyük fel egy QWMatrix típusú objektumot a Clock::_draw() metódusba. (b) Ismételjük meg 60-szor a következ három lépést: i. Húzzunk egy vonalat, ahogy azt az el z feladatban tettük (pontosan ugyanazokkal a koordinátákkal). ii. Forgassuk a QWMatrix objektumot 6 fokkal. iii. Állítsuk be a módosított QWMatrix objektum segítségével a QPainter world- Matrix-át ( QPainter::setWorldMatrix()). (a) Vegyünk fel egy QWMatrix típusú mátrixot a Clock::_draw() metódusba: /* Változók deklarálása */ QWMatrix matrix; /* Az alap megrajzolása */ (b) Alakítsuk át a vonalak rajzolását a következ re: /* A vonalak megrajzolása */ for (int i = 0; i < 60; ++i) { painter->setpen(qpen(black, 1, SolidLine)); painter->drawline(0, -50, 0, -47); matrix.rotate(6); painter->setworldmatrix(matrix); /* A számok elhelyezése az óralapon */ 4. Legyen minden ötödik vonal vastagabb és hosszabb! Alakítsuk át a Clock::_draw() metódusát a következ módon: /* A vonalak megrajzolása */ for (int i = 0; i < 60; ++i) { // vastag vagy vékony vonal kell? painter->setpen(qpen(black, i % 5 == 0? 3 : 0, SolidLine)); // rövid vagy hosszú vonal kell? painter->drawline(0, -50, 0, i % 5 == 0? -45 : -47); // 6 fokonként egy-egy vonal, összesen 60 vonal. matrix.rotate(6); painter->setworldmatrix(matrix); /* A számok elhelyezése az óralapon */ 5. Helyezzük el a 12-es feliratot az óralapon! Tippek

17 (a) A QPainter::drawText() metódusai között van egy olyan, amelynek meg lehet adni a befoglaló négyzeten belül a szöveg igazitását. (b) A QString típusnak van egy setnum() metódusa, aminek segíségével egy számot könnyen szöveggé lehet alakítani. (c) Körülményes végiggondolni, hogy az el z feladat megoldása során a QPainter world- Matrix tulajdonsága milyen állapotban maradt. Egyszer bb lehet alaphelyzetbe állítani. Alakítsuk a következ re a Clock::_draw() metódust: /* A számok elhelyezése az óralapon */ QString text; matrix.reset(); painter->setworldmatrix(matrix); text.setnum(12); painter->setpen(qpen(blue, 0, SolidLine)); painter->drawtext( -10, -45, 20, 20, Qt::AlignHCenter Qt::AlignVCenter, text ); /* A nagymutató megrajzolása */ 6. Helyezzük fel az összes számot! Tipp A QWMatrix::map() metódus segítségével koordinátákat transzformálhatunk a logikai térben. A Clock::_draw() megfelel részlete: /* A számok elhelyezése az óralapon */ QString text; matrix.reset(); painter->setpen(qpen(blue, 0, SolidLine)); painter->setworldmatrix(matrix); const int cx = 0; // x irányú közepe a szövegnek const int cy = -35; // y irányú közepe a szövegnek const int tw = 10; // A szöveg szélessége (valójában / 2) const int th = 10; // A szöveg magassága (valójában / 2) for (int i = 3; i < 13; i += 3) { int tcx, tcy; // átalakított cx, cy matrix.rotate(90); matrix.map(cx, cy, &tcx, &tcy); text.setnum(i); painter->drawtext( tcx - tw, tcy - th, tw * 2, th * 2, Qt::AlignHCenter Qt::AlignVCenter, text ); /* A nagymutató megrajzolása */

18 A rajzolást megvalósító kód 7. Hozzunk létre a Clock osztály számára egy _drawarrow() metódust, amely paraméterben megkapja a QPainter objektumot és a mutató hosszát! Ezután rajzoljuk meg a mutatót és a mutató hegyét! (a) Az új clock.h állomány tartalma: #ifndef CLOCK_H #define CLOCK_H #include <qpainter.h> #include <qwidget.h> class Clock : public QWidget { Q_OBJECT void _draw(qpainter* painter); void _drawarrow(qpainter* painter, int length); // új sor void paintevent(qpaintevent* event); public: Clock(QWidget* parent = 0, const char* name = 0, WFlags f = 0); ; #endif /* CLOCK_H */ (b) A Clock::_drawArrow() metódus: void Clock::_drawArrow(QPainter* painter, int length) { /* A ceruza és az ecset beállítása */ painter->setpen(qpen(black, 1, SolidLine)); painter->setbrush(qbrush(black, SolidPattern)); /* A mutató hegyének megrajzolása */ QCOORD triangle[3][2] = { { -3, -length + 10, { 0, -length, { 3, -length + 10 ; painter->drawconvexpolygon(qpointarray(3, &triangle[0][0])); /* A mutató szárának megrajzolása */ (c) A Clock::_draw() metódus szükséges módosítása: /* A nagymutató megrajzolása */ matrix.reset(); painter->setworldmatrix(matrix); _drawarrow(painter, 45); /* A kismutató megrajzolása */ 8. Hozzuk létre a mutató szárát. Tipp Rajzoljuk meg a kört a mutató szárának végére, hogy szépen nézzen ki. Alakítsuk át a következ re a Clock::_drawArrow() metódust: /* A mutató szárának megrajzolása */ QCOORD box[4][2] = { { -1, -length + 10, { 1, -length + 10, { 1, 0, { -1, 0

19 ; painter->setpen(qpen(black, 1, SolidLine)); painter->setbrush(qbrush(black, SolidPattern)); painter->drawconvexpolygon(qpointarray(4, &box[0][0])); painter->drawellipse(-1, -1, 3, 3); 9. Rajzoljuk meg a kismutatót. A Clock::_draw() metódust kell módosítani: /* A kismutató megrajzolása */ matrix.reset(); painter->setworldmatrix(matrix); _drawarrow(painter, 30); /* A másodperc mutató megrajzolása */ 10. Rajzoljuk meg a másodperc mutatót. A Clock::_draw() metódusának szükséges módosítása: /* A másodperc mutató megrajzolása */ matrix.reset(); painter->setworldmatrix(matrix); painter->setpen(qpen(red, 1, SolidLine)); painter->drawline(0, -45, 0, 0); /* Újabb frissítés ütemezése */

20 A rajzolást megvalósító kód

8. fejezet Az aktuális id t beállító kód 1. Valósítsuk meg a nagymutató beállítását! Tippek (a) A worldmatrix forgatásával nagyon könnyen megfelel irányba lehet állítani a mutatót. (b) A QTime::currentTime() metódusával le lehet kérdezni a megfelel id t. (a) Szerkesszük be a qdatetime.h fejlécet a clock.cpp-be: #include <qdatetime.h> (b) Módosítsuk a következ két részletet a Clock::_draw() metódusban: /* Változók deklarálása */ QWMatrix matrix; QTime t = QTime::currentTime(); /* Az alap megrajzolása */ /* A nagymutató megrajzolása */ matrix.reset(); matrix.rotate(t.minute() * 6); painter->setworldmatrix(matrix); _drawarrow(painter, 45); // új sor /* A kismutató megrajzolása */ 2. Valósítsuk meg óra és a másodperc mutató beállítását! Szükséges módosítás a Clock::_draw() állományban. /* A kismutató megrajzolása */ matrix.reset(); matrix.rotate((t.hour() * 60 + t.minute()) / 2); painter->setworldmatrix(matrix); _drawarrow(painter, 30); // új sor /* A másodperc mutató megrajzolása */

22 Az aktuális id t beállító kód matrix.reset(); matrix.rotate(t.second() * 6); painter->setworldmatrix(matrix); painter->setpen(qpen(red, 1, SolidLine)); painter->drawline(0, -45, 0, 0); // új sor /* Újabb frissítés ütemezése */ 3. Kapcsoljuk egy id zít re az újrarajzolást! Tippek (a) Vegyünk fel egy QTimer adattagot a Clock osztályba. (b) A rajzolás végeztével egy egyszeri lefutású id zít t indítsunk 1 másodperces késleltetéssel. Hogy miért? Mert így amikor a rendszer újrarajzolja az objektumot, akkor elölr l kezd dik az egy másodperc mérése. (c) Az id zít lejártát az update() metódusra kapcsolhatjuk. (d) Amennyiben új adattagot veszünk fel az osztályba, akkor a qmake által generált Makele ezt nem tudja teljesen helyesen értékelni. # make distclean # make (a) A clock.h új tartalma: #ifndef CLOCK_H #define CLOCK_H #include <qpainter.h> #include <qtimer.h> #include <qwidget.h> class Clock : public QWidget { Q_OBJECT QTimer timer; // új sor void _draw(qpainter* painter); void _drawarrow(qpainter* painter, int length); void paintevent(qpaintevent* event); public: Clock(QWidget* parent = 0, const char* name = 0, WFlags f = 0); ; #endif /* CLOCK_H */ (b) A szükséges módosítás a Clock::_draw() metódusban: /* Újabb frissítés ütemezése */ connect(&timer, SIGNAL(timeout()), this, SLOT(update())); timer.start(1000, true); (c) Amennyiben új adattagot veszünk fel az osztályba, akkor a qmake által generált Makele ezt nem tudja teljesen helyesen értékelni. # make distclean # make 4. Indítsuk el a programot, nagyítsuk fel teljes képerny sre és gyeljük meg, ahogy villog.

9. fejezet A villogás kiküszöbölése kett s puerelés (double buering) segítségével Mi is az a kett s puerelés? A villogást a rajz folyamatos újrarajzolása során a számítások viszonylagos lassúsága okozza. (Ez a számítás a képerny frissítéséhez képest értend.) A kett s puerelés ezt úgy oldja meg, hogy nem közvetlenül a képerny memóriaterületére rajzolunk. Amikor elkészülünk a rajzzal, akkor egy nagyon gyors rutinnal kicseréljük a képerny n látható rajzot a háttérben elkészülttel. Az, hogy ez hogy történik a rendszer ügyességén és hardverén múlik: ˆ Ha a grakus kártya rendelkezik kell en sok memóriával, és egy egész képerny nyi képr l van szó, akkor egy egyszer memóriacím átírással meg lehet ezt oldani. ˆ A DMA segítségével a CPU-tól függetlenül lehet adatot mozgatni (közben a CPU számításokat végezhet). Megjegyzés: Ez a feladatsor csak a végén ad vizsgálható eredményt, függetlenül attól, hogy mindegyik lépés után lefordítható. 1. Emlékeztet az el z feladatsor végér l: Indítsuk el a programot, nagyítsuk fel teljes képerny sre és gyeljük meg, ahogy villog. 2. Hozzunk létre egy képet, majd méretezzük az aktuális objektumnak megfelel méret re! (Szükség lesz ehhez arra is, hogy a Clock::paintEvent() paraméterét nevesítsük, hogy elérjük.) (a) A qpixmap.h fejlécet be kell szerkeszteni a clock.cpp állományba. (b) A Clock::paintEvent() megfelel részlete: void Clock::paintEvent(QPaintEvent* event) { /* Kett s pufferelés el készítés */ static QPixmap pixmap; // módosított sor!

24 A villogás kiküszöbölése kett s puerelés (double buering) segítségével QRect rect = event->rect(); QSize newsize = rect.size().expandedto(pixmap.size()); pixmap.resize(newsize); pixmap.fill(this, rect.topleft()); /* A QPainter objektum létrehozása */ 3. Módosítsuk a QPainter objektum létrehozását, hogy a QPixmapre rajzoljon! A Clock::paintEvent() metódus megfelel részlete: /* A QPainter objektum létrehozása */ QPainter painter(&pixmap, this); // módosított sor! /* A rajzoló rutin meghívása */ 4. A kett s puerelés képét helyezzük ki az objektumra! A Clock::paintEvent() metódus vége: /* A kett s pufferelés ábrájának kihelyezése */ bitblt(this, event->rect().topleft(), &pixmap); 5. Vegyük át a QWidget-t l az objektum teljes rajzolását (kapcsoljuk ki az automatikus újrarajzolási eseményeket)! Megjegyzés: Erre azért van szükség, mert különben automatikusan letörli az objektumot a rendszer. Módosítsuk a Clock::Clock() konstruktorát, hogy a következ módon nézzen ki: Clock::Clock(QWidget* parent, const char* name, WFlags f) : QWidget(parent, name, f Qt::WNoAutoErase) { 6. Fordítsuk le a kódot és gyeljük meg, hogyha odébb mozgatjuk az ablakot, akkor egy másodpercig szétesik a kép! 7. Oldjuk meg, hogy ha megmozdítjuk az ablakot, akkor se essen szét a kép! Tipp A QMainWindow::moveEvent() metódusát kell felüldeniálni. (a) A mainwnd.h új verziója: #ifndef MAINWND_H #define MAINWND_H #include <qmainwindow.h> #include "clock.h" class MainWnd : public QMainWindow {

25 Q_OBJECT Clock* _clock; void moveevent(qmoveevent*); public: MainWnd(); ~MainWnd(); ; #endif /* MAINWND_H */ // új sor (b) És a MainWnd::moveEvent() metódus megvalósítása: void MainWnd::moveEvent(QMoveEvent*) { _clock->update();