Enkelt histogram
Denne logikken går fram av følgende kode:
List<int> data=null; public Form1() { InitializeComponent(); data = new List<int>(100); } private void buttonDaw_Click(object sender, EventArgs e) { String[] lines = textBox1.Text.Split('\r'); data=new List<int>(lines.Length); try { foreach (string line in lines) if (line.Trim().Length > 0) data.Add(Convert.ToInt32(line.Trim())); } catch (Exception ex) { labelMsg.Text = "feil format"; } // force a redraw panel1.Invalidate(); } private void panel1_Resize(object sender, EventArgs e) { // we force a redraw when panel is sized panel1.Invalidate(); }
Vi kan lage bildet etter to strategier:
- Vi kan tegne i panelet, kopiere denne tegningen til en bitmap som vi så lagrer i det formatet vi ønsker
- Vi kan tegne direkte i en bitmap (ikke på skjermen), eventuelt kopiere til skjermen for å inspisere, og så lage bitmapen direkte.
Nedenfor finner du kode for begge strategiene
Tegne på skjermen
Vi tegner på skjermen, i panelet og kopierer til en bitmap som vi så lagrer.. Selve tegnerutina, drawData, er sitert mot slutten av modulen.
private void panel1_Paint(object sender, PaintEventArgs e) { // we draw on the panel and copy it to a bitmap // then we save it Rectangle Rec = new Rectangle(0, 0, panel1.Width, panel1.Height); drawData(e.Graphics, Rec, data); // copy the drawing to a bitmap Bitmap canvas = new Bitmap(Rec.Width, Rec.Height); Graphics bg = Graphics.FromImage(canvas); // copy from screen, in screen coordinates Rectangle screenR = panel1.RectangleToScreen(Rec); bg.CopyFromScreen(new Point(screenR.X, screenR.Y), new Point(0, 0), new Size(screenR.Width,screenR.Height)); // save the drawing canvas.Save(Path.Combine(Application.StartupPath, "bildetest.gif")); }
Tegne direkte på en bitmap
Vi tegner til en bitmap og lagrer den. I eksempelet kopierer vi bitmapen til skjermen for å inspisere, men det er ikke nødvendig for å lage bildet..
private void panel1_Paint(object sender, PaintEventArgs e) { // we draw on a bitmap and copies this bitmap to the panel // then we save it Rectangle Rec = new Rectangle(0, 0, panel1.Width, panel1.Height); Bitmap canvas = new Bitmap(Rec.Width, Rec.Height); Graphics cg = Graphics.FromImage(canvas); // set white background cg.FillRectangle(Brushes.White,Rec); drawData(cg, Rec,data); // copy the drawing to the panel e.Graphics.DrawImage(canvas,new Point(0,0)); // save the drawing canvas.Save(Path.Combine(Application.StartupPath, "bildetest.gif")); }
Selve uttegningen er gjort slik:
// draw data within Rec on g private void drawData(Graphics g,Rectangle Rec,List<int>data) { Font tFont = new Font("Arial", 16); SolidBrush blueBrush = new SolidBrush(Color.Blue); // any data to display if (data.Count == 0) { g.DrawString(" Ingen data ", tFont, blueBrush, new Point(10, 4)); } else { // find max value float max = 0.0F; foreach (int number in data) max = Math.Max((float)number, max); // Width of each column, with some margins int w = (Rec.Width - 10 * data.Count - 20) / data.Count; // flip round top and leave some room at top for text int txtheight = 20; g.ResetTransform(); g.TranslateTransform(0.0F, Rec.Height); g.ScaleTransform(1.0F, -1.0F * ((Rec.Height - txtheight) / (max + 1))); for (int ix = 0; ix < data.Count; ix++) { g.FillRectangle(Brushes.Red, new Rectangle(10 + ix * (w + 10), 0, w, data[ix])); } // text it g.ResetTransform(); g.DrawString("Resultater", tFont, blueBrush, new Point(10, 4)); } g.Flush(); }
Dette kan selvsagt gjøre på mange forskjellige måter. I slik enkle tilfeller som dette kan det kanskje være en avveining om vi skal tegne direkte i pikselkoordinater eller om vi skal transformere fra et annet koordinatsystem slik jeg har gjort.
Hvis du studerer "System.Drawing.Imaging.ImageFormat" i dokumentasjonen vil du finne at du kan spare bitmaps i en rekke andre formater enn gif.