I want to make a WinForm Application in c# that I can draw a graphic, like a rectangle, and after drawing, when I click on the rectangle, it will show 5 boxes, to let me drag it to resize, and when pointing on the middle of the rectangle, it able to move it to the new location in the picture box, how to do so?
Over the time I settled with following procedure for interactive pictures, such as schedules, CAD editors, or GUI designers:
I use an System.Drawing.Image
for the content of the PictureBox
, which contains what has already been drawn . So don't draw objects directly. Create a DataTable
(ie ID as Int32, ObjectType as String, Position as System.Drawing.Point, Dim1 as Double, Dim2 as Double
), where all drawn objects sit and where you'll be adding new. Then create a method, ie RefreshDrawing()
, that will draw all the objects in the table ( DrawElipse
for a "Circle" type, DrawLine
for "Line" type, etc.) into a Bitmap
and update PictureBox.Image
with this bitmap.
if you want to find objects by mouse, you need to create an index table and record the objects position as described above. You fill the table when creating an object (ie circle, rectangle, polygon, line,...). I usually use center of object as a reference point (in your case it's the center of the central rectangle/handle).
On PictureBox1.MouseDown
...
starting mouse click coordinates are recorded
search the index table for object to be moved, using starting mouse coordinates - in your case, you can limit it to the area of your central handle, as you described in your post.
set a status flag (you need to create one, ie a boolean variable), ie IsMoveMode = True
Now create/edit Paint
event. Everything temporrary goes into temp event. So draw here objects representing the graphics that is being moved (or bounding box, or whatever you like) based on PictureBox1.MouseMove
, while (and only while!) IsMoveMode = True
On PictureBox1.MouseUp
set IsMoveMode = False
and modify the object you moved in the objects index datatable, particularly the position of the object, and simply call method RefreshDrawing()
. That will update the image and set it to the PictureBox.Image
. The temporrary graphics in the Paint
event will disapear automatically, since they apply only to "Move" mode.
Once you get objects to move, you can expand the logic analogically to resizing and other graphical operations too.
If it sounds complicated, believe me that for the result you're looking for it doesn't get more simple that this. And it is very simple, when you get to understand the parts.
Here is a complete (simplified) solution in VB.NET and C#:
Imports System.Drawing
Public Class DrawingForm
Dim IndexTable As New DataTable
Dim IsMoveMode As Boolean = False
Dim MovedObjectID As Int32 = -1
Dim MovePoint As Point = Nothing
Private Sub DrawingForm_Load(sender As Object, e As EventArgs) Handles MyBase.Load
IndexTable.Columns.Add("ID", GetType(Int32))
IndexTable.Columns.Add("ObjectType", GetType(String))
IndexTable.Columns.Add("Position", GetType(Point))
IndexTable.Columns.Add("Size", GetType(Size))
' Sample objects
IndexTable.Rows.Add({1, "Rec", New Point(30, 50), New Size(100, 60)})
IndexTable.Rows.Add({1, "Cir", New Point(200, 180), New Size(100, 100)})
Call RefreshDrawing()
End Sub
Private Sub RefreshDrawing()
Dim bmp As Bitmap
'If Not IsNothing(PictureBox1.Image) Then
' bmp = PictureBox1.Image.Clone
'Else
' bmp = New Bitmap(PictureBox1.Width, PictureBox1.Height)
'End If
bmp = New Bitmap(PictureBox1.Width, PictureBox1.Height)
Using g As Graphics = Graphics.FromImage(bmp)
For Each DrawingObject As DataRow In IndexTable.Rows
Dim osize As Size = CType(DrawingObject("Size"), Size)
Dim opos As Point = CType(DrawingObject("Position"), Point)
Select Case DrawingObject("ObjectType")
Case "Rec" ' Rectangle
g.FillRectangle(Brushes.DarkGreen, New Rectangle(opos.X - osize.Width / 2, opos.Y - osize.Height / 2, osize.Width, osize.Height))
Case "Cir" ' Circle
g.FillEllipse(Brushes.PaleVioletRed, New Rectangle(opos.X - osize.Width / 2, opos.Y - osize.Height / 2, osize.Width, osize.Height))
End Select
Next
End Using
PictureBox1.Image = bmp
PictureBox1.Invalidate()
End Sub
Private Function GetDrawingObject(MousePos As Point) As Int32
Dim ClosestObjectRowID As Int32 = -1
Dim ClosestPosition As Point = New Point(0, 0)
For ir = 0 To IndexTable.Rows.Count - 1
Dim oPos As Point = CType(IndexTable.Rows(ir)("Position"), Point)
If Math.Sqrt((MousePos.X - oPos.X) ^ 2 + (MousePos.Y - oPos.Y) ^ 2) < Math.Sqrt((MousePos.X - ClosestPosition.X) ^ 2 + (MousePos.Y - ClosestPosition.Y) ^ 2) Then
ClosestObjectRowID = ir
ClosestPosition = oPos
End If
Next
Return ClosestObjectRowID
End Function
Private Sub PictureBox1_MouseDown(sender As Object, e As MouseEventArgs) Handles PictureBox1.MouseDown
MovedObjectID = GetDrawingObject(e.Location)
IsMoveMode = True
End Sub
Private Sub PictureBox1_MouseUp(sender As Object, e As MouseEventArgs) Handles PictureBox1.MouseUp
IsMoveMode = False
Dim orow As DataRow = IndexTable.Rows(MovedObjectID)
orow("Position") = e.Location
MovedObjectID = -1
Call RefreshDrawing()
End Sub
Private Sub PictureBox1_MouseMove(sender As Object, e As MouseEventArgs) Handles PictureBox1.MouseMove
MovePoint = e.Location
PictureBox1.Invalidate()
End Sub
Private Sub PictureBox1_Paint(sender As Object, e As PaintEventArgs) Handles PictureBox1.Paint
If IsMoveMode = True AndAlso MovedObjectID >= 0 AndAlso Not IsNothing(MovePoint) Then
Dim MovedObjectType As String = IndexTable.Rows(MovedObjectID)("ObjectType")
Dim oPos As Point = MovePoint ' CType(IndexTable.Rows(MovedObjectID)("Position"), Point)
Dim oSize As Size = CType(IndexTable.Rows(MovedObjectID)("Size"), Size)
' Using g As Graphics = Graphics.FromImage(PictureBox1.Image)
' g.Clear(Color.White)
Select Case MovedObjectType
Case "Rec" ' Rectangle
e.Graphics.DrawRectangle(Pens.DarkGreen, New Rectangle(oPos.X - oSize.Width / 2, oPos.Y - oSize.Height / 2, oSize.Width, oSize.Height))
Case "Cir" ' Circle
e.Graphics.DrawEllipse(Pens.PaleVioletRed, New Rectangle(oPos.X - oSize.Width / 2, oPos.Y - oSize.Height / 2, oSize.Width, oSize.Height))
End Select
' End Using
End If
End Sub
End Class
Translated C#:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security;
using System.Text;
using System.Threading.Tasks;
using Microsoft.VisualBasic;
using System.Drawing;
public class DrawingForm
{
private DataTable IndexTable = new DataTable();
private bool IsMoveMode = false;
private Int32 MovedObjectID = -1;
private Point MovePoint = null/* TODO Change to default(_) if this is not a reference type */;
private void DrawingForm_Load(object sender, EventArgs e)
{
IndexTable.Columns.Add("ID", typeof(Int32));
IndexTable.Columns.Add("ObjectType", typeof(string));
IndexTable.Columns.Add("Position", typeof(Point));
IndexTable.Columns.Add("Size", typeof(Size));
// Sample objects
IndexTable.Rows.Add(
{
1,
"Rec",
new Point(30, 50),
new Size(100, 60)
});
IndexTable.Rows.Add(
{
1,
"Cir",
new Point(200, 180),
new Size(100, 100)
});
RefreshDrawing();
}
private void RefreshDrawing()
{
Bitmap bmp;
// If Not IsNothing(PictureBox1.Image) Then
// bmp = PictureBox1.Image.Clone
// Else
// bmp = New Bitmap(PictureBox1.Width, PictureBox1.Height)
// End If
bmp = new Bitmap(PictureBox1.Width, PictureBox1.Height);
using (Graphics g = Graphics.FromImage(bmp))
{
foreach (DataRow DrawingObject in IndexTable.Rows)
{
Size osize = (Size)DrawingObject("Size");
Point opos = (Point)DrawingObject("Position");
switch (DrawingObject("ObjectType"))
{
case "Rec" // Rectangle
:
{
g.FillRectangle(Brushes.DarkGreen, new Rectangle(opos.X - osize.Width / (double)2, opos.Y - osize.Height / (double)2, osize.Width, osize.Height));
break;
}
case "Cir" // Circle
:
{
g.FillEllipse(Brushes.PaleVioletRed, new Rectangle(opos.X - osize.Width / (double)2, opos.Y - osize.Height / (double)2, osize.Width, osize.Height));
break;
}
}
}
}
PictureBox1.Image = bmp;
PictureBox1.Invalidate();
}
private Int32 GetDrawingObject(Point MousePos)
{
Int32 ClosestObjectRowID = -1;
Point ClosestPosition = new Point(0, 0);
for (var ir = 0; ir <= IndexTable.Rows.Count - 1; ir++)
{
Point oPos = (Point)IndexTable.Rows(ir)("Position");
if (Math.Sqrt(Math.Pow((MousePos.X - oPos.X), 2) + Math.Pow((MousePos.Y - oPos.Y), 2)) < Math.Sqrt(Math.Pow((MousePos.X - ClosestPosition.X), 2) + Math.Pow((MousePos.Y - ClosestPosition.Y), 2)))
{
ClosestObjectRowID = ir;
ClosestPosition = oPos;
}
}
return ClosestObjectRowID;
}
private void PictureBox1_MouseDown(object sender, MouseEventArgs e)
{
MovedObjectID = GetDrawingObject(e.Location);
IsMoveMode = true;
}
private void PictureBox1_MouseUp(object sender, MouseEventArgs e)
{
IsMoveMode = false;
DataRow orow = IndexTable.Rows(MovedObjectID);
orow("Position") = e.Location;
MovedObjectID = -1;
RefreshDrawing();
}
private void PictureBox1_MouseMove(object sender, MouseEventArgs e)
{
MovePoint = e.Location;
PictureBox1.Invalidate();
}
private void PictureBox1_Paint(object sender, PaintEventArgs e)
{
if (IsMoveMode == true && MovedObjectID >= 0 && !IsNothing(MovePoint))
{
string MovedObjectType = IndexTable.Rows(MovedObjectID)("ObjectType");
Point oPos = MovePoint; // CType(IndexTable.Rows(MovedObjectID)("Position"), Point)
Size oSize = (Size)IndexTable.Rows(MovedObjectID)("Size");
// Using g As Graphics = Graphics.FromImage(PictureBox1.Image)
// g.Clear(Color.White)
switch (MovedObjectType)
{
case "Rec" // Rectangle
:
{
e.Graphics.DrawRectangle(Pens.DarkGreen, new Rectangle(oPos.X - oSize.Width / (double)2, oPos.Y - oSize.Height / (double)2, oSize.Width, oSize.Height));
break;
}
case "Cir" // Circle
:
{
e.Graphics.DrawEllipse(Pens.PaleVioletRed, new Rectangle(oPos.X - oSize.Width / (double)2, oPos.Y - oSize.Height / (double)2, oSize.Width, oSize.Height));
break;
}
}
}
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.