Prevent Alpha Color Pen from Overlapping? - c#

I have a simple highlighter using a Pen object. When the size is very large, it creates odd stripes which you can fix by defining its Start & End Cap withSystem.Drawing.Drawing2D.LineCap.Round but it instantly overlaps itself and loses its transparency. A flat cap also loses its transparency when you draw over itself multiple times.
How can I create an opaque pen that does not overlap itself or create stripes with a large pen width?
private static Color baseColor = Color.Yellow;
bool Draw;
Graphics g;
Point start;
Point end;
private void Form1_Load(object sender, EventArgs e)
{
g = this.CreateGraphics();
Pen1.Color = Color.FromArgb(128, baseColor);
Pen1.Width = 50;
Pen1.StartCap = System.Drawing.Drawing2D.LineCap.Flat; //I know it's default, just for clarification's sake
Pen1.EndCap = System.Drawing.Drawing2D.LineCap.Flat; //' '''' '' ' ''''''' '''' ''' ''''''''''''' ' ''''
}
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
Draw = true;
start = e.Location;
}
private void Form1_MouseUp(object sender, MouseEventArgs e)
{
Draw = false;
}
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
if (Draw == true)
{
end = e.Location;
g.DrawLine(Pen1, start, end);
start = end;
}
}
It behaves like this;
Note: Yes, I am aware .CreateGraphics is not a good drawing method, it has a unique purpose that is irrelevant to the question.

You have two issues with the drawing objects:
You draw each Line separately; this will create ugly artifacts where the common points overlap. Instead draw the lines all in one go with the DrawLines method! (Note the plural!)
You did not restrict the Pen.MiterLimit; this creates ugly spikes when the lines directions change sharply. Try to restrict it to around 1/2 of the Pen.Width or less . Setting LineJoin is also recommened as well a the two Caps..
Collect the points of your current line in a List<Point> currentPoints in the MouseMove and collect upon MouseUp the currentList into a List<List<Point>> allPointLists !
then you can draw both in the Paint event..
foreach (List<Point> points in allPointLists)
if (points.Count > 1) e.Graphics.DrawLines(Pens.Gold, points.ToArray());
if (currentPoints.Count > 1) e.Graphics.DrawLines(Pens.Gold, currentPoints.ToArray());
Note that it will pay immediately to do it right, i.e. draw only with a valid graphics object and always rely on the Paint event to make sure that the drawing is always updated as needed! Using control.CreateGraphics is almost always wrong and will hurt as soon as you go beyond a single non-persistent drawing operation..
Here is the full code:
List<Point> currentPoints = new List<Point>();
List<List<Point>> allPointLists = new List<List<Point>>();
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
currentPoints = new List<Point>();
}
private void Form1_MouseUp(object sender, MouseEventArgs e)
{
if (currentPoints.Count > 1)
{
allPointLists.Add(currentPoints.ToList());
currentPoints.Clear();
}
}
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
currentPoints.Add(e.Location);
Invalidate();
}
}
Here is the Paint event; note that I use two different Pens for the currently drawn lines and the older ones. Also note that you can use DrawCurve instead of DrawLines to get even smoother results..
Also note that I use a List<T> to be flexible wrt the number of elements and that I convert it to an array in the Draw commands..
private void Form1_Paint(object sender, PaintEventArgs e)
{
Color c1 = Color.FromArgb(66, 77, 88, 222);
using (Pen pen = new Pen(c1, 50f))
{
pen.MiterLimit = pen.MiterLimit / 12;
pen.LineJoin = LineJoin.Round;
pen.StartCap = LineCap.Round;
pen.EndCap = LineCap.Round;
foreach (List<Point> points in allPointLists)
if (points.Count > 1) e.Graphics.DrawLines(pen, points.ToArray());
}
Color c2 = Color.FromArgb(66, 33, 111, 222);
using (Pen pen = new Pen(c2, 50f))
{
pen.MiterLimit = pen.MiterLimit / 4;
pen.LineJoin = LineJoin.Round;
pen.StartCap = LineCap.Round;
pen.EndCap = LineCap.Round;
if (currentPoints.Count > 1) e.Graphics.DrawLines(pen, currentPoints.ToArray());
}
}
To prevent flicker don't forget to turn on DoubleBuffered for your Form; or use a DoubleBuffered Panel subclass or simply a PictureBox!
Final note: I left out the case of simple clicks; if they are supposed to paint you will have to catch them, probably best in the if (points.Count > 1) check and best do a FillEllipse at the right spot and with the right size..
Update
List<T> is so useful I hardly ever use arrays theses days. Here is how to make use of it to implement a Clear and an Undo button:
private void buttonClear_Click(object sender, EventArgs e)
{
allPointLists.Clear();
Invalidate();
}
private void buttonUndo_Click(object sender, EventArgs e)
{
allPointLists.Remove(allPointLists.Last());
Invalidate();
}
Note two small corrections in the MouseUp code this has required to handle the currentPoints list properly! The clearing is obvious; the ToList() call is making a copy of the data, so we don't clear the instance we have just added to te List of Lists!

