I want to know how to draw rectangle in C# and make it dragged and dropped in the page here my code to draw it but I cannot drag or drop it.
public partial class Form1 : Form
{
public bool drag = false;
int cur_x, cur_y;
Rectangle rec = new Rectangle(10, 10, 100, 100);
public Form1()
{
InitializeComponent();
}
protected override void OnPaint(PaintEventArgs r)
{
base.OnPaint(r);
Graphics g = r.Graphics;
//g.DrawRectangle(Pens.Black, rec);
g.FillRectangle(Brushes.Aquamarine, rec);
}
private void recmousedown(object sender, MouseEventArgs m)
{
if (m.Button != MouseButtons.Left)
return;
rec = new Rectangle(m.X, m.Y,100,100);
drag = true;
cur_x = m.X;
cur_y = m.Y;
}
private void recmousemove(object sender, MouseEventArgs m)
{
if (m.Button != MouseButtons.Left)
return;
rec.X = m.X;
rec.Y = m.Y;
Invalidate();
}
}
You're pretty close, you just need to initialize the rectangle better and adjust the rectangle size in the Move event:
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
this.DoubleBuffered = true;
}
Rectangle rec = new Rectangle(0, 0, 0, 0);
protected override void OnPaint(PaintEventArgs e) {
e.Graphics.FillRectangle(Brushes.Aquamarine, rec);
}
protected override void OnMouseDown(MouseEventArgs e) {
if (e.Button == MouseButtons.Left) {
rec = new Rectangle(e.X, e.Y, 0, 0);
Invalidate();
}
}
protected override void OnMouseMove(MouseEventArgs e) {
if (e.Button == MouseButtons.Left) {
rec.Width = e.X - rec.X;
rec.Height = e.Y - rec.Y;
Invalidate();
}
}
}
You could try the approach in this article: http://beta.codeproject.com/KB/GDI-plus/flickerFreeDrawing.aspx
Related
my drawings are deleted in the code I wrote. If "refresh" is not used, the drawing does not appear. Is there a mistake in my drawing? I don't understand
How can I draw a new line without erasing my lines ?
Here's the code
Pen pen;
Point startXY;
Point endXY;
bool ismoving = false;
string choice = "Line";
public Form1(){
InitializeComponent();}
private void drawArea_MouseDown(object sender, MouseEventArgs e){
startXY = e.Location;
ismoving = true;}
private void drawArea_MouseMove(object sender, MouseEventArgs e){
if (ismoving == true){
endXY = e.Location;
drawArea.Refresh();}}
private void drawArea_MouseUp(object sender, MouseEventArgs e){
endXY = e.Location;
ismoving = false;}
private void Form1_Load(object sender, EventArgs e){
//Graphics graph = drawArea.CreateGraphics();
//graph.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
pen = new Pen(Color.White,1);
pen.StartCap = pen.EndCap = System.Drawing.Drawing2D.LineCap.Round;}
private void drawArea_Paint(object sender, PaintEventArgs e){
switch (choice){
case "Line":{
e.Graphics.DrawLine(pen, startXY, endXY);
break;}}}
Your code needs to know how to recreate the entire graphics window at any time, because windows may ask it to redraw at any time.
So you need to keep track of the things to be drawn in a list and use this list in the Paint event to render to the screen.
Below is an example code that does this. The result looks like this
public enum Tool
{
Line,
PolyLine,
Circle,
}
public partial class Form1 : Form
{
Point startXY;
Point endXY;
bool isMoving;
Tool next;
public Form1()
{
InitializeComponent();
this.Drawing = new List<IDrawObject>();
this.isMoving = false;
this.next = Tool.Line;
this.drawArea.BackColor = Color.Black;
this.drawArea.BorderStyle = BorderStyle.FixedSingle;
}
public List<IDrawObject> Drawing { get; }
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
drawArea.Resize += (s, ev) => drawArea.Refresh();
drawArea.Paint += pictureBox1_Paint;
drawArea.MouseDown += PictureBox1_MouseDown;
drawArea.MouseMove += PictureBox1_MouseMove;
drawArea.MouseUp += PictureBox1_MouseUp;
this.KeyDown += (s, ev) =>
{
switch (ev.KeyCode)
{
case Keys.Space:
next = NextTool(next);
UpdateFormTitle();
break;
}
};
UpdateFormTitle();
}
public void UpdateFormTitle()
{
this.Text = $"Draw Area. Tool={next}. Press [SPACE] to switch.";
}
private void PictureBox1_MouseUp(object sender, MouseEventArgs e)
{
isMoving = false;
endXY = e.Location;
Drawing.Add(NextDrawObject());
drawArea.Invalidate();
}
private void PictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if (isMoving)
{
endXY = e.Location;
drawArea.Invalidate();
}
}
private void PictureBox1_MouseDown(object sender, MouseEventArgs e)
{
isMoving = true;
startXY = e.Location;
}
protected void pictureBox1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
using (var pen = new Pen(Color.White, 1))
{
pen.EndCap = LineCap.Round;
pen.StartCap = LineCap.Round;
foreach (var item in Drawing)
{
item.Draw(e.Graphics, pen);
}
if (isMoving)
{
pen.Color = Color.SteelBlue;
pen.DashStyle = DashStyle.Dash;
NextDrawObject().Draw(e.Graphics, pen);
}
}
}
public static float Distance(Point from, Point to)
{
var dx = (float)(to.X-from.X);
var dy = (float)(to.Y-from.Y);
return (float)Math.Sqrt(dx*dx+dy*dy);
}
public Tool NextTool(Tool current)
{
switch (current)
{
case Tool.Line:
return Tool.Circle;
case Tool.Circle:
return Tool.Line;
case Tool.PolyLine:
throw new NotImplementedException();
default:
throw new NotSupportedException();
}
}
public IDrawObject NextDrawObject()
{
switch (next)
{
case Tool.Line:
return new Line(startXY, endXY);
case Tool.PolyLine:
throw new NotImplementedException();
case Tool.Circle:
var radius = Distance(startXY, endXY);
return new Circle(startXY, radius);
default:
throw new NotSupportedException();
}
}
}
public interface IDrawObject
{
void Draw(Graphics g, Pen pen);
}
public struct Line : IDrawObject
{
public Line(PointF from, PointF to)
{
this.From=from;
this.To=to;
}
public PointF From { get; }
public PointF To { get; }
public void Draw(Graphics g, Pen pen)
{
g.DrawLine(pen, From, To);
}
}
public struct PolyLine : IDrawObject
{
public PolyLine(params PointF[] nodes)
{
this.Nodes=nodes;
}
public PointF[] Nodes { get; }
public void Draw(Graphics g, Pen pen)
{
g.DrawLines(pen, Nodes);
}
}
public struct Circle : IDrawObject
{
public Circle(PointF center, float radius)
{
this.Center=center;
this.Radius=radius;
}
public PointF Center { get; }
public float Radius { get; }
public void Draw(Graphics g, Pen pen)
{
g.DrawEllipse(pen, Center.X-Radius, Center.Y-Radius, 2*Radius, 2*Radius);
}
}
Please take a look at this implementation from Telerik:
When hover:
When click:
Can I implement it without using any 3rd party program ?
I have created an example to demonstrate how to create your custom control.
Create a UserControl and give the name Sample and place the following code in .cs file.
[DefaultEvent("Click")]
public partial class Sample : UserControl
{
private string _text;
[Browsable(true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public override string Text
{
get
{
return _text;
}
set
{
_text = value;
}
}
private bool _mouseDown = false;
private bool _mouseHover = false;
private bool _invalidateRequired = true;
public Sample()
{
InitializeComponent();
}
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
_mouseDown = true;
_invalidateRequired = true;
this.Invalidate();
}
protected override void OnMouseUp(MouseEventArgs e)
{
base.OnMouseUp(e);
_mouseDown = false;
_invalidateRequired = true;
this.Invalidate();
}
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
_mouseHover = true;
if (_invalidateRequired)
{
this.Invalidate();
_invalidateRequired = false;
}
}
protected override void OnMouseLeave(EventArgs e)
{
base.OnMouseLeave(e);
_mouseHover = false;
this.Invalidate();
_invalidateRequired = true;
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
Rectangle r = new Rectangle(0, 0, this.ClientRectangle.Width - 1, this.ClientRectangle.Height - 1);
Color bg = Color.White;
Color fr = Color.Gray;
Color br = Color.FromArgb(173, 178, 173);
if (_mouseDown)
{
bg = Color.FromArgb(24, 162, 231);
fr = Color.White;
}
if (_mouseHover)
br = Color.FromArgb(24, 162, 231);
e.Graphics.FillRectangle(new SolidBrush(bg), r);
e.Graphics.DrawRectangle(new Pen(br, 3), r);
StringFormat sf = new StringFormat();
sf.LineAlignment = StringAlignment.Center;
sf.Alignment = StringAlignment.Center;
e.Graphics.DrawString(Text, this.Font, new SolidBrush(fr), r, sf);
}
}
Code with Designer.cs
When this form opens, it has a background image of the fullscreen and the user can mouse down and draw a rectangle which will be used later to crop the background image. The problem I am getting is that when the form paints, it's not drawing a rectangle so the user doesnt know the the area they are selecting
This is my code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace Quick_Screenshot
{
public partial class Crop : Form
{
private Rectangle croprect = Rectangle.Empty;
private bool mouseDown = false;
private bool selectedArea = false;
Point sp, ep;
Bitmap background;
public Rectangle CropArea
{
get { return croprect; }
}
public bool SelectedArea
{
get { return selectedArea; }
}
public Crop(Bitmap image)
{
InitializeComponent();
background = image;
picBox.MouseDown += new MouseEventHandler(Crop_MouseDown);
picBox.MouseUp += new MouseEventHandler(Crop_MouseUp);
picBox.MouseMove += new MouseEventHandler(Crop_MouseMove);
picBox.Paint += new PaintEventHandler(Crop_Paint);
}
private void Crop_Load(object sender, EventArgs e)
{
picBox.Image = (Image)background;
}
private void Crop_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Right)
this.Close();
else
{
mouseDown = true;
sp = ep = e.Location;
}
}
private void Crop_MouseUp(object sender, MouseEventArgs e)
{
ep = e.Location;
mouseDown = false;
croprect = GetRectangle(sp, ep);
if (croprect.Width > 10 && croprect.Height > 10)
{
selectedArea = true;
}
else
{
croprect = Rectangle.Empty;
Taskbar.Balloon("Selected area too small", "Quick Screenshot", ToolTipIcon.Error);
}
this.Close();
}
private void Crop_MouseMove(object sender, MouseEventArgs e)
{
if (mouseDown)
{
ep = e.Location;
Update();
}
}
private void Crop_Paint(object sender, PaintEventArgs e)
{
e.Graphics.DrawRectangle(Pens.Red, GetRectangle(sp, ep));
e.Graphics.Save();
}
private Rectangle GetRectangle(Point p1, Point p2)
{
return new Rectangle(
Math.Min(p1.X, p2.X),
Math.Min(p1.Y, p2.Y),
Math.Abs(p1.X - p2.X),
Math.Abs(p1.Y - p2.Y)
);
}
}
}
You should call the Invalidate() method on the picBox variable to refresh the control.
Instead of this:
private void Crop_MouseMove(object sender, MouseEventArgs e)
{
if (mouseDown)
{
ep = e.Location;
Update();
}
}
Use this:
private void Crop_MouseMove(object sender, MouseEventArgs e)
{
if (mouseDown)
{
ep = e.Location;
picBox.Invalidate();
}
}
You should call Invalidate() instead of Update()
I'm trying to move the control named pictureBox1 by dragging it around. The problem is, when it moves, it keeps moving from a location to another location around the mouse, but it does follow it...
This is my code. and I would really appreciate it if you could help me
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
bool selected = false;
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
selected = true;
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if (selected == true)
{
pictureBox1.Location = e.Location;
}
}
private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
selected = false;
}
}
All you need:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private Point MouseDownLocation;
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
MouseDownLocation = e.Location;
}
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
pictureBox1.Left = e.X + pictureBox1.Left - MouseDownLocation.X;
pictureBox1.Top = e.Y + pictureBox1.Top - MouseDownLocation.Y;
}
}
}
You can also use the extension:
public static class CmponentsExtensions
{
//Management of mouse drag and drop
#region Menu and Mouse
private static bool mouseDown;
private static Point lastLocation;
/// <summary>
/// To enable control to be moved around with mouse
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="control"></param>
public static void moveItselfWithMouse<T>(this T control) where T: Control
{
control.MouseDown += (o, e)=> { mouseDown = true; lastLocation = e.Location; };
control.MouseMove += (o, e) =>
{
if (mouseDown)
{
control.Location = new Point((control.Location.X - lastLocation.X) + e.X, (control.Location.Y - lastLocation.Y) + e.Y);
control.Update();
}
};
control.MouseUp += (o, e) => { mouseDown = false; } ;
}
public static void moveOtherWithMouse<T>(this T control, Control movedObject) where T : Control
{
control.MouseDown += (o, e) => { mouseDown = true; lastLocation = e.Location; };
control.MouseMove += (o, e) =>
{
if (mouseDown)
{
movedObject.Location = new Point((movedObject.Location.X - lastLocation.X) + e.X, (movedObject.Location.Y - lastLocation.Y) + e.Y);
movedObject.Update();
}
};
control.MouseUp += (o, e) => { mouseDown = false; };
}
#endregion
}
Then you need to use it with some control:
In this case pictureBox1 moved the whole Form
pictureBox1.moveOtherWithMouse(this);
In this case you move only pictureBox:
pictureBox1.moveItselfWithMouse();
try this to move pictureBox control at runtime using mouse
private void pictureBox7_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
xPos = e.X;
yPos = e.Y;
}
}
private void pictureBox7_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
{
PictureBox p = sender as PictureBox;
if (p != null)
{
if (e.Button == MouseButtons.Left)
{
p.Top += (e.Y - yPos);
p.Left += (e.X - xPos);
}
}
}
Following is my code. i am trying to draw line, filled rectangle, etc.....
Problem is that, lets suppose i draw a line but when i try to draw an other line first drawn line disappears. so i want help that i'll be able to draw multiple shapes on a form and first draw lines don't disappears.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace finalPaint
{
public partial class Form1 : Form
{
List<Point> points = new List<Point>();
Rectangle rect;
Point first;
Point last;
string op;
public Form1()
{
InitializeComponent();
}
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
points.Add(e.Location);
rect = new Rectangle(rect.Left, rect.Top, e.X - rect.Left, e.Y - rect.Top);
last = e.Location;
this.Invalidate();
this.Update();
}
}
private void Form1_MouseUp(object sender, MouseEventArgs e)
{
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
switch (op)
{
case "toolStripButton1":
{
if (points.Count > 2)
{
e.Graphics.DrawLines(Pens.Black, points.ToArray());
}
}
break;
case "toolStripButton2":
{
using (Pen pen = new Pen(Color.Red, 2))
{
e.Graphics.DrawRectangle(pen, rect);
}
}
break;
case "toolStripButton3":
{
Pen pen = new Pen(Color.Red, 2);
e.Graphics.DrawLine(pen, first, last);
this.Update();
}
break;
case "toolStripButton4":
{
using (SolidBrush pen = new SolidBrush(Color.Red))
{
e.Graphics.FillRectangle(pen, rect);
}
}
break;
case "toolStripButton5":
{
using (SolidBrush pen = new SolidBrush(Color.Red))
{
e.Graphics.FillEllipse(pen, rect);
}
}
break;
case "toolStripButton6":
{
using (Pen pen = new Pen(Color.Red,2))
{
e.Graphics.DrawEllipse(pen, rect);
}
}
break;
default:
break;
}
}
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
rect = new Rectangle(e.X, e.Y, 0, 0);
first = e.Location;
this.Invalidate();
}
private void toolStrip1_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
{
}
private void selectedButton(object sender, EventArgs e)
{
foreach (ToolStripButton btn in toolStrip1.Items)
{
btn.Checked = false;
}
ToolStripButton btnClicked = sender as ToolStripButton;
btnClicked.Checked = true;
op = btnClicked.Name;
}
}
}
On each Paint event, you need to paint all of the objects you want on the screen. You are not just painting on top of what is already there. You are repainting the entire scene.
The reason for this is that your control may be obscured from view at some point, and Windows will repaint it when it is revealed again.
If you want to keep a memory of all the the objects, you need to store them in your code. Since each object is different (lines, rectangles, ellipses) you will want to store them in a manner that lets you differentiate. You could create classes like this:
public class DrawingShape
{
public string Name { get; set; }
public DrawingShapeType Type { get; set; }
// other shared properties
public virtual void Draw(Graphics g)
{
}
}
public class DrawingRectangle : DrawingShape
{
public DrawingRectangle()
{
Name = "Rectangle";
Type = DrawingShapeType.Rectangle;
}
public override void Draw(Graphics g)
{
// draw this shape
}
}
public enum DrawingShapeType
{
Rectangle,
Ellipse,
Line,
}
Then you can just store all your objects in a List. The order of the items in the list is your z-order, so you add items to the list and you enumerate through the list in your Paint event and draw each one differently depending on the type.
From here you can store pen and brush information in the class and other info. Your Paint event can tell each class to paint itself and it doesn't need to know which type they are.
You need a possibility to store all your shapes, in order to draw them all in the Paint event, since the background of the form is repainted before each call to Paint. Let us define a base class from which we will derive all the shapes
abstract class Shape
{
public abstract void Paint(PaintEventArgs e);
public abstract void UpdateShape(Point newLocation);
}
Here we declare the abstract methods Paint and UpdateShape that we will have to override in the derived classes. UpdateShape will be called in MouseMove.
Let us start with the freeform line
class FreeformLine : Shape
{
private List<Point> _points = new List<Point>();
public FreeformLine(Point startLocation)
{
_points.Add(startLocation);
}
public override void Paint(PaintEventArgs e)
{
if (_points.Count >= 2) {
e.Graphics.DrawLines(Pens.Black, _points.ToArray());
}
}
public override void UpdateShape(Point newLocation)
{
const int minDist = 3;
// Add new point only if it has a minimal distance from the last one.
// This creates a smoother line.
Point last = _points[_points.Count - 1];
if (Math.Abs(newLocation.X - last.X) >= minDist ||
Math.Abs(newLocation.Y - last.Y) >= minDist)
{
_points.Add(newLocation);
}
}
}
Here we need a list of points. In the constructor, we pass the first point. The Paint method just executes the paint logic that you had already defined and the UpdateShape method adds new points to our points list.
The straight line works in a very similar way, but defines only the first and the last point.
class StraightLine : Shape
{
private Point _first;
private Point _last;
public StraightLine(Point startLocation)
{
_first = startLocation;
}
public override void Paint(PaintEventArgs e)
{
if (!_last.IsEmpty) {
Pen pen2 = new Pen(Color.Red, 2);
e.Graphics.DrawLine(pen2, _first, _last);
}
}
public override void UpdateShape(Point newLocation)
{
_last = newLocation;
}
}
We define only one rectangle class and add a variable in order to remember if the shape is filled or not.
class RectangleShape : Shape
{
protected bool _filled;
protected Rectangle _rect;
protected Point _start;
public RectangleShape(Point startLocation, bool filled)
{
_start = startLocation;
_rect = new Rectangle(startLocation.X, startLocation.Y, 0, 0);
_filled = filled;
}
public override void Paint(PaintEventArgs e)
{
if (_filled) {
using (SolidBrush brush = new SolidBrush(Color.Red)) {
e.Graphics.FillRectangle(brush, _rect);
}
} else {
using (Pen pen = new Pen(Color.Red, 2)) {
e.Graphics.DrawRectangle(pen, _rect);
}
}
}
public override void UpdateShape(Point newLocation)
{
int x = Math.Min(_start.X, newLocation.X);
int y = Math.Min(_start.Y, newLocation.Y);
int width = Math.Abs(newLocation.X - _start.X);
int height = Math.Abs(newLocation.Y - _start.Y);
_rect = new Rectangle(x, y, width, height);
}
}
Finally, we declare the ellipse class. Since this one uses a rectangle as well, we just derive it from our rectangle class.
class Ellipse : RectangleShape
{
public Ellipse(Point startLocation, bool filled)
: base(startLocation, filled)
{
}
public override void Paint(PaintEventArgs e)
{
if (_filled) {
using (SolidBrush brush = new SolidBrush(Color.Red)) {
e.Graphics.FillEllipse(brush, _rect);
}
} else {
using (Pen pen = new Pen(Color.Red, 2)) {
e.Graphics.DrawEllipse(pen, _rect);
}
}
}
}
Here we only override the Paint method. All the rectangle update logic remains the same.
Now to the form. Here we declare the global variables
List<Shape> _shapes = new List<Shape>();
Shape _lastShape;
string op;
In the mouse down event we create a new shape and add it to the list like this
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
switch (op) {
case "toolStripButton1":
_lastShape = new FreeformLine(e.Location);
break;
case "toolStripButton2":
_lastShape = new RectangleShape(e.Location, false);
break;
case "toolStripButton3":
_lastShape = new StraightLine(e.Location);
break;
case "toolStripButton4":
_lastShape = new RectangleShape(e.Location, true);
break;
case "toolStripButton5":
_lastShape = new Ellipse(e.Location, true);
break;
case "toolStripButton6":
_lastShape = new Ellipse(e.Location, false);
break;
default:
break;
}
_shapes.Add(_lastShape);
Refresh();
}
In the MouseMove we update the last shape like this
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left && _lastShape != null) {
_lastShape.UpdateShape(e.Location);
this.Refresh();
}
}
The Paint method is now much simpler
private void Form1_Paint(object sender, PaintEventArgs e)
{
foreach (Shape shape in _shapes) {
shape.Paint(e);
}
}
Note that we do all the shape specific things in the shape classes, instead of doing them in the form. The only place in the form where have to care about the different shapes, is where we create the different shapes. This is a typical object-oriented approach. It is easier to maintain and to extend. You could add new shapes, with only a minimum changes in the form itself.