简体   繁体   中英

Draw, Click and drag a drawn graphics in Picturebox c#

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM