Rectangle can't be drawn on the panel by mouse dragging runtime - c#

I am trying to draw a rectangle on a panel, but nothing is drawn. Below is the code to show how I draw a rectangle on the panel. In my code SetSelectionRect() is used to set the rectangle to be drawn. For these I use following methods.
private void Panel_MouseDown(object sender, MouseEventArgs e)
{
Point point = new Point();
this.mouseDown = true;
this.Panel.SendToBack();
point = this.Panel.PointToClient(Cursor.Position);
point.X = e.X;
point.Y = e.Y;
this.selectionStart.X = point.X;
this.selectionStart.Y = point.Y;
}
private void Panel_MouseMove(object sender, MouseEventArgs e)
{
if (!this.mouseDown)
{
return;
}
else
{
this.mouseMove = true;
Point point = this.Panel.PointToClient(Cursor.Position);
point.X = e.X;
point.Y = e.Y;
this.selectionEnd.X = point.X;
this.selectionEnd.Y = point.Y;
this.SetSelectionRect();
////this.Panel.Invalidate();
////this.Invalidate();
}
}
private void Panel_MouseUp(object sender, MouseEventArgs e)
{
SetSelectionRect();
this.GetSelectedControls();
this.mouseDown = false;
this.mouseMove = false;
////this.Panel.Invalidate();
////this.Invalidate();
this.Panel.Refresh();
}
private void Panel_Paint(object sender, PaintEventArgs e)
{
////base.OnPaint(e); drawRect = true when RectangleToolStripMenuItem is Clicked.
if (this.drawRect)
{
using (Pen pen = new Pen(Color.Black, 1F))
{
this.rectangle = new RectangleShape();
this.Panel.SendToBack();
this.shapeContainer1.Shapes.Add(this.rectangle);
this.rectangle.Location = this.selection.Location;
this.rectangle.Size = this.selection.Size;
this.rectangle.Name = "rectShape";
this.shapeContainer1.Size = this.Panel.Size;
this.shapeContainer1.Location = this.Panel.Location;
this.rectangle.Enabled = false;
this.rectangle.MouseClick += new MouseEventHandler(this.mouseclick);
this.rectangle.MouseMove += new MouseEventHandler(this.mouseMove);
this.rectangle.MouseDown += new MouseEventHandler(this.mouseDown);
this.rectangle.MouseUp += new MouseEventHandler(this.mouseUp);
this.drawRect = false;
}
}
}
protected override void OnPaint (PaintEventArgs e)
{
base.OnPaint(e);
}
What's wrong with the code?

The problem is base.OnPaint(e); is raising an Paint event, where you placed base.OnPaint(e);, so it calling itself again and again.
private void panel_Paint(object sender, PaintEventArgs e)
{
//base.OnPaint(e); // remove it from here
// something to do.
}
base.OnPaint(e); should be called in overriden method:
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
}

Related

What is wrong with my Rectangle drawing coordinates?

I'm trying to use the following code to allow the user to draw a rectangle around something on the screen, to select that area.
public partial class MainWindow : Window
{
public enum DrawMode
{
Move,
Draw
}
private DrawMode _drawmode;
private Point _startPoint;
private Rectangle _rectangle;
public MainWindow()
{
_rectangle = new Rectangle();
_rectangle.Stroke = new SolidColorBrush(Colors.Black);
_rectangle.StrokeThickness = 1;
InitializeComponent();
}
private void MapImageOnMouseDown(object sender, MouseButtonEventArgs e)
{
_drawmode = DrawMode.Draw;
_startPoint = e.GetPosition(DrawCanvas);
}
private void MapImageOnMouseUp(object sender, MouseButtonEventArgs e)
{
_drawmode = DrawMode.Move;
}
private void MapImageOnMouseMove(object sender, MouseEventArgs e)
{
if (_drawmode == DrawMode.Draw)
{
DrawCanvas.Children.Remove(_rectangle);
var endPoint = e.GetPosition(DrawCanvas);
var width = Math.Abs(endPoint.X - _startPoint.X);
var height = Math.Abs(endPoint.Y - _startPoint.Y);
_rectangle.Width = width;
_rectangle.Height = height;
DrawCanvas.Children.Add(_rectangle);
Canvas.SetTop(_rectangle, _startPoint.X);
Canvas.SetLeft(_rectangle, _startPoint.Y);
}
}
}
However, although when I mousedown, the top left of the rectangle is nowhere near the point that I mousedown at. Are there different coordinate systems or something?
You have confused X and Y (or Left and Top). Change
Canvas.SetTop(_rectangle, _startPoint.X);
Canvas.SetLeft(_rectangle, _startPoint.Y);
to
Canvas.SetLeft(_rectangle, _startPoint.X);
Canvas.SetTop(_rectangle, _startPoint.Y);
It is also not necessary to remove and add the Rectangle each time its position changes:
public MainWindow()
{
InitializeComponent();
_rectangle = new Rectangle
{
Stroke = Brushes.Black,
StrokeThickness = 1
};
DrawCanvas.Children.Add(_rectangle); // add it once
}
private void MapImageOnMouseMove(object sender, MouseEventArgs e)
{
if (_drawmode == DrawMode.Draw)
{
var endPoint = e.GetPosition(DrawCanvas);
_rectangle.Width = Math.Abs(endPoint.X - _startPoint.X);
_rectangle.Height = Math.Abs(endPoint.Y - _startPoint.Y);
Canvas.SetLeft(_rectangle, Math.Min(_startPoint.X, endPoint.X));
Canvas.SetTop(_rectangle, Math.Min(_startPoint.Y, endPoint.Y));
}
}
Point startPoint = new Point(0, 0);
Point endPoint = new Point(1, 1);
bool mousePress = false;
control.MouseDown += (s, e) =>
{
startPoint = new Point(e.X,e.Y);
mousePress = true;
};
control.MouseUp += (s, e) =>
{
mousePress = false;
};
control.MouseMove += (s, e) =>
{
if (mousePress)
{
endPoint = new Point(e.X, e.Y);
control.Invalidate();
}
};
control.Paint += (s, e) =>
{
Graphics g = e.Graphics;
g.DrawRectangle(Pens.Black, new Rectangle(startPoint.X, startPoint.Y,endPoint.X-startPoint.X, endPoint.Y-startPoint.Y));
};
I have been doing drawing in the past and this worked for me for rectangles, dont know how it translates to wpf tho

Move rectangle with mouse using translate/transform

I need to make a graph of lines from a csv file and draw it with GDI got a Windows form but now I want to change the scale and move.
I started with something more simple as moving a rectangle with the mouse but to start drawing the rectangle always from the origin.
Can anyone help?
My code is:
public partial class Form1 : Form {
int origenX;
int origenY;
bool transformar = false;
public Form1() {
InitializeComponent();
}
private void Form1_Paint(object sender, PaintEventArgs e) {
dibujar(e.Graphics);
}
private void Form1_MouseMove(object sender, MouseEventArgs e) {
int deltaX = e.X - origenX;
int deltaY = e.Y - origenY;
if (transformar) {
System.Drawing.Graphics g = this.CreateGraphics();
Matrix mAux = new Matrix();
mAux.Translate(deltaX, deltaY);
g.Transform = mAux;
dibujar(g);
g.Dispose();
}
this.Text = "x=" + deltaX.ToString() + ", y=" + deltaY.ToString();
}
private void Form1_MouseDown(object sender, MouseEventArgs e) {
transformar = true;
origenX = e.X;
origenY = e.Y;
}
private void Form1_MouseUp(object sender, MouseEventArgs e) {
transformar = false;
}
private void dibujar(System.Drawing.Graphics g) {
g.Clear(Color.White);
g.DrawEllipse(new Pen(Color.Blue, 2), new Rectangle(50, 50, 50, 50));
}
}
Already solved, thanks anyway, the code was as follows:
public partial class Form2 : Form {
private float dx=0;
private float dy=0;
private float X0=1;
private float Y0=1;
private bool trasladar = false;
public Form2() {
InitializeComponent();
}
private void Form2_Paint(object sender, PaintEventArgs e) {
e.Graphics.TranslateTransform(dx, dy, MatrixOrder.Append);
e.Graphics.Clear(Color.White);
e.Graphics.DrawEllipse(new Pen(Color.Blue), new Rectangle(50, 50, 50, 50));
}
private void Form2_MouseDown(object sender, MouseEventArgs e) {
Cursor = Cursors.SizeAll;
trasladar = true;
X0 = e.X;
Y0 = e.Y;
}
private void Form2_MouseUp(object sender, MouseEventArgs e) {
Cursor = Cursors.Default;
trasladar = false;
}
private void Form2_MouseMove(object sender, MouseEventArgs e) {
if (trasladar) {
dx += (e.X - X0);
dy += (e.Y - Y0);
X0 = e.X;
Y0 = e.Y;
Invalidate();
}
}
}
Use this.Invalidate(); when the form should redraw.
It will declare the form as invalid, so it will be forced to redraw. Only then the Form1_Paint will be called.
Test this behaivour by doing an Debug output in the Paint-Event.
Then you can start further debugging to get what you want.

Draw on Panel, save as Bitmap

