Display an image as I manipulate it - c#

I am writing a C# program to do some scanning of the pixels in an image. This is for a program I am only going to run maybe 5 times so does not need to be efficient.
After reading each pixel I want to change it's colour and update the display of the image so I can see the scans progress and what it is finding, but I can't get anything to display. Has anyone done something like this before or know of a good example?
Edit:
The code I am trying to use at the moment is.
void Main()
{
Bitmap b = new Bitmap(#"C:\test\RKB2.bmp");
Form f1 = new Form();
f1.Height = (b.Height /10);
f1.Width = (b.Width / 10);
PictureBox PB = new PictureBox();
PB.Image = (Image)(new Bitmap(b, new Size(b.Width, b.Height)));
PB.Size = new Size(b.Width /10, b.Height /10);
PB.SizeMode = PictureBoxSizeMode.StretchImage;
f1.Controls.Add(PB);
f1.Show();
for(int y = 0; y < b.Height; y++)
{
for(int x = 0; x < b.Width; x++)
{
if(b.GetPixel(x,y).R == 0 && b.GetPixel(x,y).G == 0 && b.GetPixel(x,y).B == 0)
{
//color is black
}
if(b.GetPixel(x,y).R == 255 && b.GetPixel(x,y).G == 255 && b.GetPixel(x,y).B == 255)
{
//color is white
Bitmap tes = (Bitmap)PB.Image;
tes.SetPixel(x, y, Color.Yellow);
PB.Image = tes;
}
}
}
}

You need to separate the image processing action and the update action. A good start would be to create a Windows Forms project, add the PictureBox control to the form and a button. Bind the button to an action and in the action start the processing. Then the update process will be visible. When your code is changed to this, then the final transformation should be visible:
void Main()
{
Bitmap b = new Bitmap(#"C:\test\RKB2.bmp");
Form f1 = new Form();
f1.Height = (b.Height /10);
f1.Width = (b.Width / 10);
// size the form
f1.Size = new Size(250, 250);
PictureBox PB = new PictureBox();
PB.Image = (Image)(new Bitmap(b, new Size(b.Width, b.Height)));
PB.Size = new Size(b.Width /10, b.Height /10);
PB.SizeMode = PictureBoxSizeMode.StretchImage;
PB.SetBounds(0, 0, 100, 100);
Button start = new Button();
start.Text = "Start processing";
start.SetBounds(100, 100, 100, 35);
// bind the button Click event
// The code could be also extracted to a method:
// private void startButtonClick(object sender, EventArgs e)
// and binded like this: start.Click += startButtonClick;
start.Click += (s, e) =>
{
for(int y = 0; y < b.Height; y++)
{
for(int x = 0; x < b.Width; x++)
{
if(b.GetPixel(x,y).R == 0 && b.GetPixel(x,y).G == 0 && b.GetPixel(x,y).B == 0)
{
//color is black
}
if(b.GetPixel(x,y).R == 255 && b.GetPixel(x,y).G == 255 && b.GetPixel(x,y).B == 255)
{
//color is white
Bitmap tes = (Bitmap)PB.Image;
tes.SetPixel(x, y, Color.Yellow);
PB.Image = tes;
}
}
}
};
f1.Controls.Add(PB);
f1.Controls.Add(start);
f1.Show();
}
After the change the result (with my test image) looks like this:

Related

How to calculate cell height [that has long text] when printing DataGridView in C#

I searched but didn't find how to set the cell height when printing DataGridView when the cell has long text.
I didn't find one result that concentrate how to calculate the height with long text. And I don't want to use 3rd party DLL file that print it with right cell height.
I use this code to calculate the height but text always cut and short text has lower cell height that on DGV.
var tallestHeight = 0;
foreach (DataGridViewCell cell in GridRow.Cells)
{
if (!cell.Visible) { continue; }
var s = e.Graphics.MeasureString(cell.FormattedValue.ToString(), dataGridView1.Font);
var tempHeight = (int)(s.Height * Math.Ceiling(s.Width / dataGridView1.Columns[cell.ColumnIndex].Width));
if (tempHeight > tallestHeight)
{
tallestHeight = tempHeight;
}
tallestHeight = (tallestHeight < 22) ? 22 : tallestHeight;
}
iCellHeight = tallestHeight;
I want when I print DataGridView to printer to show all the text in all cells without cutting. Long text increase the row height and if no long text row's height stays unchanged.
I have row height = 22
Text wrap for my DataGridView is enabled
Edit1:
Here is my DataGridView properties
Here is how i print my DataGridView: PrintDGV Class that i use
My DGV appears
Print preview
Yellow highlighted text isn't complete Full text is First Middle lastname- some text- 0130011511478- تجربةة 7427/01300/8346584584563846
The text below it complete.
How to show the first row at full?
Apart from the grid settings, you need to use the output sizes to calculate the adequate height of each row to fit their contents. Also, calling a MeasureString method overload that takes StringFormat is necessary to get more accurate result.
I see in the printout image above you are dividing the MarginBounds.Width by the visible cells. Thus, the following:
Calculate
Create a method to calculate and return the proper height of each row.
// +
using System.Linq;
private int GetRowHeight(
Graphics g,
DataGridViewRow row,
Rectangle bounds,
StringFormat sf,
int minHeight = 22)
{
var cells = row.Cells.OfType<DataGridViewTextBoxCell>()
.Where(c => c.Visible);
if (cells == null) return minHeight;
var cell = cells.Aggregate((DataGridViewTextBoxCell)null, (x, y) => x != null &&
x.FormattedValue.ToString().Length > y.FormattedValue.ToString().Length ? x : y);
if (cell == null) return minHeight;
var h = g.MeasureString(cell.FormattedValue.ToString(),
row.DataGridView.Font,
new SizeF(bounds.Width / cells.Count(), bounds.Height),
sf).ToSize().Height;
return Math.Max(h + 6, minHeight); // 6 for top and bottom margins...
}
Call
Caller example and class variables to track the printing...
// +
using System.Drawing.Printing;
private int rowIndex;
private int cellCount;
private int pageNumber;
private readonly PrintDocument printDoc;
// ...
// ctor
public YourForm()
{
InitializeComponent();
printDoc = new PrintDocument();
printDoc.PrintPage += OnPrintPage;
}
// Cleanup
private void YourForm_FormClosed(object sender, FormClosedEventArgs e)
{
printDoc.Dispose();
}
// Preview
private void btnPrintPreview(object sender, EventArgs e) => Print(true);
// Print
private void btnPrint(object sender, EventArgs e) => Print();
// Print Routine
private void Print(bool preview = false)
{
rowIndex = 0;
cellCount = 0;
pageNumber = 0;
var rows = dataGridView1.Rows
.Cast<DataGridViewRow>()
.FirstOrDefault(r => !r.IsNewRow);
if (rows != null)
cellCount = rows.Cells
.OfType<DataGridViewTextBoxCell>()
.Where(c => c.Visible)
.Count();
if (cellCount == 0)
{
MessageBox.Show("Nothing to print...");
return;
}
printDoc.DefaultPageSettings.Landscape = true;
if (preview)
{
using (var pd = new PrintPreviewDialog())
{
pd.Document = printDoc;
pd.ShowDialog();
}
}
else
{
using (var pd = new PrintDialog())
{
pd.Document = printDoc;
if (pd.ShowDialog() == DialogResult.OK)
pd.Document.Print();
}
}
}
Print
PrintDocument.PrintPage event example.
// +
using System.Drawing.Text;
private void OnPrintPage(object sender, PrintPageEventArgs e)
{
var w = e.MarginBounds.Width / cellCount;
var x = e.MarginBounds.X;
var y = e.MarginBounds.Y;
int h;
Rectangle rec;
using (var sf = new StringFormat())
{
sf.Alignment = StringAlignment.Center;
sf.LineAlignment = StringAlignment.Center;
// Maybe you need to set this? I see Arabic text in the images.
// sf.FormatFlags = StringFormatFlags.DirectionRightToLeft;
e.Graphics.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
// Uncomment to print the headers in the first page only.
//if (pageNumber == 0)
//{
h = dataGridView1.RowTemplate.Height;
foreach (var col in dataGridView1.Columns
.OfType<DataGridViewTextBoxColumn>()
.Where(c => c.Visible))
{
rec = new Rectangle(x, y, w, h);
e.Graphics.FillRectangle(Brushes.Gainsboro, rec);
e.Graphics.DrawString(
col.HeaderText,
col.DataGridView.Font,
Brushes.Black,
rec,
sf);
e.Graphics.DrawRectangle(Pens.Black, rec);
x += w;
}
x = e.MarginBounds.X;
y += h;
//}
for (var i = rowIndex; i < dataGridView1.RowCount; i++)
{
var row = dataGridView1.Rows[i];
if (row.IsNewRow) break;
h = GetRowHeight(e.Graphics, row, e.MarginBounds, sf);
if (h > e.MarginBounds.Height)
{
MessageBox.Show("Insufficient height.");
e.Cancel = true;
return;
}
foreach (var cell in row.Cells
.OfType<DataGridViewTextBoxCell>()
.Where(c => c.Visible))
{
rec = new Rectangle(x, y, w, h);
if (rec.Bottom > e.MarginBounds.Bottom)
{
pageNumber++;
rowIndex = i;
e.HasMorePages = true;
return;
}
e.Graphics.DrawString(
cell.FormattedValue.ToString(),
dataGridView1.Font,
Brushes.Black,
rec,
sf);
e.Graphics.DrawRectangle(Pens.Black, rec);
x += rec.Width;
}
x = e.MarginBounds.X;
y += h;
}
}
}
Output

Use a KeyDown inside a Timer_Tick Event

Me and my buddy have been working on this magnifier application and we cannot make it work the way we want it.
The way we would like it to work:
Open app.
Move mouse to area you want magnified.
Hit enter.
Magnifying window moves to (offset) location of mouse and keeps updating that window for that specific location.
Hit enter again to move window to new cursor location.
Right now once i hit enter, the window follows the mouse because it goes into a for loop where it grabs "Cursor.Position". I've tried to save the Cursor.Position value at the "OnkeyDown" event and use it inside the timer loop but that won't work since it "does not exist in current context".
Can anyone see how i can do this?
Thanks in advance!
/Morten
/* O-button zooms out
* I-button zooms in
* Esc-button exits app
* Enter moves magnifying window to new location (doesn't work)
*/
using System;
using System.Drawing;
using System.Windows.Forms;
namespace Magnifier
{
public partial class Form1 : Form
{
Bitmap printscreen = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
PictureBox pictureBox1 = new PictureBox();
int zoom = 3; //zoom level
public bool NewZoomLocation = false;
public Form1()
{
{
InitializeComponent();
pictureBox1.Dock = DockStyle.Fill;
pictureBox1.BorderStyle = BorderStyle.FixedSingle;
Controls.Add(pictureBox1);
FormBorderStyle = FormBorderStyle.None;
Timer timer = new Timer();
timer.Interval = 100;
timer.Tick += timer_Tick;
timer.Start();
}
void timer_Tick(object sender, EventArgs e)
{ var position = Cursor.Position;
int xlocation = position.X;
int ylocation = position.Y;
{
try
{
var graphics = Graphics.FromImage(printscreen as Image);
graphics.CopyFromScreen(0, 0, 0, 0, printscreen.Size);
GC.Collect(); // Force the garbage collector (deals with memory leak)
if (NewZoomLocation == true)
{
var lensbmp = new Bitmap(50, 50); //Bitmap for Zoom window
var i = 0;
var j = 0;
for (int row = xlocation - 25; row < xlocation + 25; row++)
{
j = 0;
for (int column = ylocation - 25; column < ylocation + 25; column++)
{
lensbmp.SetPixel(i, j, printscreen.GetPixel(row, column));
j++;
}
i++;
}
this.pictureBox1.Image = new Bitmap(lensbmp, lensbmp.Width * zoom, lensbmp.Height * zoom);
Size = pictureBox1.Image.Size;
Left = xlocation - 45 * (zoom); //Horisontal position of final zoom window
Top = ylocation + 30; //Vertical position of final zoom window
TopMost = true;
}
}
catch //(Exception ex)
{
//MessageBox.Show(ex.Message);
}
}
}
}
protected override void OnKeyDown(KeyEventArgs e)
{
if (e.KeyValue == 73) // I-button to zoom in
zoom++;
else if (e.KeyValue == 79) // O-button to zoom in
zoom--;
else if (e.KeyValue == 27) // Esc-button to exit
{
Close();
Dispose();
}
else if (e.KeyValue == 13) // Enter-button to choose zoon area
{
NewZoomLocation = true;
}
base.OnKeyDown(e);
}
}
}
I'm not really sure what you want to achieve here, however this should get you in a better place.
First thing first. The use of GC.Collect its because you are trying to plug a memory leak, if you ever create an image, dispose of it.
Given some globals
private readonly PictureBox pictureBox1 = new PictureBox();
private Bitmap _lastBmp = new Bitmap(300, 300);
private Point _position;
public bool NewZoomLocation;
private int zoom = 3; //zoom level
Constructor
public Form1()
{
InitializeComponent();
pictureBox1.Dock = DockStyle.Fill;
pictureBox1.BorderStyle = BorderStyle.FixedSingle;
Controls.Add(pictureBox1);
FormBorderStyle = FormBorderStyle.None;
KeyPreview = true;
Size = _lastBmp.Size;
TopMost = true;
var timer = new Timer();
timer.Interval = 100;
timer.Tick += timer_Tick;
timer.Start();
}
Cleanup
protected override void OnClosed(EventArgs e)
{
base.OnClosed(e);
_lastBmp.Dispose();
_lastBmp = null;
}
Keydown
protected override void OnPreviewKeyDown(PreviewKeyDownEventArgs e)
{
base.OnPreviewKeyDown(e);
switch (e.KeyCode)
{
case Keys.Enter:
NewZoomLocation = true;
_position = Cursor.Position;
break;
case Keys.Up:
zoom++;
break;
case Keys.Down:
zoom--;
break;
case Keys.Escape:
Close();
break;
}
}
Timer
private void timer_Tick(object sender, EventArgs e)
{
if (NewZoomLocation)
{
var w = _lastBmp.Size.Width / zoom;
var h = _lastBmp.Size.Height / zoom;
var x = _position.X - w / 2;
var y = _position.Y - h / 2;
var size = new Size(w, h);
using (var screen = new Bitmap(size.Width, size.Height))
{
using (var g = Graphics.FromImage(screen))
{
g.CopyFromScreen(new Point(x, y), Point.Empty, size);
}
// resize
using (var g = Graphics.FromImage(_lastBmp))
{
g.DrawImage(screen, new Rectangle(new Point(), _lastBmp.Size), new Rectangle(0, 0, w, h), GraphicsUnit.Pixel);
}
}
pictureBox1.Image = _lastBmp;
}
}
There is a lot more that can be done with this, however it should get you started. There is no memory leak anymore, it only grabs a screen shot of what it needs so will be faster.
Good luck

couldn't change active tabPage with button c#

I have a MetroTabControl named mtcNewExpTabControl with four pages(mtpSettings, mtpNewExp, mtpTempImages, mtpCompareImages). I am starting New Experiment on mtpNewExp page and get image after clicking "StartExperiment" button. User can get many images. After completion of experiment, I add images to imageList1.Images.
When I click on the mtpTempImages tabPage mtcNewExpTabControl_SelectedIndexChanged triggered and images are displayed with combobox named with imageList1.Images.Keys[i]. I can show many combobox and picturebox pairs on mtpTempImages.
On mtpTempImages there is also a mtbCompareImages button. User can check checkboxes next to the picturebox named same with checboxName. After checking all the checkboxes needed to compared, user will click on the "Compare Images" button. I want to change active tabPage to mtpCompareImages without clicking on the tab. mtbCompareImages button should be enough for that. I can show images on mtpTempImages but I could not succeded that on mtpCompareImages tabpage. Active tabPage also do not change to mtpCompareImages tabPage. What should I do?
List<MetroCheckBox> cbxTempImages = new List<MetroCheckBox>();
List<MetroCheckBox> cbxCompareImages = new List<MetroCheckBox>();
List<PictureBox> pbxTempImages = new List<PictureBox>();
List<PictureBox> pbxCompareImages = new List<PictureBox>();
private void mtbCompareImages_Click(object sender, EventArgs e)
{
for (int i = 0; i < cbxTempImages.Count(); i++)
{
if (cbxTempImages[i].Checked == true)
{
imageListChecked.Images.Add(pbxTempImages[i].Name, pbxTempImages[i].Image);
}
}
this.mtcNewExpTabControl.SelectedTab = mtpCompareImages;
}
private void mtcNewExpTabControl_SelectedIndexChanged(object sender, EventArgs e)
{
if((MetroTabPage)this.mtcNewExpTabControl.SelectedTab == mtpTempImages)
{
for (int i = 0; i < imageList1.Images.Count; i++)
{
cbxTempImages.Add(new MetroCheckBox());
cbxTempImages[i].Name = imageList1.Images.Keys[i].ToString();
cbxTempImages[i].Size = new Size(15, 15);
cbxTempImages[i].BackColor = Color.Transparent;
cbxTempImages[i].Location = new Point(x, y);
//PictureBox pic = new PictureBox();
pbxTempImages.Add(new PictureBox());
pbxTempImages[i].Name = imageList1.Images.Keys[i].ToString();
pbxTempImages[i].Image = imageList1.Images[i];
pbxTempImages[i].SizeMode = PictureBoxSizeMode.StretchImage;
pbxTempImages[i].Location = new Point(x + 15, y);
x += 120;
if (x > this.pnlTempImages.Width - 120)
{
x = 10; y += 100;
}
this.pnlTempImages.Controls.Add(cbxTempImages[i]);
this.pnlTempImages.Controls.Add(pbxTempImages[i]);
}
}
else if((MetroTabPage)this.mtcNewExpTabControl.SelectedTab == mtpCompareImages)
{
x = 10; y = 10;
for (int i = 0; i < imageListChecked.Images.Count; i++)
{
cbxCompareImages.Add(new MetroCheckBox());
//MetroCheckBox cbxCI = new MetroCheckBox();
cbxCompareImages[i].Name = imageListChecked.Images.Keys[i].ToString();
cbxCompareImages[i].Size = new Size(15, 15);
cbxCompareImages[i].BackColor = Color.Transparent;
cbxCompareImages[i].Location = new Point(x, y);
//PictureBox picCI = new PictureBox();
pbxCompareImages.Add(new PictureBox());
pbxCompareImages[i].Name = imageListChecked.Images.Keys[i].ToString();
pbxCompareImages[i].Image = imageListChecked.Images[i];
pbxCompareImages[i].SizeMode = PictureBoxSizeMode.StretchImage;
pbxCompareImages[i].Location = new Point(x + 15, y);
x += 120;
if (x > this.pnlCompareImages.Width - 120)
{
x = 10; y += 100;
}
this.pnlCompareImages.Controls.Add(cbxCompareImages[i]);
this.pnlCompareImages.Controls.Add(pbxCompareImages[i]);
}
}
InitializeComponent();
}

how to give a panel its exact size in c#?

I'm not an English user,so forgive me for grammatical problems please. Smile | :)
I have some paper forms that i want to print some labels on them.these papers have special size(24 cm * 14).so I made a panel(907 pixel * 529 pixel) and i put my labels on it(I converted cm to pixel and i put labels in the special parts of my panel).these labels are going to be printed in empty fields of my paper forms.but the problem is that, just the first form can be printed in the right style.others are printed in upper place of the form. I thought it may be because of I didn't give my panel and labels exact size in pixel. but i couldn't give my panel exact size in pixels,coz it doesn't accept pixels in decimal. any ideas?
this is a part of my code:
private void printDocument1_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
{
Pen blackPen = new Pen(Color.Black, 1);
e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
e.Graphics.DrawLine(blackPen, 188, 400, 302, 400);
e.Graphics.DrawRectangle(blackPen, 330, 319, 122, 55);
e.Graphics.DrawString(label20.Text, label20.Font, new SolidBrush(label20.ForeColor), label20.Location);
e.Graphics.DrawString(label21.Text, label21.Font, new SolidBrush(label21.ForeColor), label21.Location);
e.Graphics.DrawString(label23.Text, label23.Font, new SolidBrush(label23.ForeColor), label23.Location);
e.Graphics.DrawString(label24.Text, label24.Font, new SolidBrush(label24.ForeColor), label24.Location);
e.Graphics.DrawString(label25.Text, label25.Font, new SolidBrush(label25.ForeColor), label25.Location);
e.Graphics.DrawString(label26.Text, label26.Font, new SolidBrush(label26.ForeColor), label26.Location);
e.Graphics.DrawString(label27.Text, label27.Font, new SolidBrush(label27.ForeColor), label27.Location);
e.Graphics.DrawString(lbl_kod.Text, lbl_kod.Font, new SolidBrush(lbl_kod.ForeColor), lbl_kod.Location);
e.Graphics.DrawString(lbl_ttarikh.Text, lbl_ttarikh.Font, new SolidBrush(lbl_ttarikh.ForeColor), lbl_ttarikh.Location);
e.Graphics.DrawString(lbl_ctot25.Text, lbl_ctot25.Font, new SolidBrush(lbl_ctot25.ForeColor), lbl_ctot25.Location);
e.Graphics.DrawString(lbl_pricetot25.Text, lbl_pricetot25.Font, new SolidBrush(lbl_pricetot25.ForeColor), lbl_pricetot25.Location);
e.Graphics.DrawString(lbl_pricetot.Text, lbl_pricetot.Font, new SolidBrush(lbl_pricetot.ForeColor), lbl_pricetot.Location);
e.Graphics.DrawString(lbl_pricetoth.Text, lbl_pricetoth.Font, new SolidBrush(lbl_pricetoth.ForeColor), lbl_pricetoth.Location);
e.Graphics.DrawString(lbl_name.Text, lbl_name.Font, new SolidBrush(lbl_name.ForeColor), lbl_name.Location);
e.Graphics.DrawString(lbl_dtarikh.Text, lbl_dtarikh.Font, new SolidBrush(lbl_dtarikh.ForeColor), lbl_dtarikh.Location);
}
and the print region for each paper form:
for (int i = 0; i < dataGridView1.RowCount && k < 3878; i++)
{
k = Convert.ToInt32(dataGridView1.Rows[i].Cells[0].Value);
bool found = false;
ctot25 = Convert.ToInt32(dataGridView1.Rows[i].Cells[13].Value);
ctot50 = Convert.ToInt32(dataGridView1.Rows[i].Cells[14].Value);
ctot100 = Convert.ToInt32(dataGridView1.Rows[i].Cells[15].Value);
foreach (object row1 in hoome)
if (row1.ToString() == (dataGridView1.Rows[i].Cells[0].Value).ToString())
{
found = true;
}
if (found == false)
{
if (i > 0 && ctot25 != 0 || ctot50 != 0 || ctot100 != 0)
{
#region tarikh
string date = dataGridView1.Rows[i].Cells[8].Value.ToString();
var aStringBuilder = new StringBuilder(date);
aStringBuilder.Insert(2, "/");
aStringBuilder.Insert(5, "/");
lbl_dtarikh.Text = aStringBuilder.ToString();
lbl_ttarikh.Text = datestringbuilder.ToString();
#endregion
decimal pricetot25;
pricetot25 = ctot25 * price25;
lbl_name.Text = (dataGridView1.Rows[i].Cells[1].Value).ToString();
lbl_kod.Text = (dataGridView1.Rows[i].Cells[0].Value).ToString();
lbl_ctot25.Text = (ctot25).ToString();
lbl_pricetot25.Text = (pricetot25).ToString();
lbl_pricetoth.Text = num2str(pricetot.ToString()) + " ریال" + "//";
#region print
System.Drawing.Printing.PrintDocument doc = new System.Drawing.Printing.PrintDocument();
doc.PrintPage += new System.Drawing.Printing.PrintPageEventHandler(printDocument1_PrintPage);
PrintDialog PrintSettings = new PrintDialog();
PrintSettings.Document = doc;
PageSettings pgsetting = new PageSettings();
doc.Print();
#endregion
}
}
}
here is a link to my screenshot:
my panel
Since your question is a little unclear, I think you better not to add your panel in design layout and create it programmatically. It'd be better if u take a screenshot of your second page.
EDIT:
Try creating labels in your FOR loop. You can drop panel in this way. I hope it works
if (found == false)
{
if (i > 0 && ctot25 != 0 || ctot50 != 0 || ctot100 != 0)
{
//Somthethin
Label lbl_Name = new Label { Location = new Point(50, 50), Text = (dataGridView1.Rows[i].Cells[1].Value).ToString() };
this.Controls.Add(lbl_Name);
//The rest of the codes
}
}

Fastest way to draw shapes (Line, FilledRectangle, Rectangle etc)

I am working on a project using .Net Compact Framework 3.5 using C# 3.0.
I have a user control which receives data every 15 miliseconds and I have to draw shapes
like lines, rectangle, filled rectangles on user control.
I want to know what is the fastest way to draw these shapes, I am also open to use P/Invoke methods if there are some to increase performance and speed.
The code I am using is as follows:
private void DrawThreeFunctions(Graphics g)
{
// drawing back functions
if (DisplayFunction1.DrawOrder == DrawOrder.Back && GraphDataArray.Length > 0)
{
DrawFunction(g, DisplayFunction1, GraphDataArray[0]);
}
if (DisplayFunction2.DrawOrder == DrawOrder.Back && GraphDataArray.Length > 1)
{
DrawFunction(g, DisplayFunction2, GraphDataArray[1]);
}
if (DisplayFunction3.DrawOrder == DrawOrder.Back && GraphDataArray.Length > 2)
{
DrawFunction(g, DisplayFunction3, GraphDataArray[2]);
}
// drawing middle functions
if (DisplayFunction1.DrawOrder == DrawOrder.Middle && GraphDataArray.Length > 0)
{
DrawFunction(g, DisplayFunction1, GraphDataArray[0]);
}
if (DisplayFunction2.DrawOrder == DrawOrder.Middle && GraphDataArray.Length > 1)
{
DrawFunction(g, DisplayFunction2, GraphDataArray[1]);
}
if (DisplayFunction3.DrawOrder == DrawOrder.Middle && GraphDataArray.Length > 2)
{
DrawFunction(g, DisplayFunction3, GraphDataArray[2]);
}
// drawing front functions
if (DisplayFunction1.DrawOrder == DrawOrder.Front && GraphDataArray.Length > 0)
{
DrawFunction(g, DisplayFunction1, GraphDataArray[0]);
}
if (DisplayFunction2.DrawOrder == DrawOrder.Front && GraphDataArray.Length > 1)
{
DrawFunction(g, DisplayFunction2, GraphDataArray[1]);
}
if (DisplayFunction3.DrawOrder == DrawOrder.Front && GraphDataArray.Length > 2)
{
DrawFunction(g, DisplayFunction3, GraphDataArray[2]);
}
}
private void DrawFunction(Graphics g, DisplayFunction function, int[] data)
{
Color color = Utils.GetColor(function.Color);
switch (function.Shape)
{
case FunctionShape.StepLine:
DrawStepLines(g, data, color);
break;
case FunctionShape.Rectangle:
DrawFilledRectangles(g, data, color);
break;
case FunctionShape.FramedRectangle:
DrawFramedRectangles(g, data, color);
break;
case FunctionShape.Line:
DrawLines(g, data, color);
break;
default:
break;
}
}
#region Drawing methods
// drawing lines
private void DrawLines(Graphics g, int[] lineData, Color lineColor)
{
BarPositions = new List<int>();
List<Point> linePoints = new List<Point>();
int lineYPos = -1;
int lineXPos = FirstBarDrawPosition;
Point point = Point.Empty;
using (Pen linePen = new Pen(lineColor, 2.0f))
{
for (int i = FirstVisibleItemIndex, k = 0; i < _indexLimit; i++, k++)
{
if (base.GetBarEndPosition(k) > Width)
break;
lineXPos = GetTickPosition(k);
BarPositions.Add(lineXPos);
if (i < lineData.Length)
lineYPos = lineData[i];
else
continue;
point.X = lineXPos;
point.Y = lineYPos;
linePoints.Add(point);
}
if (linePoints.Any())
{
g.DrawLines(linePen, linePoints.ToArray());
}
}
}
// drawing framed rectangles
private void DrawFramedRectangles(Graphics g, int[] functionValues, Color functionColor)
{
BarPositions = new List<int>();
int barXPos = FirstBarDrawPosition;
Rectangle barRect = Rectangle.Empty;
barRect.Width = WidthOfBar - 1;
int barYPos = -1;
using (Pen barPen = new Pen(functionColor))
{
for (int i = FirstVisibleItemIndex, k = 0; i < _indexLimit; i++, k++)
{
if (base.GetBarEndPosition(k) > Width)
return;
BarPositions.Add(GetTickPosition(k));
if (i < functionValues.Length)
barYPos = functionValues[i];
else
continue;
//barRect = new Rectangle();
barRect.X = barXPos;
barRect.Y = barYPos;
//barRect.Width = WidthOfBar - 1;
barRect.Height = Height - barYPos;
g.DrawRectangle(barPen, barRect);
barXPos += (WidthOfBar + DistanceBetweenBars);
}
}
}
// drawing filled rectangles
private void DrawFilledRectangles(Graphics g, int[] functionValues, Color functionColor)
{
BarPositions = new List<int>();
int barXPos = FirstBarDrawPosition;
Rectangle barRect = Rectangle.Empty;
barRect.Width = WidthOfBar;
int barYPos = -1;
using (SolidBrush barBrush = new SolidBrush(functionColor))
{
for (int i = FirstVisibleItemIndex, k = 0; i < _indexLimit; i++, k++)
{
if (base.GetBarEndPosition(k) > Width)
return;
BarPositions.Add(GetTickPosition(k));
if (i < functionValues.Length)
barYPos = functionValues[i];
else
continue;
//barRect = new Rectangle();
barRect.X = barXPos;
barRect.Y = barYPos;
//barRect.Width = WidthOfBar;
barRect.Height = Height - barYPos;
g.FillRectangle(barBrush, barRect);
barXPos += (WidthOfBar + DistanceBetweenBars);
}
}
}
private void DrawStepLines(Graphics g, int[] lineData, Color lineColor)
{
BarPositions = new List<int>();
int lineYPos = -1;
int barXPos = FirstBarDrawPosition;
using (Pen linePen = new Pen(lineColor, 2.0f))
{
for (int i = FirstVisibleItemIndex, k = 0; i < _indexLimit; i++, k++)
{
if (base.GetBarEndPosition(k) > Width)
return;
BarPositions.Add(GetTickPosition(k));
if (i < lineData.Length)
lineYPos = lineData[i];
else
continue;
// draw third function line
//lineHeight = lineData[i];
g.DrawLine(linePen, barXPos, lineYPos, barXPos + WidthOfBar - 1, lineYPos);
barXPos += (WidthOfBar + DistanceBetweenBars);
}
}
}
I am using drawing order and shape like step line , line , framed rectangle ( just rectangle ) and rectangle is filled rectangle.
Because of performance critical application I want to know the fastest way of drawing these shapes.
Thanks in advance for any suggestion.
Are you familiar with double-buffering? Keep an offscreen image buffer to do your writes to as the changes come in. Then override the OnPaint to blit the whole image in one statement. Also, override the OnPaintBackground with a no-op to get rid of the default behavior of clearing the control to its backcolor on each paint.
Old as the hills, but here is an article on some best-practices on using GDI in the Compact Framework.

Categories