Grafiikan piirto Juha Järvensivu juha.jarvensivu@tut.fi 2006
Sisältö GDI ja Device Context Piirtofunktioiden käyttö Koordinaatisto Tekstin piirtäminen, fontit Rajaus (clipping) Skaalautuminen (scaling) Ikkunan päivittämisen problematiikka
Graphical Device Interface (GDI) Laiteriippumaton rajapinta grafiikan piirtämiseen Sisältää joukon piirto-objekteja, joilla sovellus voi esittää tietoa graafisessa muodossa Piirto-objektit ovat pohjimmiltaan tavallisia tietorakenteita (Struct) Piirtokoodi toteutettu kahden dll-kirjaston välisenä vuorovaikutuksena GDI.dll laiteriippumattomat piirtofunktiot VGA.dll piirtofunktioiden toteutuskoodi käytössä olevalle laitteelle (tässä tapauksessa vga-näyttö)
Graphical Device Interface (GDI)
GDI-Objekteja Sivellin (Brush) GDI-objekti, jolla voi maalata laajoja alueita Kynä(Pen) GDI-objekti viivojen piirtämiseen Fontti (Font) GDI-objekti piirrettävän tekstin tyylin ja ulkoasun määrittämiseen Bittikartta (Bitmap) Väri (Color)
Device context (piirtopinta) GDI:n ylläpitämä windowsin sisäinen tietorakenne, joka sisältää piirtopintaan liittyviä atribuutteja, 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);
Device context (piirtopinta).net toteutus GDI+ Luodaan Graphicsolio Kutsutaan piirtofunktiota ja annetaan tarvittavat muuttujat parametrina
Esimerkki.NET // Luodaan sivellin Brush br = Brushes.Blue; // Piirretään suorakulmio ruudulle e.graphics.fillrectangle(br,0,0,100,100); // Vapautetaan siveltimen varaamat resurssit br.dispose();
WM_PAINT Sovellus saa WM_PAINT sanoman kun järjestelmä lähettää ikkunan päivityspyynnön Omassa sovelluksessa ei kutsuta piirtofunktiota suoraan, vaan aiheutetaan WM_PAINT sanoma, jos ikkuna pitää päivittää InvalidateWindow + UpdateWindow
Esimerkki public Form1() { this.mousemove += new MouseEventHandler(Form1_MouseMove); this.paint += new PaintEventHandler(Form1Paint); } void Form1_MouseDown(object sender, MouseEventArgs e) { x = e.x; y = e.y; this.invalidate(); this.update(); } void Form1Paint(object sender, PaintEventArgs e) { e.graphics.drawrectangle(pens.blue, x, y, 100, 100); }
System.Drawing.Graphics (.NET) GDI rajapinnan piirtometodit kapseloiva luokka Saadaan paint-eventin parametrina void PaintEventHandler(PaintEventArgs e) { Graphics g = e.graphics; } Voidaan myös pyytää Control-luokalta Graphics g = Control.CreateGraphics();
System.Drawing.Graphics Yksinkertaiset muodot DrawLine Fill / DrawRectangle Fill / DrawEllipse Fill / DrawPath Monimutkaisemmat kuviot Draw / FillPie DrawPath( GraphicsPath path) Tekstin piirto DrawText DrawImage
Kynät ja siveltimet System.Drawing.Pen Pen(Burshb) Pen(Color c) Pens.Blue System.Drawing.Bursh SolidBrush(Color c) Brushes.Blue System.Drawing.Color Color.FromArgb(int alpha, int red, int green, int blue) Color.Blue
Paint - piirtotapahtuma public class Form1 { public Form1 { this.paint += new PaintEventHandler(Form1_Paint); } } void Form1_Paint(object sender, PaintEventArgs e) { Brush b = new SolidBrush(Color.Blue); e.graphics.drawline(pens.red, 10, 10, 100, 100); e.graphics.fillrectangle(b, 120, 20, 50, 50); b.dispose(); }
Tuplapuskurointi Vähentää ikkunan välkkymistä Lisää muistinkulutusta Ei oletuksena päällä formissa Form1.DoubleBuffered = false;
Fontti System.Drawing.Font FontFamily fontfamily = new FontFamily("Arial"); Font font = new Font( fontfamily, 16, FontStyle.Regular, GraphicsUnit.Pixel);
FontDialog Valmis dialogi, jolla käyttäjä voi valita käytettävän fontin Näyttää kaikki järjestelmään asennetut fontit System.Windows.Forms.FontDialog
FontDialog private void button1_click(object sender, System.EventArgs e) { fdlg.showcolor = true; fdlg.font = textbox1.font; fdlg.color = textbox1.forecolor; } if(fdlg.showdialog()!= DialogResult.Cancel ) { textbox1.font = fdlg.font ; textbox1.forecolor = fdlg.color; }
Järjestelmäfontti (system font) Oletusfontti, jota käytetään mikäli fonttia ei erikseen valita Esim ikkunoiden otsikoissa Fontin koko riippuu esimerkiksi näytön resoluutiosta Ei yleensä muutu suorituksen aikana, joten riittää että fontin koon selvittää sovelluksen käynnistysvaiheessa.
Tekstin piirtäminen void Form1_Paint(object sender, PaintEventArgs e) { Brush b = new SolidBrush(Color.Blue); FontFamily fontfamily = new FontFamily("Arial"); Font font = new Font(fontFamily, 16, FontStyle.Regular, GraphicsUnit.Pixel); } Point p = new Point(10,10); e.grapihcs.drawstring("hello world", font, b, p);
Wrapped Text string text1 = "Draw text in a rectangle by passing a RectF to the DrawString method."; Font font1 = new Font("Arial", 12, FontStyle.Bold, GraphicsUnit.Point); RectangleF rectf1 = new RectangleF(30, 10, 100, 122); e.graphics.drawstring(text1, font1, Brushes.Blue, rectf1); e.graphics.drawrectangle(pens.black, Rectangle.Round(rectF1));
Värit (Color) Esittää ARGB värejä A Läpinäkyvyys (0-255) R Punainen (0-255) G Vihreä (0-255) B Sininen (0-255) System.Drawing.Color.FromArgb(a,r,g,b) Sisältää useita valmiiksi määriteltyjä värejä Esim Color.DarkBlue
ColorDialog ColorDialog dlg = new ColorDialog(); dlg.color = Color.Red; if(dlg.showdialog() == DialogResult.OK) { // }
System.Drawing2D Graphics g = e.graphics; LinearGradientBrush b = new LinearGradientBrush( new Point(0, 0), new Point(100, 100), Color.Red, Color.Blue); g.fillrectangle(b, 10, 10, 100, 100);
Koordinaatisto Fyysiset koordinaatit fyysinen yksikkö yksi kuvapiste, pikseli pikseli = pienin laitteen erottama kuvan mitta Loogiset koordinaatit loogiset yksiköt esitetty mittayksikköinä
Graphics.PageUnit Kertoo mitä yksikköä piirrossa käytetään GraphicsUnit Display Document (1/300 inch) Inch Millimeter Pixel Point (1/72 inch)
Graphics.TranslateTransform Muuttaa origon paikkaa koordinaatistossa Graphics g = e.graphics; Rectangle r = new Rectangle(10, 10, 50, 50); g.fillrectangle(brushes.red, r); g.translatetransform(50, 50); g.fillrectangle(brushes.blue, r);
Graphics.PageScale Asettaa skaalauskertoimen world unit page unit Graphics g = e.graphics; Rectangle r = new Rectangle(10, 10, 50, 50); g.fillrectangle(brushes.red, r); g.pagescale = 2; g.fillrectangle(brushes.blue, r);
Clipping Keino rajata alue, jolle piirto halutaan tapahtuvan Alueen ulkopuolelle jäävä osa jätetään piirtämättä Graphics g = e.graphics; Rectangle r = new Rectangle(10, 10,100, 100); g.setclip(new Rectangle(10, 10, 50, 50)); g.fillellipse(brushes.red, r);
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 aiheutetaan WM_PAINT sanoma Invalidate + Update Refresh 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ä? Invalidate Asettaa ikkunan alueen epäkelvoksi
Miten päivitetään? Pidä varsinainen piirtometodi mahdollisimman tehokkaana Älä suorita piirtometodissa turhaa laskentaa tms. Tuplapuskurointi (Double buffering) Hyödyllinen monimutkaisten piirto-operaatioiden yhteydessä Ikkunan sisältö piirretään ensin muistiin ja vasta tämän jälkeen kerralla näytölle Ikkunan taustan pyyhkiminen WM_ERASEBKGND GDI-objektin vaihtaminen (kynä, sivellin, fontti jne) Ota talteen piirtopinnalla oleva vanha objekti Aseta vanha objekti takaisin piirron jälkeen
Ikkunan koon muuttaminen Ikkuna lukitaan koon muutoksen yhteydessä Jos ikkunaa halutaan päivittää kesken koon muutoksen, täytyy lukitus purkaa LockWindowUpdate WM_SIZING Lähetetään useita kertoja ikkunan kokoa muutettaessa WM_SIZE Lähetetään aina kun ikkunan koko on muuttunut
Lähteitä Using fonts and text http://msdn2.microsoft.com/en-us/library/a3a2bads.aspx System.Drawing namespace http://msdn.microsoft.com/library/default.asp?url=/library/enus/cpref/html/frlrfsystemdrawing.asp GDI http://msdn.microsoft.com/library/default.asp?url=/library/enus/winprog/winprog/graphics_device_interface.asp Device Context http://msdn.microsoft.com/library/default.asp?url=/library/enus/gdi/devcons_0g6r.asp
Lähteitä Getting started with Graphics programming http://msdn2.microsoft.com/enus/library/da0f23z7.aspx Charles Petzold Programming windows Petzold, C. Programming Windows, 5th edition, Microsoft Press 1999. Using managed graphics classes http://msdn2.microsoft.com/enus/library/yhez825d.aspx