TIE-11300 Tietotekniikan vaihtuva-alainen kurssi Graafisen käyttöliittymän ohjelmointi Syksy 2013 Luento 5 Qt: Grafiikan piirto Juha-Matti Vanhatupa
Sisältö GDI Qt paint system Koordinaatisto-operaatioita
GDI Windows:ssa piirtämisestä huolehtii GDI (Graphical Device Interface). API sisältää joukon GDI-objekteja joiden avulla rajapintaa voidaan käyttää GDI+ (Windows XP)
Graphical Device Interface (GDI)
GDI-objekteja Pen Brush Font Color Bitmap
Device context (piirtopinta) GDI:n ylläpitämä windowsin sisäinen tietorakenne, joka sisältää piirtopintaan liittyviä attribuutteja, kuten väri ja fontti tekstin piirrossa Piirtopintoja Näyttö (Display) Tulostin (Printer) Muisti (Memory, Bitmap)
Device context (piirtopinta) Matalan tason toteutus Pyydetään käyttöjärjestelmältä piirtopinnan kahva Asetetaan piirtopintaan tarvittavat asetukset (esim kynä) Suoritetaan piirtotoiminnot GDI-funktioilla Vapautetaan piirtopinta, jonka jälkeen kahva ei ole enää käyttökelpoinen
Esimerkki (winapi) HDC hdc; PAINTSTRUCT ps; // Pyydetään kahva piirtopintaan hdc = BeginPaint(hWnd, &ps); // Asetetaan objekti piirtopintaan HBRUSH old = SelectObject(hdc, GetStockObject(GRAY_BRUSH)); // Piirretään suorakulmio GDI-rajapinnan funktiolla Rectangle(hdc,0,0,100,100); // Asetetaan vanha sivellin takaisin SelectObject(hdc,old); // Vapautetaan piirtopinta EndPaint(hWnd,&ps);
GDI:n virhetilanne http://en.wikipedia.org/wiki/file:ie7_errors_caused_by_10000_gdi_objects_1.jpg GDI:ssä rajat paljonko objekteja voidaan käyttää yhtäaikaa. Esimerkissä otettu käyttöön liikaa objekteja. GDI:n virhe voi estää villiintyneen ohjelman lopettamisen (koska lopetusdialogia ei piirretä)
Qt Paint System Tarjoaa grafiikkarajapinnan ohjelmoijan käyttöön. Käyttää sisäisessä toteutuksessa kunkin alustan omaa grafiikkarajapintaa (esim. Windows -> GDI). Jakautuu pääasiassa kolmeen luokkaan, joista ohjelmoija käyttää QPainter-luokan tarjoamaa rajapintaa
Qt Paint System Mille tahansa QT:n widgetille voidaan ylimääritellä piirto-funktio (paint eventin käsittelijä), jossa voidaan piirtää grafiikkaa ja tekstiä ruudulle QPaintEvent lähetetään widgetille, jonka tulee piirtää itsensä uudelleen. Widgetin piirtofunktiota kutsutaan ennen lapsiwidgettien piirtofunktioita.
Qt Paint System class RenderArea : public QWidget { Q_OBJECT protected: void paintevent(qpaintevent *event); } RenderArea::paintEvent(QPaintEvent* event) { QPainter painter(this); painter.setpen(pen); QRect rect(10, 20, 80, 60); painter.drawellipse(rect); painter.restore(); }
QPainter Tarjoaa matalan tason piirtofunktio API:n ohjelmoijalle drawline, drawellipse, yms. Sisältää myös piirtoon vaikuttavia asetuksia setpen Koordinaatiston muokkaus, clipping jne
Reunaviivojen piirtäminen QPen pen(qt::blue, // Väri 3, // Viivan paksuus Qt::DashDotLine, // Tyyli Qt::RoundCap, // Viivan muoto Qt::RoundJoin); // Viivan muoto QPainter painter(this); painter.setpen(pen); QRect rect(10, 20, 80, 60); painter.drawrect(rect); painter.restore(); QPen
Objektin maalaaminen QPainter painter(this); QPen pen(qt::blue, 3, Qt::DashDotLine, Qt::RoundCap, Qt::RoundJoin); painter.setpen(pen); QBrush brush(qt::green, // Väri Qt::SolidPattern); // Tyyli painter.setbrush(brush); QBrush
Kuvion piirtäminen QPainter painter(this); QPainterPath path; QVector<QPoint> points; points << QPoint(0,0); points << QPoint(150,150); points << QPoint(200,150); points << QPoint(0,250); points << QPoint(0,0); QPolygonF polygon(points); path.addpolygon(polygon); painter.drawpath(path); QPainterPath
Ikkunan päivittämisen problematiikka Milloin päivitetään? Mitä päivitetään? Miten päivitetään?
Milloin päivitetään? Kun ohjelma itse haluaa päivitystä Ei kutsuta itse ikkunan päivitysfunktiota, vaan kutsutaan update() tai repaint() Repaint kutsu aiheuttaa widgetille välittömän paintevent kutsun. Repaint kutsu paintevent:n sisällä luo ikuisen silmukan! Käytä repaint:iä vain jos tarvitaan välitön paintevent, esim. animaatiossa.
Milloin päivitetään? Update luo paint eventin käsittelyä varten. Useat peräkkäiset update()-kutsut aiheuttavat vain yhden paintevent()-kutsun. Lähes kaikissa tilanteissa parempi kuin repaint, koska sallii Qt:n optimoida kutsuja ja minimoida widgetin välkyntää.
Milloin päivitetään? Kun käyttöjärjestelmä lähettää päivityspyynnön ikkunan koko muuttuu ikkuna peittyy toisen ikkunan alle ikkunaa vieritetään
Mitä päivitetään? Ikkunan päivittäminen on raskasta Kannattaa päivittää vain se alue, joka todella vaatii päivittämistä (Clipping) Hitaus korostuu erityisesti usein päivitettäessä Esim. Pitääkö ikkuna päivittää aina kun hiirtä liikutetaan ikkunan päällä? Repaint ja Update -funktioista ylikuormitetut funktiot, jotka päivittävät vain parametrina annetun alueen.
Miten päivitetään? Pidä varsinainen piirtometodi mahdollisimman tehokkaana Älä suorita piirtometodissa turhaa laskentaa tms. Tuplapuskurointi (Double buffering) Hyödyllinen monimutkaisten piirtooperaatioiden yhteydessä Ikkunan sisältö piirretään ensin muistiin ja vasta tämän jälkeen kerralla näytölle Qt 4.0:sta lähtien QWidget:ssä automaattisesti.
Värin määrittäminen QColor QColor () QColor ( int r, int g, int b, int a = 255 ) QColor ( QRgb color ) QColor ( const QString & name ) QColor ( const char * name ) QColor ( const QColor & color ) QColor ( Qt::GlobalColor color ) Qt::GlobalColor Qt::white, Qt::black,Qt::red Color name "#RRGGBB" Alpha Läpinäkyvyysarvo 0-255
Värin kysyminen käyttäjältä QColorDialog dlg; dlg.setcurrentcolor(qt::red); if(dlg.exec() == QDialog::Accepted) { QColor c = dlg.selectedcolor(); }
Kuvan näyttäminen QPainter painter(this); QString path; QPixmap pixmap(path); painter.drawpixmap(0,0,pix map); QPixmap
Tekstin piirtäminen QString text = "OHJ-7400 Graafisen käyttöliittymän ohjelmointi"; QFont font("arial",24); QPainter painter(this); painter.setfont(font); painter.drawtext(100,100,text); QFont
Rivitetty teksti QString text = "OHJ-7400 Graafisen käyttöliittymän ohjelmointi"; QFont font("arial",24); painter.setfont(font); QRect r(100,100,300,300); QPainter painter(this); painter.drawrect(r); painter.drawtext(r,text);
Tekstin leveyden laskeminen QString text = "OHJ-7400 Graafisen käyttöliittymän ohjelmointi"; QFont font("arial",24); QFontMetrics metrics(font); int widthinpixels = metrics.width(text); QFontMetrics
Fontin kysyminen käyttäjältä QFontDialog dlg; if(dlg.exec() == QDialog::Accepted) { QFont f = dlg.selectedfont(); }
Järjestelmäfontti (system font) Oletusfontti, jota käytetään mikäli fonttia ei erikseen valita Esim ikkunoiden otsikoissa Fontin koko riippuu esimerkiksi käyttöjärjestelmän asetuksista (large font asetus)
Antialiasing painter.setrenderhint(qpainter::antialiasing,false); painter.drawellipse(50,50,100,100); painter.setrenderhint(qpainter::antialiasing,true); painter.drawellipse(250,50,100,100);
Tuplapuskurointi + Vähentää ikkunan välkkymistä - Lisää muistinkulutusta Voidaan toteuttaa piirtämällä ruudun sisältö ensin kuvaan ja tämän jälkeen kuva yhdellä kertaa ruudulle.
Koordinaatisto Fyysiset koordinaatit fyysinen yksikkö yksi kuvapiste, pikseli pikseli = pienin laitteen erottama kuvan mitta Loogiset koordinaatit loogiset yksiköt esitetty mittayksikköinä
Translate Muuttaa origon paikkaa koordinaatistossa painter.drawellipse(50,50,50,50); painter.translate (100,100); painter.drawellipse(50,50,50,50);
Scale Asettaa skaalauskertoimen painter.drawellipse(50,50,50,50); painter.scale (2,2); painter.drawellipse(50,50,50,50);
Rotate Kääntää koordinaatistoa painter.drawrect(50,50,50,50); painter.translate (100,100); painter.rotate(45); painter.drawrect(50,50,50,50);
Clipping Keino rajata alue, jolle piirto halutaan tapahtuvan Alueen ulkopuolelle jäävä osa jätetään piirtämättä painter.setclipping(true); painter.setcliprect(qrect(10, 10, 50, 50)); painter.drawellipse(qrect(10, 10,100, 100));