Graphics.DrawLine lags when PictureBox SizeMode is set to Zoom - c#

I have a winforms app where I draw on an image in a picturebox. The drawing part works really well, except for lag when PictureBox.SizeMode = PictureBoxSizeMode.Zoom. The reason I set the SizeMode to Zoom is so I could zoom in and out of the image while preserving memory. Is there any way to speed up the drawing process?
The code for the PictureBox's Paint method looks like so:
pen = new Pen(color, 5);
solidBrush = new SolidBrush(solid);
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
e.Graphics.ScaleTransform(PictureScale, PictureScale);
foreach (List<Point> polygon in Polygons)
{
e.Graphics.DrawLines(pen, polygon.ToArray());
}
if (NewPolygon != null)
{
Pen pp = new Pen(color, 5);
if (NewPolygon.Count > 1)
{
e.Graphics.DrawLines(pp, NewPolygon.ToArray());
}
if (NewPolygon.Count > 0)
{
using (Pen dashed_pen = pp)
{
dashed_pen.DashPattern = new float[] { 3, 3 };
e.Graphics.DrawLine(dashed_pen, NewPolygon[NewPolygon.Count - 1], NewPoint);
}
}
}
The code allows the user to draw a series of points connected by some solid lines. After adding the first point, there is a dotted line going from the previous point to the mouse's current position. The program 'fills' in the line when the user adds a new Point NewPolygon is a List<Point> object, and the program adds a point every time the user clicks. Pol is a List<List<Point>> object which holds NewPolygon. I attached a GIF of the drawing process because an image is worth 1000 words. The lag in the gif is not noticeable at all in different size modes.
The if (NewPolygon.Count > 1) loop draws solid lines between at least 2 points. The if (NewPolygon.Count > 0) draws a dotted line between spot and NewPoint when there is at least one point.
EDIT : full drawing code
int x = 0;
int y = 0;
bool drag = false;
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
Point spot = new Point((int)((float)(e.Location.X) / PictureScale), (int)((float)(e.Location.Y) / PictureScale));
if (e.Button == MouseButtons.Middle)
{
x = e.X;
y = e.Y;
drag = true;
}
else
{
if (NewPolygon != null)
{
if (e.Button == MouseButtons.Right)
{
if (NewPolygon.Count > 1)
{
int counter = NewPolygon.Count;
Polygons.Add(NewPolygon);
}
NewPolygon = null;
}
else if (e.Button == MouseButtons.Left)
{
if (NewPolygon[NewPolygon.Count - 1] != spot)
{
NewPolygon.Add(spot);
scaffolds.Add(new Rectangle(spot.X - 3, spot.Y - 3, 6, 6));
}
}
}
else
{
NewPolygon = new List<Point>();
NewPoint = spot;
NewPolygon.Add(spot);
scaffolds.Add(new Rectangle(spot.X - 3, spot.Y - 3, 6, 6));
}
}
//this.Capture = true;
pictureBox1.Refresh();
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if (drag)
{
pictureBox1.Top += e.Y - y;
pictureBox1.Left += e.X - x;
this.Cursor = Cursors.SizeAll;
}
else
{
if (NewPolygon == null)
return;
NewPoint = new Point((int)((float)(e.Location.X) / PictureScale), (int)((float)(e.Location.Y) / PictureScale));
pictureBox1.Refresh();
}
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
e.Graphics.ScaleTransform(PictureScale, PictureScale);
foreach (Rectangle rect in scaffolds)
{
e.Graphics.DrawEllipse(pen, rect);
}
foreach (List<Point> polygon in Polygons)
{
e.Graphics.DrawLines(pen, polygon.ToArray());
}
if (NewPolygon != null)
{
Pen pp = new Pen(color, 5);
if (NewPolygon.Count > 0)
{
if (NewPolygon.Count > 1)
{
e.Graphics.DrawLines(pp, NewPolygon.ToArray());
}
using (Pen dashed_pen = pp)
{
dashed_pen.DashPattern = new float[] { 3, 3 };
e.Graphics.DrawLine(dashed_pen, NewPolygon[NewPolygon.Count - 1], NewPoint);
}
}
}
}

