Piirtofunktiot ja ikkunan päivittäminen Juha Järvensivu juha.jarvensivu@tut.fi 2008
GDI Graphical Device Interface
Graphical Device Interface (GDI)
GDI+ Parannettu versio GDI:stä (windows XP) Toteutus.NET:ssä wrapperiluokkien avulla Graphics object private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs pe) { Graphics g = pe.graphics; }
Pen GDI-objekti reunaviivojen piirtämiseen System.Drawing.Pen Graphics g = pe.graphics; Pen mypen; mypen = new Pen(Color.Blue); g.drawrectangle(pen,100,50,80,40); mypen.dispose();
Pen Graphics g = pe.graphics; Pen mypen; mypen = new Pen(Color.Blue); mypen.width = 3; mypen.dashstyle = DashStyle.Dot; g.drawrectangle(pen,100,50,80,40); mypen.dispose();
Brush GDI-objekti alueiden maalaamiseen System.Drawing.Brush Graphics g = pe.graphics; Brush b = new SolidBrush(Color.Blue); g.fillrectangle(b, 120, 20, 50, 50); b.dispose();
System.Drawing2D using System.Drawing.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);
Graphicspath using System.Drawing.Drawing2D; Point[] points = { new Point(40, 60), new Point(50, 70), new Point(30, 90)}; GraphicsPath path = new GraphicsPath(); path.startfigure(); // Start the first figure. path.addarc(175, 50, 50, 50, 0, -180); path.addline(100, 0, 250, 20); // First figure is not closed. path.startfigure(); // Start the second figure. path.addline(50, 20, 5, 90); path.addcurve(points, 3); path.addline(50, 150, 150, 180); path.closefigure(); // Second figure is closed. e.graphics.drawpath(new Pen(Color.FromArgb(255, 255, 0, 0), 2), path);
Color GDI-objekti värin määrittämiseen Tukee myös läpinäkyvyyttä (alpha) System.Drawing.Color Color red1 = Color.Red; // Alpa, red, green, blue Color red2 = Color::FromArgb(0,255,0,0);
Värin kysyminen käyttäjältä ColorDialog dlg = new ColorDialog(); dlg.color = Color.Red; if(dlg.showdialog() == DialogResult.OK) { } Color selected = dlg.color;
Bitmap GDI-objekti kuvan piirtämiseen System.Drawing.Bitmap String filename = "C:\\Documents and Settings\\All Users\\Documents\\My Pictures\\Sample Pictures\\Sunset.jpg"; Bitmap bitmap = new Bitmap(filename); e.graphics.drawimage(bitmap,new Point(0,0));
Font System.Drawing.Font FontFamily fontfamily = new FontFamily("Arial"); Font font = new Font( fontfamily, 16, FontStyle.Regular, GraphicsUnit.Pixel);
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) 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));
Fontin kysyminen käyttäjältä FontDialog fdlg = new FontDialog(); fdlg.showcolor = true; fdlg.font = textbox1.font; fdlg.color = textbox1.forecolor; if(fdlg.showdialog()!= DialogResult.Cancel ) { textbox1.font = fdlg.font ; textbox1.forecolor = fdlg.color; }
GDI-tietorakenteita namespace System.Drawing; Point Size Rectangle
Antialiasing mygraphics.smoothingmode = SmoothingMode.AntiAlias; mygraphics.drawline(mypen, 0, 0, 12, 8); ms-help://ms.msdnqtr.v80.en/ms.msdn.v80/ms.visualstudio.v80.en/dv_fxmclignrl/html/810da1a4-c136-4abf-88df-68e49efdd8d4.htm
Piirtopinta
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);
Paint sanoma ja ikkunan päivittäminen
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); }
Tuplapuskurointi Vähentää ikkunan välkkymistä Lisää muistinkulutusta Ei oletuksena päällä formissa Form1.DoubleBuffered = false;
Koordinaatisto
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