Related

How to use the Paint event to draw shapes at mouse coordinates

I recently started programming in C# obviously and was trying to do a simple WinForms app that takes mouse coordinates and scales a Rectangle according to the coordinates.
The issue I am facing is that I don't know how to call a method that uses more arguments (in this case is x, y and PaintEventArgs). Or, I do know what to do with the PaintEvent.
Here is the whole code, since its pretty short and rather simple:
using System;
using System.Drawing;
using System.Windows.Forms;
public partial class Form1 : Form
{
public void Form1_MouseMove(object sender, MouseEventArgs e)
{
int x = e.X;
int y = e.Y;
String data = (x.ToString() + " " + y.ToString());
DrawRect(Something, x, y);
}
PaintEventArgs pEventArgs;
private void Form1_Paint(object sender, PaintEventArgs e)
{
}
public void DrawRect(PaintEventArgs e, int rey, int rex)
{
Graphics gr = e.Graphics;
Pen pen = new Pen(Color.Azure, 4);
Rectangle rect = new Rectangle(0, 0, rex, rey);
gr.DrawRectangle(pen, rect);
}
}
I'm trying to call the DrawRect() method to draw the Rectangle with width and height according to the mouse coordinates.
So how can I call the DrawRect() with coordinates and PaintEventArgs?
When drawing on a Control's surface, you always use the Paint event of that Control or override the OnPaint method of a Custom/User Control.
Do not try to store its Graphics object: it becomes invalid as soon as the Control is invalidated (repainted).
Use the Graphics object provided by the PaintEventArgs object.
When a more complex procedure is required to draw different shapes, you can pass the e.Graphics object to different methods which will use this object to perform specialized drawings.
In the example, the coordinates and other properties of each drawn shape are assigned to a specialized class, DrawingRectangle (a simplified structure here, it can hold more complex functionalities).
A List<DrawingRectangle>() stores the references of all the DrawingRectangle objects generated in a session (until the drawing is cleared).
Each time a Left MouseDown event is generated on the Control's surface, a new DrawingRectangle object is added to the List.
The e.Location is stored both as the DrawingRectangle.StartPoint (a value that doesn't change) and the DrawingRectangle.Location: this value will be updated when the mouse pointer is moved.
When the Mouse is moved, the current e.Location value is subtracted from the starting point coordinates previously stored. A simple calculation allows to draw the shapes from all sides.
This measure determines the current Size of the Rectangle.
To remove a Rectangle from the drawing, you just need to remove its reference from the List and Invalidate() the Control that provides the drawing surface.
To clear the drawing surface, clear the List<DrawingRectangle>() (drawingRects.Clear()) and call Invalidate().
Some other examples here:
Transparent Overlapping Circular Progress Bars
GraphicsPath and Matrix classes
Connecting different shapes
Drawing Transparent/Translucent Custom Controls
// Assign the Color used to draw the border of a shape to this Field
Color SelectedColor = Color.LightGreen;
List<DrawingRectangle> drawingRects = new List<DrawingRectangle>();
public class DrawingRectangle
{
public Rectangle Rect => new Rectangle(Location, Size);
public Size Size { get; set; }
public Point Location { get; set; }
public Control Owner { get; set; }
public Point StartPosition { get; set; }
public Color DrawingcColor { get; set; } = Color.LightGreen;
public float PenSize { get; set; } = 3f;
}
private void form1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button != MouseButtons.Left) return;
DrawingRects.Add(new DrawingRectangle() {
Location = e.Location,
Size = Size.Empty,
StartPosition = e.Location,
Owner = (Control)sender,
DrawingcColor = SelectedColor // <= Shape's Border Color
});
}
private void form1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button != MouseButtons.Left) return;
var dr = DrawingRects[DrawingRects.Count - 1];
if (e.Y < dr.StartPosition.Y) { dr.Location = new Point(dr.Rect.Location.X, e.Y); }
if (e.X < dr.StartPosition.X) { dr.Location = new Point(e.X, dr.Rect.Location.Y); }
dr.Size = new Size(Math.Abs(dr.StartPosition.X - e.X), Math.Abs(dr.StartPosition.Y - e.Y));
this.Invalidate();
}
private void form1_MouseUp(object sender, MouseEventArgs e)
{
// The last drawn shape
var dr = DrawingRects.Last();
// ListBox used to present the shape coordinates
lstPoints.Items.Add($"{dr.Location}, {dr.Size}");
}
private void form1_Paint(object sender, PaintEventArgs e)
{
DrawShapes(e.Graphics);
}
private void DrawShapes(Graphics g)
{
if (DrawingRects.Count == 0) return;
g.SmoothingMode = SmoothingMode.AntiAlias;
foreach (var dr in DrawingRects) {
using (Pen pen = new Pen(dr.DrawingcColor, dr.PenSize)) {
g.DrawRectangle(pen, dr.Rect);
};
}
}
// A Button used to save the current drawing to a Bitmap
private void btnSave_Click(object sender, EventArgs e)
{
using (var bitmap = new Bitmap(panCanvas.ClientRectangle.Width, panCanvas.ClientRectangle.Height))
using (var g = Graphics.FromImage(bitmap)) {
DrawShapes(g);
bitmap.Save(#"[Image Path]", ImageFormat.Png);
// Clone the Bitmap to show a thumbnail
}
}
// A Button used to clear the current drawing
private void btnClear_Click(object sender, EventArgs e)
{
drawingRects.Clear();
this.Invalidate();
}
app that takes mouse coordinates and scales rectangle according to the coordinates
I'd expect to see something like this (pseudocode):
Point _point;
void Form1_MouseMove(object sender, MouseEventArgs e)
{
... // calculate new coordinates/scale factor/whatever here
_point = ... ; // store results in fields
Invalidate(); // this will cause repaint every time you move mouse
}
void Form1_Paint(object sender, PaintEventArgs e)
{
... // take values from fields
e.Graphics.DrawRectangle(pen, rect); // draw
}
It's pretty simply. Painting is a combination of Invalidate() calls, which rise up paint event. The variables you pass using fields.
The PaintEventArgs allows you to access to the Graphics object, you need that one to draw something.
If you don't want to use the PaintEventArgs, i suggest that you call the CreateGraphics() method of your Form, and it will allow you to draw the rectangle.
To improve performance, i suggest that you use the using(...){ } keywork in order to dispose the Graphics object and the Pen object.
You need to include System.Drawing in order to use Graphics and Pen.
You're code will look like that :
using System.Drawing;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApp2
{
public partial class Form1 : Form
{
Point _coordinates;
public Form1()
{
this._coordinates = new Point();
this.InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
public void Form1_MouseMove(object sender, MouseEventArgs e)
{
this._coordinates = new Point(e.X, e.Y);
this.Invalidate();
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
// Don't draw on first Paint event
if(this._coordinates.X != 0 && this._coordinates.Y != 0)
{
this.DrawRect(e);
}
}
public void DrawRect(PaintEventArgs e)
{
using (Pen pen = new Pen(Color.Azure, 4))
{
Rectangle rect = new Rectangle(0, 0, this._coordinates.X, this._coordinates.Y);
e.Graphics.DrawRectangle(pen, rect);
}
}
}
}
Drawing in WinForms application works in a slightly different way then you probably expect. Everything on screen now is considered to be temporary, if you e.g. minimize and restore your window, the onscreen stuff will be erased and you'll be asked to repaint it again (your window's Paint event will be fired by the system).
That's why that DrawRect method expects PaintEventArgs argument: it is supposed to be called only withing your Paint event handler. If you call it from outside (like it is suggested in other answer) your rectangles might behave inconsistently.
I would suggest remember your rectangles in some internal variable and then repaint them when asked for that by the system:
private Point pointToDrawRect = new Point(0,0);
public void Form1_MouseMove(object sender, MouseEventArgs e)
{
int x = e.X;
int y = e.Y;
String data = (x.ToString() + " " + y.ToString());
pointToDrawRect= new Point(x, y);
Invalidate();
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
if(pointToDrawRect.X != 0 || pointToDrawRect.Y != 0)
{
DrawRect(e, pointToDrawRect.X, pointToDrawRect.Y);
}
}
public void DrawRect(PaintEventArgs e, int rey, int rex)
{
using (Pen pen = new Pen(Color.Azure, 4))
{
Rectangle rect = new Rectangle(0, 0, rex, rey);
e.Graphics.DrawRectangle(pen, rect);
}
}

How to make a draw rectangle 2px larger on each side than the recorded rectangle. C#

Hey so I'm currently using this post to create rectangles on a canvas and was wandering how i could make the drawn rectangle 2px larger than the actual rectangle recorded. Is this possible and if so how would i do this have been trying to work it out for a while now would be really useful to finally have a solution.
Point startPos; // mouse-down position
Point currentPos; // current mouse position
bool drawing; // busy drawing
List<Rectangle> rectangles = new List<Rectangle>(); // previous rectangles
private Rectangle getRectangle() {
return new Rectangle(
Math.Min(startPos.X, currentPos.X),
Math.Min(startPos.Y, currentPos.Y),
Math.Abs(startPos.X - currentPos.X),
Math.Abs(startPos.Y - currentPos.Y));
}
private void canevas_MouseDown(object sender, MouseEventArgs e) {
currentPos = startPos = e.Location;
drawing = true;
}
private void canevas_MouseMove(object sender, MouseEventArgs e) {
currentPos = e.Location;
if (drawing) canevas.Invalidate();
}
private void canevas_MouseUp(object sender, MouseEventArgs e) {
if (drawing) {
drawing = false;
var rc = getRectangle();
if (rc.Width > 0 && rc.Height > 0) rectangles.Add(rc);
canevas.Invalidate();
}
}
private void canevas_Paint(object sender, PaintEventArgs e) {
if (rectangles.Count > 0) e.Graphics.DrawRectangles(Pens.Black, rectangles.ToArray());
if (drawing) e.Graphics.DrawRectangle(Pens.Red, getRectangle());
}
just for reference this code came from this post
https://stackoverflow.com/questions/4060446/how-to-draw-rectangle-on-mousedown-move-c-sharp
In the getRectangle method you just need to change the values that you use in the constructor for the Rectangle. Since the third one refers to the width property, you add the number of pixels to Math.Abs(startPos.X - currentPos.X).After this the check if (rc.Width > 0) is useless for obvious reasons.

Transparent picture box on top of another picture box is not working. How to fix this?

I want to create two picture boxes, overlapping.
The first Picturebox is used as the background, the picture of the screen.
using this method:
public void BckShow()
{
Rectangle rect = Screen.GetBounds(this);
gBackImg = Graphics.FromImage(bBackImg);
gBackImg.CopyFromScreen(0,0,0,0,
Screen.PrimaryScreen.Bounds.Size,
CopyPixelOperation.SourceCopy);
}
The second picturebox is above the first one, a transparent picture box that can be drawn using this mouse event:
public void Draw(bool draw, Point sp, Point ep)
{
if (draw)
{
gCanvas.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
pen = new Pen(new SolidBrush(ColorName), BrushSize);
if (toolPen.Checked)
{
gCanvas.DrawLine(pen, sp, ep);
}
else if (toolEreser.Checked)
{
Rectangle rect = new Rectangle(ep.X, ep.Y, BrushSize*5, BrushSize*5);
gCanvas.DrawEllipse(pen, rect);
gCanvas.FillEllipse(new SolidBrush(ColorName), rect);
}
bCanvas.MakeTransparent(Color.White);
pbxCanvas.Refresh();
dirty = true;
toolSave.Enabled = true;
}
}
private void pbxCanvas_MouseDown(object sender, MouseEventArgs e)
{
sp = e.Location;
if (e.Button == MouseButtons.Left)
{
ActivePaint = true;
}
}
private void pbxCanvas_MouseUp(object sender, MouseEventArgs e)
{
ActivePaint = false;
}
private void pbxCanvas_MouseMove(object sender, MouseEventArgs e)
{
ep = e.Location;
Draw(ActivePaint, sp, ep);
sp = ep;
}
but when i run the program, the second PictureBox does not draw anything when the mouse event was fired. how i can fix this?
I do this because I just want to save the image in the second picture box. Unlike PrintScreen but seemed to make notes on the screen and save the image apart from the screen image.
Is there another way to do this? like using controls other than picture box, or may directly use the screen as a background but still can save the image in the transparent PictureBox separately.
This is the example I want to achieve:
when drawing:
results stored images:
I hope you all will help me to fix this. sorry for poor explanation.
this the document outline window for more detail:
It's likely that your surface being overdrawn by refresh. You should be tracking what you want to draw, and then drawing it in the picture box's Paint event. That way, you get handed a Graphics object and every refresh, you're drawing.
That's assuming, of course, that you have a valid, and correct, Graphics object in the first place.
BTW: passing a form-scope variable to Draw is confusing, just use it.
Check your gCanvas initializer, if it is used from within Paint event (e.Graphics), then your changes are lost when you call the Refresh() method. Refresh() causes a new Paint event to be fired, creating a new Graphics object and therefore invalidating yours.
Create a new graphics object from your PictureBox's Image to persist your changes permanently.
private List<Point> points = new List<Point>();
private void pbxCanvas_MouseDown(object sender, MouseEventArgs e) {
if (e.Button == MouseButtons.Left) {
ActivePaint = true;
}
}
private void pbxCanvas_MouseUp(object sender, MouseEventArgs e) {
ActivePaint = false;
points.Clear();
}
private void pbxCanvas_MouseMove(object sender, MouseEventArgs e) {
if (ActivePaint) {
points.Add(e.Location);
Refresh();
}
}
private void pbxCanvas_Paint(object sender, PaintEventArgs e) {
using (var graphics = Graphics.FromImage(pbxCanvas.Image)) {
for (int i = 0; i < points.Count - 1; i++) {
graphics.DrawLine(Pens.Black, points[i], points[i + 1]);
}
}
}

In a PictureBox, drawing a temporary circle on mouse down, to follow the mouse, until the mouseUp event is detected

I'm really new to drawing in C#, and I'm using Windows Forms instead of WPF, so maybe I'm doing it wrong from the get-go... you tell me... but I'd like to have a temporary marker put down on the PictureBox (on MouseDown) that will follow the mouse (erasing the previous drawings of itself, i.e. not leaving a trail), and then being drawn in the final position on the MouseUp event.
Here's some skeleton code that you guys can fill in:
bool mDown;
Graphics g; // initialized to pictureBox1.CreateGraphics() on Form_Load, though
// I am unsure how that differs from Graphics.FromImage(pictureBox1)
SolidBrush sbGray, sbGreen;
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
mDown = true;
// store/push initial drawing
g.FillEllipse(sbGray, e.X - 5, e.Y - 5, 10, 10);
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if (mDown)
{
// restore/pop initial drawing, erasing old trail
g.FillEllipse(sbGray, e.X - 5, e.Y - 5, 10, 10);
}
}
private void pictureBox1_MouseClick(object sender, MouseEventArgs e)
{
// restore/pop initial drawing, erasing old trail
g.FillEllipse(sbGreen, e.X - 5, e.Y - 5, 10, 10);
mDown = false;
}
I suppose there are several ways to skin a cat, such as changing the mouse icon, so perhaps this is not even the best way to do it? Even so, I will probably need to know the answers to both questions -- whether there is a better way to do it, and also how to extract the graphics from a PictureBox (as this knowledge will most likely prove useful later anyways.)
(Note: Although the gray circles should erase themselves, the green circles should be persistent and multiple green circles should be capable of existing in the PictureBox at the same time.)
You need to look at the PictureBox's Paint Event also, it is better to do all of your graphics in the Paint event since you do not have to worry about disposing the Graphic Object.. See if this is what you were wanting.
Edit: added code to retain points and also to clear them.
public partial class Form1 : Form
{
bool mDown;
SolidBrush sbGray = new SolidBrush(Color.Gray);
SolidBrush sbGreen = new SolidBrush(Color.LimeGreen);
SolidBrush sbTemp;
Point mPosition = new Point();
public List<Point> points = new List<Point>();
public Form1()
{
InitializeComponent();
pictureBox1.Image = Image.FromFile(#"C:\Temp\Test.jpg");
}
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
mDown = true;
mPosition = new Point(e.X, e.Y);
sbTemp = sbGray;
pictureBox1.Invalidate();
}
else
{
points.Clear();
sbTemp = null;
pictureBox1.Invalidate();
}
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if (mDown)
{
mPosition = new Point(e.X, e.Y);
sbTemp = sbGray;
pictureBox1.Invalidate();
}
}
private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
mPosition = new Point(e.X, e.Y);
points.Add(mPosition);
sbTemp = sbGreen;
pictureBox1.Invalidate();
mDown = false;
}
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
if (sbTemp != null)
{
e.Graphics.FillEllipse(sbTemp, mPosition.X -5, mPosition.Y -5, 10, 10);
}
if (points != null)
{
foreach (var loc in points)
{
e.Graphics.FillEllipse(sbGreen, loc.X - 5, loc.Y - 5, 10, 10);
}
}
}
}