Related

Redrawing a picturebox drawing without flickering or lag

I've drawn a grid on a picturebox with .drawline I then let users click a cell on this grid to change the colour. I'm doing this through setting a value for colour for each cell (clicking sets it to 1)
The only way I can get it to update is on mouse up which causes problems with the pathfinding algorithms I'm testing. I tried putting it on a timer but it flickers too much.
You can see the problem here
The pathfinding algorithm finishes but the grid doesn't update until I click the grid.
private void pictureBox1_MouseClick(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
GetX(this, e);
GetY(this, e);
if (DrawCase == "Wall") {
if (gridmatrix[XClick, YClick].COLOUR == 0) //If tile is white and left mouse is pressed
{
gridmatrix[XClick, YClick].COLOUR = 1; //Set colour to 1 (place a wall)
}
else if (gridmatrix[XClick, YClick].COLOUR == 1) //If tile is a wall and left mouse is pressed
{
gridmatrix[XClick, YClick].COLOUR = 0; //Set to empty
}
}
Grid is updated on MouseUp... (How else could I update the grid?)
private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
mousedown = false;
int rowcolumn = Convert.ToInt32(textBox1.Text); //Gets the dimensions from the users input
cellsize = (pictureBox1.Width / rowcolumn);
if (pictureBox1.Image == null)//if no available bitmap exists on the picturebox to draw on
{
//create a new bitmap
Bitmap bmp = new Bitmap(pictureBox1.Width, pictureBox1.Height);
pictureBox1.Image = bmp; //assign the picturebox.Image property to the bitmap created
}
for (int i = 0; i < gridmatrix.GetLength(0); i++)
{
for (int j = 0; j < gridmatrix.GetLength(1); j++)
{
Rectangle rect = new Rectangle(gridmatrix[i, j].X * cellsize, reverseYvalues[gridmatrix[i, j].Y] * cellsize, cellsize, cellsize); //Positioning and sizing for the rectangle
if (gridmatrix[i, j].COLOUR == 0)
{
using (Graphics g = Graphics.FromImage(pictureBox1.Image))
{
g.FillRectangle(Brushes.White, rect);
}
}
else if (gridmatrix[i, j].COLOUR == 1)
{
using (Graphics g = Graphics.FromImage(pictureBox1.Image))
{
g.FillRectangle(Brushes.Blue, rect);
}
}
}
}
}

How to change the color of the line when hover including all the nearest points of the other line

I just want to ask how to dynamically change the color of the hovered line and the nearest points of the line.
private void Solid_Green_MouseMove_NotDown(object sender, MouseEventArgs e)
{
Pen red = new Pen(Color.Red, 1);
red.DashPattern = new float[] { 5.0F, 5.0F, 5.0F, 5.0F };
Pen Red = new Pen(Color.Red, 1);
Graphics g = this.CreateGraphics();
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.High;
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
Point hit_point;
int segment_number;
if (MouseIsOverEndpoint(e.Location, out segment_number, out hit_point))
{
g.DrawLine(Red, Pt1[segment_number], Pt2[segment_number]);
}
else if (MouseIsOverSegment(e.Location, out segment_number))
{
g.DrawLine(Red, Pt1[segment_number], Pt2[segment_number]);
int other_side;
int other_other_side;
int other_other_other_side;
int other_other_other_other_side;
if (MouseIsOverSegment(Pt1[segment_number], out other_side) || MouseIsOverSegment(Pt2[segment_number], out other_side))
{
g.DrawLine(Red, Pt1[other_side], Pt2[other_side]);
if (MouseIsOverSegment(Pt1[other_side], out other_other_side) || MouseIsOverSegment(Pt2[other_side], out other_other_side))
{
g.DrawLine(Red, Pt1[other_other_side], Pt2[other_other_side]);
if (MouseIsOverSegment(Pt1[other_other_side], out other_other_other_side))
{
g.DrawLine(Red, Pt1[other_other_other_side], Pt2[other_other_other_side]);
if (MouseIsOverSegment(Pt1[other_other_other_side], out other_other_other_other_side))
{
g.DrawLine(Red, Pt1[other_other_other_other_side], Pt2[other_other_other_other_side]);
}
}
}
}
}}
Here is my code so far. I want to improve it like minimizing the usage of if else condition and become dynamic.

