简体   繁体   English

在Picturebox c#中绘制,单击并拖动绘制的图形

[英]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?我想用c#做一个WinForm应用程序,我可以画一个图形,比如一个矩形,画完后,当我点击这个矩形时,它会显示5个框,让我拖动它来调整大小,当指向矩形的中间,它能够将它移动到图片框中的新位置,如何做到这一点? 可拖动矩形图形

Over the time I settled with following procedure for interactive pictures, such as schedules, CAD editors, or GUI designers:随着时间的推移,我对交互式图片采用了以下程序,例如日程表、CAD 编辑器或 GUI 设计器:

  • I use an System.Drawing.Image for the content of the PictureBox , which contains what has already been drawn .我使用System.Drawing.Image作为PictureBox的内容,其中包含已绘制的内容 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.创建一个DataTable (即ID as Int32, ObjectType as String, Position as System.Drawing.Point, Dim1 as Double, Dim2 as Double ),所有绘制的对象都在其中,您将在其中添加新对象。 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.然后创建一个方法,即RefreshDrawing() ,它将把表中的所有对象(“圆形”类型的DrawElipse ,“线”类型的DrawLine等)绘制DrawElipse Bitmap并用这个位图更新PictureBox.Image

  • 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 ...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设置一个状态标志(你需要创建一个,即布尔变量),即IsMoveMode = True

  • Now create/edit Paint event.现在创建/编辑Paint事件。 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因此,基于PictureBox1.MouseMove在这里绘制代表正在移动的图形(或边界框,或任何您喜欢的东西)的对象,(且仅当!) 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() .PictureBox1.MouseUp设置IsMoveMode = False并修改您在对象索引数据表中移动的对象,特别是对象的位置,只需调用RefreshDrawing()方法即可。 That will update the image and set it to the PictureBox.Image .这将更新图像并将其设置为PictureBox.Image The temporrary graphics in the Paint event will disapear automatically, since they apply only to "Move" mode. Paint事件中的临时图形将自动消失,因为它们仅适用于“移动”模式。

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#:这是 VB.NET 和 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#:翻译 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;
                    }
            }
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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