I'm trying to make a simple application where the user can draw on the Panel and save it to their computer as a bitmap. When I proceed to the save part, however, all I get is an empty (white) bitmap.
I've been browsing many other solutions and I am pretty sure I am saving the bitmap the correct way, so I am starting to wonder if my drawing process is incorrect. What exactly is wrong here?
public partial class Form1 : Form
{
SolidBrush brush;
Pen pen;
Point[] points = new Point[3];
Graphics display;
Bitmap bmap;
public Form1()
{
InitializeComponent();
display = panel1.CreateGraphics();
bmap = new Bitmap(panel1.Width, panel1.Height);
}
private void panel1_MouseDown(object sender, MouseEventArgs e)
{
brush = new SolidBrush(Color.Black);
pen = new Pen(Color.Black);
display.FillEllipse(brush, e.X, e.Y, 10, 10);
panel1.DrawToBitmap(bmap, new Rectangle(0, 0, panel1.Width, panel1.Height));
//this.Invalidate();
}
private void clearToolStripMenuItem_Click(object sender, EventArgs e)
{
Graphics display = panel1.CreateGraphics();
display.Clear(panel1.BackColor);
}
private void saveToolStripMenuItem_Click(object sender, EventArgs e)
{
bmap.Save(#"C:\Temp\Test.bmp");
}
}
EDIT
With this revision, I just get a black bmp and I don't even see elipses being created anymore on my screen. Although I did notice that if I put invalidate and Draw to bitmap back in the mousedown event, then the save button will save the last ellipse, while there is still nothing appearing on my screen.
private void panel1_MouseDown(object sender, MouseEventArgs e)
{
mousedown = true;
x = e.X;
y = e.Y;
}
private void panel1_Paint(object sender, PaintEventArgs e)
{
//Graphics g = e.Graphics;
if(mousedown==true)
{
brush = new SolidBrush(Color.Black);
pen = new Pen(Color.Black);
Graphics.FromImage(bmap).FillEllipse(brush, x, y, 10, 10);
panel1.Invalidate();
//panel1.DrawToBitmap(bmap, new Rectangle(0, 0, panel1.Width, panel1.Height));
//panel1.Invalidate();
}
}
As Hans did most of the work in his comment, here is how your code should probably look:
public partial class Form1 : Form {
Bitmap bmap;
public Form1() {
InitializeComponent();
bmap = new Bitmap(panel1.ClientWidth, panel1.ClientHeight);
panel1.MouseDown += panel1_MouseDown;
panel1.Paint += panel1_Paint;
}
void panel1_Paint(object sender, PaintEventArgs e) {
e.Graphics.DrawImage(bmap, Point.Empty);
}
void panel1_MouseDown(object sender, MouseEventArgs e) {
using (Graphics g = Graphics.FromImage(bmap)) {
g.FillEllipse(Brushes.Black, e.X, e.Y, 10, 10);
}
panel1.Invalidate();
}
private void clearToolStripMenuItem_Click(object sender, EventArgs e) {
using (Graphics g = Graphics.FromImage(bmap)) {
g.Clear(Color.White);
}
panel1.Invalidate();
}
private void saveToolStripMenuItem_Click(object sender, EventArgs e) {
bmap.Save(#"c:\temp\bmap.bmp");
}
}
CreateGraphics is just a temporary canvas, so you rarely, if ever, use that for drawing purposes, especially since you are trying to save an image.
This will works fine. I tested it and worked well
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace drawing
{
public partial class Form2 : Form
{
Graphics g;
bool startPaint = false;
int? initX = null;
int? initY = null;
bool drawSquare = false;
bool drawRectangle = false;
bool drawCircle = false;
public Form2()
{
InitializeComponent();
bmp = new Bitmap(panel1.ClientSize.Width, panel1.ClientSize.Height);
}
Bitmap bmp;
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
}
void panel1_MouseMove(object sender, MouseEventArgs e)
{
if (startPaint)
{
using ( g = Graphics.FromImage(bmp))
{
// g.FillEllipse(Brushes.Black, new Rectangle(e.X, e.Y , 5, 5));
Pen p = new Pen(btn_PenColor.BackColor, float.Parse(cmb_PenSize.Text));
g.DrawLine(p, new Point(initX ?? e.X, initY ?? e.Y), new Point(e.X, e.Y));
initX = e.X;
initY = e.Y;
//g.DrawImage(bmp, new Rectangle(e.X - 4, e.Y - 4, 8, 8));
}
panel1.Invalidate();
}
}
private void pnl_Draw_MouseDown(object sender, MouseEventArgs e)
{
startPaint = true;
if (drawSquare)
{
//Use Solid Brush for filling the graphic shapes
SolidBrush sb = new SolidBrush(btn_PenColor.BackColor);
//setting the width and height same for creating square.
//Getting the width and Heigt value from Textbox(txt_ShapeSize)
g.FillRectangle(sb, e.X, e.Y, int.Parse(txt_ShapeSize.Text), int.Parse(txt_ShapeSize.Text));
//setting startPaint and drawSquare value to false for creating one graphic on one click.
startPaint = false;
drawSquare = false;
}
if (drawRectangle)
{
SolidBrush sb = new SolidBrush(btn_PenColor.BackColor);
//setting the width twice of the height
g.FillRectangle(sb, e.X, e.Y, 2 * int.Parse(txt_ShapeSize.Text), int.Parse(txt_ShapeSize.Text));
startPaint = false;
drawRectangle = false;
}
if (drawCircle)
{
SolidBrush sb = new SolidBrush(btn_PenColor.BackColor);
g.FillEllipse(sb, e.X, e.Y, int.Parse(txt_ShapeSize.Text), int.Parse(txt_ShapeSize.Text));
startPaint = false;
drawCircle = false;
}
}
private void pnl_Draw_MouseUp(object sender, MouseEventArgs e)
{
startPaint = false;
initX = null;
initY = null;
}
void panel1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.DrawImage(bmp, Point.Empty);
}
private void button1_Click(object sender, EventArgs e)
{
bmp.Save("D://filename.jpg", ImageFormat.Png);
}
}
}