c# How can I move a picturebox by a vScrollbar?

I have a pictureBox in c# and I have to move it by a vScrollBar.
It should be like this: (pseudo-code!)
if (scrollbar.ScrollUp)
{
int i = 0;
i += +1 per scroll
pictureBox.Location = new Point(0, i);
}
if (scrollbar.ScrollDown)
{
int k = 0;
k += -1 per scroll
pictureBox.Location = new Point(0, k);
}
I hope someone can understand my problem. Thanks
The example for the MSDN ScrollBar.Scroll event actually shows how to scroll a PictureBox.
Code from MSDN:
private void HandleScroll(Object sender, ScrollEventArgs e)
{
//Create a graphics object and draw a portion of the image in the PictureBox.
Graphics g = pictureBox1.CreateGraphics();
int xWidth = pictureBox1.Width;
int yHeight = pictureBox1.Height;
int x;
int y;
if (e.ScrollOrientation == ScrollOrientation.HorizontalScroll)
{
x = e.NewValue;
y = vScrollBar1.Value;
}
else //e.ScrollOrientation == ScrollOrientation.VerticalScroll
{
y = e.NewValue;
x = hScrollBar1.Value;
}
g.DrawImage(pictureBox1.Image,
new Rectangle(0, 0, xWidth, yHeight), //where to draw the image
new Rectangle(x, y, xWidth, yHeight), //the portion of the image to draw
GraphicsUnit.Pixel);
pictureBox1.Update();
}
Where HandleScroll is the event handler for the ScrollBar's Scroll event.
scrollBar1.Scroll += HandleScroll;
This is assuming you are trying to scroll the PictureBox. If you really just want to move it around, you could try the following:
private void HandleScroll(Object sender, ScrollEventArgs e)
{
var diff = scrollBar1.Value - e.NewValue;
if (e.ScrollOrientation == ScrollOrientation.HorizontalScroll)
{
pictureBox1.Location = new Point(diff, pictureBox1.Location.Y);
}
else //e.ScrollOrientation == ScrollOrientation.VerticalScroll
{
pictureBox1.Location = new Point(pictureBox1.Location.X, diff);
}
}
Warning, this code has not been tested.

How do i make that when i select different item in the listBox it will show me the cropped image for that item?