C# Image processing is very slow

In the last few months I've been working on an application, and one of it's functions is that it can crop images. So, I've coded a function that draws a transparent orange rectangle, to show the user the crop area, but it works very slowly - can anyone help me/show me a way to make it faster?
Here is the code:
Image source;
private void pictureBox1_MouseDown(object sender, MouseEventArgs e) {
mousePos = e.Location;
}
Point mousePos;
private void pictureBox1_MouseMove(object sender, MouseEventArgs e) {
if (e.Button == MouseButtons.Left) {
Image editSource = new Bitmap(source);
Graphics g = Graphics.FromImage(editSource);
SolidBrush brush = new SolidBrush(
Color.FromArgb(128, Color.Orange.R, Color.Orange.G, Color.Orange.B));
int width = e.X - mousePos.X;
if (width < 0) {
width *= -1;
}
int height = e.Y - mousePos.Y;
if (height < 0) {
height *= -1;
}
Size cropRectSize = new Size(width, height);
Rectangle cropRect = new Rectangle(mousePos, cropRectSize);
g.FillRectangle(brush, cropRect);
pictureBox1.Image = editSource;
}
}
The way to make it faster is don't create bitmaps on mouse move. If you need to draw on a graphics surface, do so without creating new bitmaps.
Don't use a picture box. Add your own user drawn control.
On MouseMove just invalidate the changed region
In Draw, write directly to graphics object, don't play with in memory bitmaps
So, all recommendations for not using picture box aside... I'll give you a method to doing it ;)
The idea behind this is to only use mouse move, mouse down, etc to store what should be drawn. Then when it's time to draw it use the stored state. This draws an orange rectangle whenever you have the mouse depressed on the picture box (even though recommendation is to not use picture box this same approach can be used for other surfaces.).
Point startPoint;
Point currentPoint;
bool draw = false;
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
startPoint = e.Location;
draw = true;
}
private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
draw = false;
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
currentPoint = e.Location;
pictureBox1.Invalidate();
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
if (draw)
{
int startX = Math.Min(startPoint.X, currentPoint.X);
int startY = Math.Min(startPoint.Y, currentPoint.Y);
int endX = Math.Max(startPoint.X, currentPoint.X);
int endY = Math.Max(startPoint.Y, currentPoint.Y);
e.Graphics.DrawRectangle(Pens.Orange, new Rectangle(startX, startY, endX-startX, endY-startY));
}
}

Categories