Drag and Drop Function with Drawing Rectangle C# .net - Forms

I want to drag and drop that I have drawn on the forms. Here is my code for drawing the rectangle. An this works fine.
Rectangle rec = new Rectangle(0, 0, 0, 0);
public Form1()
{
InitializeComponent();
this.DoubleBuffered = true;
}
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();
}
}
Now I want to drag and drop that rectangle in to a different place.
Pls help How to do that
Thank You
yohan
I have written a helper class for this kind of stuff:
class ControlMover
{
public enum Direction
{
Any,
Horizontal,
Vertical
}
public static void Init(Control control)
{
Init(control, Direction.Any);
}
public static void Init(Control control, Direction direction)
{
Init(control, control, direction);
}
public static void Init(Control control, Control container, Direction direction)
{
bool Dragging = false;
Point DragStart = Point.Empty;
control.MouseDown += delegate(object sender, MouseEventArgs e)
{
Dragging = true;
DragStart = new Point(e.X, e.Y);
control.Capture = true;
};
control.MouseUp += delegate(object sender, MouseEventArgs e)
{
Dragging = false;
control.Capture = false;
};
control.MouseMove += delegate(object sender, MouseEventArgs e)
{
if (Dragging)
{
if (direction != Direction.Vertical)
container.Left = Math.Max(0, e.X + container.Left - DragStart.X);
if (direction != Direction.Horizontal)
container.Top = Math.Max(0, e.Y + container.Top - DragStart.Y);
}
};
}
}
Then I just Initialize it in my form load event with my control:
ControlMover.Init(myControl, myContainer, ControlMover.Direction.Any);
Well, you don't have a control to move. It's a rectangle. But hopefully, you'll get the idea.
UPDATE: Have you checked out the related questions listed in this page? Try:
Drag and drop rectangle in C#

Draw lines on a picturebox using mouse clicks in C#

I'm trying to make a program that will draw lines over a picturebox using mouse clicks for the locations of where the line is to be drawn from and to. This is my current code:
public partial class Form1 : Form
{
int Drawshape;
private Point p1, p2;
List<Point> p1List = new List<Point>();
List<Point> p2List = new List<Point>();
public Form1()
{
InitializeComponent();
pictureBox1.Image = new Bitmap(pictureBox1.Width, pictureBox1.Height);
}
private void button1_Click(object sender, EventArgs e)
{
Drawshape = 1;
}
private void button2_Click(object sender, EventArgs e)
{
Drawshape = 2;
}
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
if (Drawshape == 1)
{
if (p1.X == 0)
{
p1.X = e.X;
p1.Y = e.Y;
}
else
{
p2.X = e.X;
p2.Y = e.Y;
p1List.Add(p1);
p2List.Add(p2);
Invalidate();
p1.X = 0;
}
}
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
Graphics G = Graphics.FromImage(pictureBox1.Image);
if (Drawshape == 1)
{
using (var p = new Pen(Color.Blue, 4))
{
for (int x = 0; x < p1List.Count; x++)
{
G.DrawLine(p, p1List[x], p2List[x]);
}
}
}
}
At the moment it doesn't allow me to draw on the picturebox at all. How would that be possible?
Change Invalidate(); to pictureBox1.Invalidate();
You need to draw each line on the Image object (using Graphics.FromImage) after creating the line.
You also need to dispose the Graphics object in a using block.

Categories