listbox selected index event:
private void listBoxSnap_SelectedIndexChanged(object sender, EventArgs e)
{
WindowSnap snap = this.listBoxSnap.SelectedItem as WindowSnap;
selectedIndex = this.listBoxSnap.SelectedIndex.ToString();
this.pictureBoxSnap.Image = snap.Image;
for (int i = 0; i < rectangles.Length; i++)
{
if (rectangles[i] != RectClone)
{
ClearGraphics = false;
}
else
{
ClearGraphics = true;
}
}
if (rectangles[listBoxSnap.SelectedIndex].Width == 0 && rectangles[listBoxSnap.SelectedIndex].Height == 0)
{
Reset.Enabled = false;
ConfirmRectangle.Enabled = false;
cm.MenuItems[0].Enabled = false;
cm.MenuItems[1].Enabled = false;
cm.MenuItems[2].Enabled = false;
}
if (rectangles[listBoxSnap.SelectedIndex].Width > 5 && rectangles[listBoxSnap.SelectedIndex].Height > 5)
{
Reset.Enabled = true;
if (IsRectangleConfirmed == true)
{
ConfirmRectangle.Enabled = false;
ClearGraphics = true;
cropRect = true;
}
else
{
ConfirmRectangle.Enabled = true;
}
cm.MenuItems[0].Enabled = true;
cm.MenuItems[1].Enabled = true;
cm.MenuItems[2].Enabled = true;
}
}
And the paint event of the pictureBox:
private void pictureBoxSnap_Paint(object sender, PaintEventArgs e)
{
if (pictureBoxSnap.Image != null)
{
{
if (ClearGraphics == false)
{
if (rectangles[listBoxSnap.SelectedIndex] != Rectangle.Empty)
{
e.Graphics.DrawRectangle(Pens.Firebrick, rectangles[listBoxSnap.SelectedIndex]);
}
}
if (cropRect == true)
{
if (recttest.Width > 5 && recttest.Height > 5)
{
pnt = PointToScreen(pictureBoxSnap.Location);
e.Graphics.Clear(Color.White);
e.Graphics.CopyFromScreen(pnt.X + rect.X, pnt.Y + rect.Y, rect.X, rect.Y, new Size(rect.Width, rect.Height));
}
}
}
}
}
The problem is with this part:
pnt = PointToScreen(pictureBoxSnap.Location);
e.Graphics.Clear(Color.White);
e.Graphics.CopyFromScreen(pnt.X + rect.X, pnt.Y + rect.Y, rect.X, rect.Y, new Size(rect.Width, rect.Height));
This part draw the cropped rectangle but then when i select another item in the listBox and then back to this item with the cropped rectangle again it's drawing it again and i want it just to remember it and show it again according to the selected item.
This part:
if (IsRectangleConfirmed == true)
{
ConfirmRectangle.Enabled = false;
ClearGraphics = true;
cropRect = true;
}
The IF: if (IsRectangleConfirmed == true) means that i clicked a button and a cropped rectangle created for this item im in now.
The problem is that when i get back each time to this item the cropped rectangle is drawing over again and i want it to just be shown like it will remember the cropped rectangle for this selected item(index).
What i want to do is a few things:
When i draw rectangle on the pictureBox and move between items in the listBox it will remember those items with already drawed rectangle. This part is working.
When i click on the button ConfirmRectangle_Click it will make a cropped rectangle from the rectangle i drawed i want that when i move between items in the listBox it will remember those items with cropped image.
This line get minimized windows screenshots:
this.listBoxSnap.Items.AddRange(WindowSnap.GetAllWindows(true, true).ToArray());
I add them to the listBox and when moving between items i see the screenshots of each one in the pictureBox.
I want to do now on items that have cropped image take screenshot of the part of the cropped image only.
If there is no cropped image take screenshot regular from the whole image.
This method GetAllWindows show in the listBox the text of the window but what i want to show in the listBox as item is only the name of it.
This is my project in zip file the name is CaptureZip
CaptureZip
And this is my project in winrar name Capture:
Capture
Set pictureBoxSnap SizeMode to normal.
private bool[] isCropped;
private Image img;
private Image imgClone;
public Form1()
{
InitializeComponent();
img = new Bitmap(pictureBoxSnap.Width, pictureBoxSnap.Height);
imgClone = new Bitmap(pictureBoxSnap.Width, pictureBoxSnap.Height);
Graphics g;
using (g = Graphics.FromImage(img))
{
g.Clear(Color.White);
}
pictureBoxSnap.Image = img;
...
...
rectangles = new Rectangle[listBoxSnap.Items.Count];
isCropped = new bool[listBoxSnap.Items.Count];
...
}
private void listBoxSnap_SelectedIndexChanged(object sender, EventArgs e)
{
drawpicbox(this.listBoxSnap.SelectedIndex);
}
private void drawpicbox(int index)
{
Graphics g, g1;
Size sz;
WindowSnap snap = this.listBoxSnap.SelectedItem as WindowSnap;
Bitmap testBmp;
using (g = Graphics.FromImage(img))
{
g.Clear(Color.White);
sz = calculateSizeAndPosition(snap.Image.Size);
if (isCropped[index] == true)
{
ConfirmRectangle.Enabled = false;
using (testBmp = new Bitmap (img.Width , img.Height )){
using (g1 = Graphics.FromImage(testBmp))
{
g1.Clear(Color.White);
g1.DrawImage(snap.Image, (int)((pictureBoxSnap.Width - sz.Width) / 2.0), (int)((pictureBoxSnap.Height - sz.Height) / 2.0), sz.Width, sz.Height);
}
g.DrawImage(testBmp, rectangles[index], rectangles[index], GraphicsUnit.Pixel);
g.DrawRectangle(Pens.Firebrick, rectangles[index]);
}
}
else if (rectangles[index].Width != 0)
{
ConfirmRectangle.Enabled = true;
g.DrawImage(snap.Image, (int)((pictureBoxSnap.Width - sz.Width) / 2.0), (int)((pictureBoxSnap.Height - sz.Height) / 2.0), sz.Width, sz.Height);
g.DrawRectangle(Pens.Firebrick, rectangles[index]);
}
else
{
ConfirmRectangle.Enabled = false;
g.DrawImage(snap.Image, (int)((pictureBoxSnap.Width - sz.Width) / 2.0), (int)((pictureBoxSnap.Height - sz.Height) / 2.0), sz.Width, sz.Height);
}
}
pictureBoxSnap.Invalidate();
}
private Size calculateSizeAndPosition(Size snapSize)
{
int wdth, hgt;
Single flt;
wdth = snapSize.Width;
hgt = snapSize.Height;
flt = (Single)wdth / (Single)hgt;
if (wdth <= pictureBoxSnap.Width && hgt <= pictureBoxSnap.Height)
{
//return new Size(wdth, hgt);
}
else{
if(wdth >= hgt){
while (true)
{
wdth--;
hgt = (int)(wdth / flt);
if (wdth <= pictureBoxSnap.Width && hgt <= pictureBoxSnap.Height)
{
break;
}
}
}
else{
while (true)
{
hgt--;
wdth = (int)((Single)hgt * flt);
if (wdth <= pictureBoxSnap.Width && hgt <= pictureBoxSnap.Height)
{
break;
}
}
}
}
return new Size(wdth, hgt);
}
private void pictureBoxSnap_MouseMove(object sender, MouseEventArgs e)
{
if (isCropped[listBoxSnap.SelectedIndex] == false && e.Button == MouseButtons.Left && e.Location != RectStartPoint)
{
DrawRectangle(e.Location);
}
}
private void DrawRectangle(Point pnt)
{
Graphics g = Graphics.FromImage(img);
//g.DrawRectangle(Pens.Firebrick, 50, 50, 300, 200);
g.DrawImage(imgClone, 0, 0);
if (pnt.X == RectStartPoint.X || pnt.Y == RectStartPoint.Y)
{
g.DrawLine(Pens.Firebrick, RectStartPoint.X, RectStartPoint.Y, pnt.X, pnt.Y);
}
else if (pnt.X > RectStartPoint.X && pnt.Y > RectStartPoint.Y) //Right-Down
{
rect.X = RectStartPoint.X; rect.Y = RectStartPoint.Y; rect.Width = pnt.X - RectStartPoint.X; rect.Height = pnt.Y - RectStartPoint.Y;
g.DrawRectangle(Pens.Firebrick, rect);
}
else if (pnt.X > RectStartPoint.X && pnt.Y < RectStartPoint.Y) //Right-Up
{
rect.X = RectStartPoint.X; rect.Y = pnt.Y; rect.Width = pnt.X - RectStartPoint.X; rect.Height = RectStartPoint.Y - pnt.Y;
g.DrawRectangle(Pens.Firebrick, rect);
}
else if (pnt.X < RectStartPoint.X && pnt.Y > RectStartPoint.Y) //Left-Down
{
rect.X = pnt.X; rect.Y = RectStartPoint.Y; rect.Width = RectStartPoint.X - pnt.X; rect.Height = pnt.Y - RectStartPoint.Y;
g.DrawRectangle(Pens.Firebrick, rect);
}
else //Left-Up
{
rect.X = pnt.X; rect.Y = pnt.Y; rect.Width = RectStartPoint.X - pnt.X; rect.Height = RectStartPoint.Y - pnt.Y;
g.DrawRectangle(Pens.Firebrick, rect);
}
g.Dispose();
pictureBoxSnap.Invalidate();
}
private void pictureBoxSnap_MouseDown(object sender, MouseEventArgs e)
{
Graphics g;
Size sz;
if (isCropped[listBoxSnap.SelectedIndex] == false && e.Button == MouseButtons.Left)
{
WindowSnap snap = this.listBoxSnap.SelectedItem as WindowSnap;
RectStartPoint = e.Location;
sz = calculateSizeAndPosition(snap.Image.Size);
using (g = Graphics.FromImage(imgClone))
{
g.Clear(Color.White);
g.DrawImage(snap.Image, (int)((pictureBoxSnap.Width - sz.Width) / 2.0), (int)((pictureBoxSnap.Height - sz.Height) / 2.0), sz.Width, sz.Height);
}
}
}
private void pictureBoxSnap_MouseUp(object sender, MouseEventArgs e)
{
if (isCropped[listBoxSnap.SelectedIndex] == false && e.Button == MouseButtons.Left && e.Location.X != RectStartPoint.X && e.Location.Y != RectStartPoint.Y)
{
ConfirmRectangle.Enabled = true;
rectangles[listBoxSnap.SelectedIndex] = rect;
//drawpicbox(this.listBoxSnap.SelectedIndex);
}
}
private void ConfirmRectangle_Click(object sender, EventArgs e)
{
isCropped[this.listBoxSnap.SelectedIndex] = true;
drawpicbox(this.listBoxSnap.SelectedIndex);
}
private void Reset_Click(object sender, EventArgs e)
{
isCropped[this.listBoxSnap.SelectedIndex] = false;
rectangles[this.listBoxSnap.SelectedIndex] = new Rectangle(0, 0, 0, 0);
drawpicbox(this.listBoxSnap.SelectedIndex);
}
private void pictureBoxSnap_Paint(object sender, PaintEventArgs e)
{
//Nothing
}
private void RefreshWindowsList()
{
Graphics g;
g = GraphicsfromImage(img);
g.Clear(Color.White);
ClearGraphics = true;
this.listBoxSnap.Items.Clear();
buttonSnap.Enabled = false;
this.listBoxSnap.Items.AddRange(WindowSnap.GetAllWindows(true, true).ToArray());
buttonSnap.Enabled = true;
for (int i = listBoxSnap.Items.Count - 1; i >= 0; i--)
{
string tt = listBoxSnap.Items[i].ToString();
if (tt.Contains(" ,"))
{
listBoxSnap.Items.RemoveAt(i);
}
}
rectangles = new Rectangle[listBoxSnap.Items.Count];
isCropped = new bool[listBoxSnap.Items.Count];
ConfirmRectangle.Enabled = false;
textBoxIndex.Text = listBoxSnap.Items.Count.ToString();
if (this.listBoxSnap.Items.Count > 0)
this.listBoxSnap.SetSelected(0, true);
listBoxSnap.Select();
pictureBoxSnap.Invalidate();
}
EDIT
Some minor corrections:
private void RefreshWindowsList()
{
//Graphics g; <- You dont need this
//g = GraphicsfromImage(img); <- You dont need this
//g.Clear(Color.White); <- You dont need this
//ClearGraphics = true; <- You dont need this
this.listBoxSnap.Items.Clear();
buttonSnap.Enabled = false;
this.listBoxSnap.Items.AddRange(WindowSnap.GetAllWindows(true, true).ToArray());
buttonSnap.Enabled = true;
for (int i = listBoxSnap.Items.Count - 1; i >= 0; i--)
{
string tt = listBoxSnap.Items[i].ToString();
if (tt.Contains(" ,"))
{
listBoxSnap.Items.RemoveAt(i);
}
}
rectangles = new Rectangle[listBoxSnap.Items.Count];
isCropped = new bool[listBoxSnap.Items.Count];
//ConfirmRectangle.Enabled = false; <- You dont need this
textBoxIndex.Text = listBoxSnap.Items.Count.ToString();
if (this.listBoxSnap.Items.Count > 0)
this.listBoxSnap.SetSelected(0, true);
listBoxSnap.Select();
//pictureBoxSnap.Invalidate(); <- You dont need this
}
Replace private void DrawRectangle(Point pnt) with:
private void DrawRectangle(Point pnt)
{
Graphics g = Graphics.FromImage(img);
g.DrawImage(imgClone, 0, 0);
if (pnt.X == RectStartPoint.X || pnt.Y == RectStartPoint.Y)
{
g.DrawLine(Pens.Firebrick, RectStartPoint.X, RectStartPoint.Y, pnt.X, pnt.Y);
}
else
{
g.DrawRectangle(Pens.Firebrick, Math.Min(RectStartPoint.X, pnt.X), Math.Min(RectStartPoint.Y, pnt.Y),
Math.Abs(RectStartPoint.X - pnt.X), Math.Abs(RectStartPoint.Y - pnt.Y));
}
g.Dispose();
pictureBoxSnap.Invalidate();
}
Replace private void pictureBoxSnap_MouseUp(object sender, MouseEventArgs e) with:
private void pictureBoxSnap_MouseUp(object sender, MouseEventArgs e)
{
if (isCropped[listBoxSnap.SelectedIndex] == false && e.Button == MouseButtons.Left)
{
if (Math.Abs(e.Location.X - RectStartPoint.X) < 10 || Math.Abs(e.Location.Y - RectStartPoint.Y) < 10)
{
rectangles[listBoxSnap.SelectedIndex] = new Rectangle(0, 0, 0, 0);
drawpicbox(listBoxSnap.SelectedIndex);
}
else
{
ConfirmRectangle.Enabled = true;
rectangles[listBoxSnap.SelectedIndex] = new Rectangle(Math.Min(RectStartPoint.X, e.X), Math.Min(RectStartPoint.Y, e.Y),
Math.Abs(RectStartPoint.X - e.X), Math.Abs(RectStartPoint.Y - e.Y));
}
}
}
Some explanation:
Function calculateSizeAndPosition() (should probably be calculateSize()), calculates the new size of snap image in order to fit to picturebox. It calculates it in a way similar to picturebox zoom mode.
img is what picturebox always draws after pictureBoxSnap.Invalidate();. So, if you want to make any changes to picturebox, draw on img and then invalidate.
Valter
As per your previous post you are trying to crop the image by Mouse drag. Now, you want to get that cropped image back when you select that item again after selecting another. In this case after cropping the image you are not setting that cropped image back to the SelectedItem so when you select that item again it will show cropped image not its original.
Image img = CropImage();
((WindowSnap)listBox.SelectedItem).Image = img;
or you can create another property in WindowSnap class.
ie. public image CroppedImage {get; set;}
So, when you select the item it should check that is item cropped or not. if it is then you can display cropped image instead of original.
WindowSnap snap = this.listBoxSnap.SelectedItem as WindowSnap;
selectedIndex = this.listBoxSnap.SelectedIndex.ToString();
///Here you can draw image at your desire position as you have done using e.DrawImage
///in pictureBoxSnap_Paint event instead of assigning pictureBoxSnap.Image property
this.pictureBoxSnap.Image = snap.CroppedImage
;

How to draw multiple rectangles using c#

I have drawn and saved the Rectangle on the image i loaded in the picture box. How i like to draw multiple rectangles for that i tried array in the rectangle but it gives error ("Object reference not set to an instance of an object." (Null reference Exception was unhandled).
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
if (mybitmap == null)
{
mybitmap = new Bitmap(sz.Width, sz.Height);
}
rect[count] = new Rectangle(e.X, e.Y, 0, 0);
this.Invalidate();
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if (stayToolStripMenuItem.Checked == true)
{
switch (e.Button)
{
case MouseButtons.Left:
{
rect[count] = new Rectangle(rect[count].Left, rect[count].Top, e.X - rect[count].Left, e.Y - rect[count].Top);
pictureBox1.Invalidate();
count++:
break;
}
}
}
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
if (stayToolStripMenuItem.Checked == true)
{
button1.Visible = true;
button2.Visible = true;
if (mybitmap == null)
{
return;
}
using (g = Graphics.FromImage(mybitmap))
{
using (Pen pen = new Pen(Color.Red, 2))
{
//g.Clear(Color.Transparent);
e.Graphics.DrawRectangle(pen, rect);
label1.Top = rect[count].Top; label1[count].Left = rect[count].Left; label1.Width = rect[count].Width;
label1.Height = rect[count].Height;
if (label1.TextAlign == ContentAlignment.TopLeft)
{
e.Graphics.DrawString(label1.Text, label1.Font, new SolidBrush(label1.ForeColor), rect);
g.DrawString(label1.Text, label1.Font, new SolidBrush(label1.ForeColor), rect);
g.DrawRectangle(pen, rect[count]);
}
}
}
}
}
How can i do this.....
You're incrementing the count variable after filling the rect array. By the time pictureBox1_Paint is executed, this increment has already taken place, so rect[count] is now a null reference, which you then try to draw :)
Also, there appears to be a compiler error in pictureBox1_MouseDown. The count++ inside the switch statement doesn't belong to any case block. Put it before the break; statement.
I imagine your intention is something like this:
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
if (mybitmap == null)
return;
using (g = Graphics.FromImage(mybitmap))
using (Pen pen = new Pen(Color.Red, 2))
{
g.Clear(Color.Transparent);
for (int i = 0; i < count; i++)
{
// Code to draw rect[i], instead of rect[count]
}
}
}
How large is your rect array, by the way? Arrays do not automatically grow to accommodate your needs. You may want to look at using List<Rectangle> instead.
Have change the code little bit. Instead of mouse move event used Mouse click event.
On using mouse move event it calls every time when mouse move on the picture box. so list rectangle count gets increased. for this i used mouse click event.
When list rectangle added in Mouse down event, it's only get the values for height and width of the rectangle (if use (0,0,e.X,e.Y))and also rectangle always starts from top left corner (not able to start the rectangle point where user likes) and it's gets only X and Y values (if use(e.X, e.Y,0,0))
to over come this I used the list rectangle in the mouse click event, so I get all values.
List<Rectangle> rectangles = new List<Rectangle>();
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
if (stayToolStripMenuItem.Checked == true)
{
if (mybitmap == null)
{
mybitmap = new Bitmap(sz.Width, sz.Height);
}
rect = new Rectangle(e.X, e.Y, 0, 0);
this.Invalidate();
}
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
if (stayToolStripMenuItem.Checked == true)
{
button1.Visible = true;
button2.Visible = true;
if (mybitmap == null)
{
return;
}
using (g = Graphics.FromImage(mybitmap))
{
using (Pen pen = new Pen(Color.Red, 2))
{
//g.Clear(Color.Transparent);
e.Graphics.DrawRectangle(pen, rect);
label1.Top = rect.Top; label1.Left = rect.Left; label1.Width = rect.Width;
label1.Height = rect.Height;
if (label1.TextAlign == ContentAlignment.TopLeft)
{
e.Graphics.DrawString(label1.Text, label1.Font, new SolidBrush(label1.ForeColor), rect);
g.DrawString(label1.Text, label1.Font, new SolidBrush(label1.ForeColor), rect);
g.DrawRectangle(pen, rect);
}
}
}
private void pictureBox1_MouseClick(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
rect = new Rectangle(rect.Left, rect.Top, e.X - rect.Left, e.Y - rect.Top);
rectangles.Add(rect);
pictureBox1.Invalidate();
f = 0;
}
}
What ever rectangle I draw get saved in the list rectangles and get saved when i saved the work (could see all the drawn rectangles when i opened the saved file).
Now the problem is, when I draw a new rectangle the previous one get disappeared (on run time. However this added in list rectangle).
How to display all the rectangles drawn on run time, so user can know how many rectangles drawn and where.

Categories

Resources