前言

  • 本文描述了如何使用Winform窗体中的控件,绘制形状(如:矩形),实现添加、删除、选中、移动、缩放。点击按钮添加矩形。
  • WinForms (Windows Forms) 是微软.NET框架中的一个图形用户界面(GUI)类库,用于开发Windows桌面应用程序。
  • 在创建窗体后可以通过拖拽方式创建各种控件(如文本框按钮等)。

【C#】Winform窗体任意控件绘制形状图形(实现添加、删除、选中、移动、缩放功能)_c#

演示案例

运行效果1

【C#】Winform窗体任意控件绘制形状图形(实现添加、删除、选中、移动、缩放功能)_c#_02

运行效果2

【C#】Winform窗体任意控件绘制形状图形(实现添加、删除、选中、移动、缩放功能)_c#_03

代码讲解

Shape类

【C#】Winform窗体任意控件绘制形状图形(实现添加、删除、选中、移动、缩放功能)_控件_04

public abstract class Shape
 {
     #region 字段、属性
     private int _id = -1;
     private Color _shapeColor = Color.Blue;   //填充颜色
     private Color _handleColor = Color.Blue; //边框颜色
     private float _borderWidth = 0;            //边缘宽度
     private int _alpha = 50;                 // 透明度            
     private int _handleSize = 8;             // 手柄的视觉大小
     private int _handleOutSize = 16;         // 手柄外区域大小(比视觉大)
     private bool _isSelected = true;         //选中状态
     private static int _nextId = 0;
     public int ID { get => _id; private set => _id = value; }
     public Color ShapeColor { get => _shapeColor; set => _shapeColor = value; }
     public Color HandleColor { get => _handleColor; set => _handleColor = value; }
     public float BorderWidth { get => _borderWidth; set => _borderWidth = value; }
     public int Alpha { get => _alpha; set => _alpha = value; }
     public int HandleSize
     {
         get => _handleSize;
         set
         {
             if (_handleSize != value)
             {
                 _handleSize = value;
                 HandleOutSize = value * 2;
             }
         }
     }
     public int HandleOutSize { 
         get => _handleOutSize; 
         set
         {
             if (_handleOutSize != value)
             {
                 _handleOutSize = value;
                 _handleSize = value / 2;
             }
         }
     }
     public bool IsSelected { get => _isSelected; set => _isSelected = value; }
     #endregion
     #region 构造函数
     protected Shape()
     {
         //获取不重复的ID,当前程序运行生效。
         ID = Interlocked.Increment(ref _nextId);
     }
     #endregion
     #region 抽象方法
     /// <summary>
     /// 点是否在手柄上
     /// </summary>
     public abstract bool IsInHandle(Point point, int x, int y);
     /// <summary>
     /// 获取手柄类型
     /// </summary>
     public abstract HandleType GetHandleType(Point point);
     /// <summary>
     /// 绘制手柄
     /// </summary>
     protected abstract void DrawHandle(Graphics graphics, int x, int y);
     /// <summary>
     /// 绘制形状和手柄
     /// </summary>
     public abstract void DrawShapeWithHandles(Graphics graphics);
     #endregion
 }
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.

URectangle 类

  • 继承Shape类,方便统一形状。

创建矩形的基本属性:

  • 矩形的基本属性参数(X,Y,Width,Height)。
  • Rectangle 实际显示的矩形,RectangleF :用于缩放转换矩形

重写方法:

  • 重写形状方法,实现具体的绘制图形功能。
public class URectangle: Shape
{
    #region 字段|属性
    private Rectangle rectangle;
    public Rectangle Rectangle 
    { 
        get => rectangle; 
        set => rectangle = value; 
    }
    private RectangleF rectangleF;
    public RectangleF RectangleF 
    { 
        get => rectangleF; 
        set => rectangleF = value; 
    }
    public int X { 
        get { return rectangle.X; }
        set
        {
            if (rectangle != null) rectangle.X = value;
        }
    }
    public int Y {
        get { return rectangle.Y; }
        set
        {
            if (rectangle != null) rectangle.Y = value;
        }
    }
    public Point Point
    {
        get => new Point(X, Y);
        set
        {
            X = value.X;
            Y = value.Y;
        }
    }
    public int Width {
        get => rectangle.Width;
        set
        {
            if (rectangle!=null)
            {
                rectangle.Width = value;
            }
        }
    }
    public int Height { 
        get => rectangle.Height;
        set
        {
            if (rectangle != null)
            {
                rectangle.Height = value;
            }
        }
    }
    public Size Location
    {
        get => new Size(Width, Width);
        set
        {
            Width = value.Width;
            Width = value.Width;
        }
    }
    #endregion
    #region 构造函数
    public URectangle():base()
    {
    }
    public URectangle(Rectangle rectangle)
    {
        this.rectangle = rectangle;
    }
    #endregion
    #region 绘制矩形相关
    /// <summary>
    /// 绘制矩形和手柄(选中时绘制):
    /// </summary>
    public override void DrawShapeWithHandles(Graphics graphics)
    {
        using (var brush = new SolidBrush(Color.FromArgb(Alpha, ShapeColor)))
        {
            graphics.FillRectangle(brush, rectangle);
        }
        Pen pen = new Pen(ShapeColor, BorderWidth);
        graphics.DrawRectangle(pen, rectangle);
        if (IsSelected)
        {
            DrawHandle(graphics, rectangle.Left, rectangle.Top);       // 左上角
            DrawHandle(graphics, rectangle.Right, rectangle.Top);      // 右上角
            DrawHandle(graphics, rectangle.Left, rectangle.Bottom);    // 左下角
            DrawHandle(graphics, rectangle.Right, rectangle.Bottom);   // 右下角
        }
    }
    /// <summary>
    /// 绘制手柄:
    /// </summary>
    protected override void DrawHandle(Graphics graphics, int x, int y)
    {
        Rectangle handleRect = new Rectangle( x - HandleSize / 2,y - HandleSize / 2,HandleSize,HandleSize);
        using (var brush = new SolidBrush(Color.FromArgb(Alpha, HandleColor)))
        {
            graphics.FillRectangle(brush, handleRect);
        }
        Pen pen = new Pen(HandleColor, BorderWidth);
        graphics.DrawRectangle(pen, handleRect);
    }
    /// <summary>
    /// 获取要显示的手柄类型:根据指定点,判断当前矩形应该使用什么类型的手柄。
    /// </summary>
    public override HandleType GetHandleType(Point point)
    {
        if (IsInHandle(point, rectangle.Left, rectangle.Top)) 
            return HandleType.TopLeft;
        if (IsInHandle(point, rectangle.Right, rectangle.Top)) 
            return HandleType.TopRight;
        if (IsInHandle(point, rectangle.Left, rectangle.Bottom)) 
            return HandleType.BottomLeft;
        if (IsInHandle(point, rectangle.Right, rectangle.Bottom)) 
            return HandleType.BottomRight;
        return HandleType.None;
    }
    /// <summary>
    /// 指定点是否在手柄范围内
    /// </summary>
    public override bool IsInHandle(Point point, int x, int y)
    {
        Rectangle handleRect = new Rectangle(x - HandleOutSize / 2,y - HandleOutSize / 2,HandleOutSize,HandleOutSize);
        return handleRect.Contains(point);
    }
    #endregion
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.
  • 111.
  • 112.
  • 113.
  • 114.
  • 115.
  • 116.
  • 117.
  • 118.
  • 119.
  • 120.
  • 121.
  • 122.
  • 123.
  • 124.
  • 125.
  • 126.
  • 127.
  • 128.
  • 129.
  • 130.
  • 131.
  • 132.
  • 133.
  • 134.
  • 135.

ShapeModule 类 -

  • 创建URectangle 类对象只能创建基本的形状,具体还需要将形状图形绘制到控件中,下面的模块就是如何实现该绘制形状到控件容器中。
通过创建事件、并给容器绑定事件,然后根据事件操作判断实现功能:

【C#】Winform窗体任意控件绘制形状图形(实现添加、删除、选中、移动、缩放功能)_WinForm_05

public class ShapeModule
 {
     #region 字段 | 属性
     private float scaleX = 1.0f;                        //缩放X
     private float scaleY = 1.0f;                        //缩放Y
     private bool isScaled = false;                      //是否缩放
     private int selectedIndex = -1;                     //选择索引
     private DrawMode currentMode = DrawMode.None;       //当前模式
     private HandleType handleType = HandleType.None;    //手柄类型
     private Point startPoint;                           //起始点
     private Control container;                          //形状显示容器
     private URectangle currentRect;                     //当前矩形
     private URectangle displayRect;                     //选择的矩形
     private ContextMenuStrip rightKeyMenuStrip;         //右键菜单
     private Dictionary<int, Shape> _shapeDictionary;    //形状存储字典
     public float ScaleX
     {
         get => scaleX;
         set
         {
             scaleX = value;
             UpdateDisplayShape();
         }
     }
     public float ScaleY
     {
         get => scaleY;
         set
         {
             scaleY = value;
             UpdateDisplayShape();
         }
     }
     public DrawMode CurrentMode
     {
         get => currentMode;
         set => currentMode = value;
     }
     public Dictionary<int, Shape> ShapeDictionary { get => _shapeDictionary;private set => _shapeDictionary = value; }
     #endregion
     #region 构造函数
     public ShapeModule(Control container)
     {
         Initialize(container);
     }
     #endregion
     #region 初始化
     private void Initialize(Control container)
     {
         this.container = container;
         ShapeDictionary = new Dictionary<int, Shape>();
         InitializeContainer();
         InitializeRightKeyMenu();
     }
     #region 初始化容器
     private void InitializeContainer()
     {
         container.MouseDown += Container_MouseDown;
         container.MouseUp += Container_MouseUp;
         container.MouseMove += Container_MouseMove;
         container.MouseUp += Container_MouseUp;
         container.MouseWheel += Container_MouseWheel;
         container.Paint += Container_Paint;
     }
     #endregion
     #region 右键菜单功能
     private void InitializeRightKeyMenu()
     {
         // 创建菜单项
         rightKeyMenuStrip = new ContextMenuStrip();
         var copyItem = new ToolStripMenuItem("复制");
         copyItem.Click += (s, e) => CopyAction();
         var deleteItem = new ToolStripMenuItem("删除");
         deleteItem.Click += (s, e) => DeleteAction();
         // 创建右键菜单
         rightKeyMenuStrip.Items.Add(copyItem);
         rightKeyMenuStrip.Items.Add(deleteItem);
     }
     private void CopyAction()
     {
     }
     private void DeleteAction()
     {
         ShapeDictionary.Remove(selectedIndex);
         selectedIndex = -1;
         container.Invalidate();
     }
     #endregion
     #endregion
     #region 形状显示相关:缩放、显示
     /// <summary>
     /// 更新显示形状
     /// </summary>
     private void UpdateDisplayShape()
     {
         foreach (var shape in ShapeDictionary.Values)
         {
             if (shape is URectangle rectangle)
             {
                 rectangle.Rectangle = new Rectangle(
                    (int)(rectangle.RectangleF.X * scaleX),
                    (int)(rectangle.RectangleF.Y * scaleY),
                    (int)(rectangle.RectangleF.Width * scaleX),
                    (int)(rectangle.RectangleF.Height * scaleY));
             }
         }
         container.Invalidate();
     }
     /// <summary>
     /// 缩小
     /// </summary>
     private RectangleF ScaleDown(Rectangle rect)
     {
         return new RectangleF(
             rect.X / scaleX,
             rect.Y / scaleY,
             rect.Width / scaleX,
             rect.Height / scaleY);
     }
     /// <summary>
     /// 放大
     /// </summary>
     private Rectangle ScaleUp(RectangleF rect)
     {
         return new Rectangle(
             (int)(rect.X * scaleX),
             (int)(rect.Y * scaleY),
             (int)(rect.Width * scaleX),
             (int)(rect.Height * scaleY));
     }
     /// <summary>
     /// 放大
     /// </summary>
     private void ZoomIn()
     {
         ScaleX += 0.1F;
         ScaleY += 0.1F;
     }
     /// <summary>
     /// 缩小
     /// </summary>
     private void ZoomOut()
     {
         ScaleX -= 0.1F;
         ScaleY -= 0.1F;
     }
     #endregion
     #region 事件
     private void Container_MouseDown(object sender, MouseEventArgs e)
     {
         if (e.Button == MouseButtons.Left)
         {
             // 形状绘制
             if (CurrentMode == DrawMode.Drawing)
             {
                 currentRect = new URectangle();
                 startPoint = e.Location;
                 currentRect.Rectangle = new Rectangle(e.Location, Size.Empty);
             }
             // 形状移动
             else if (CurrentMode == DrawMode.Moving)
             {
                 int dx = e.X - startPoint.X;
                 int dy = e.Y - startPoint.Y;
                 displayRect.X += dx;
                 displayRect.Y += dy;
                 displayRect.RectangleF = ScaleDown(displayRect.Rectangle);
                 startPoint = e.Location;
             }
             // 形状调整大小
             else if (CurrentMode == DrawMode.Resizing)
             {
                 Rectangle rect = displayRect.Rectangle;
                 switch (handleType)
                 {
                     case HandleType.TopLeft:
                         rect.X = e.X;
                         rect.Y = e.Y;
                         rect.Width = displayRect.Rectangle.Right - e.X;
                         rect.Height = displayRect.Rectangle.Bottom - e.Y;
                         break;
                     case HandleType.TopRight:
                         rect.Y = e.Y;
                         rect.Width = e.X - displayRect.Rectangle.Left;
                         rect.Height = displayRect.Rectangle.Bottom - e.Y;
                         break;
                     case HandleType.BottomLeft:
                         rect.X = e.X;
                         rect.Width = displayRect.Rectangle.Right - e.X;
                         rect.Height = e.Y - displayRect.Rectangle.Top;
                         break;
                     case HandleType.BottomRight:
                         rect.Width = e.X - displayRect.Rectangle.Left;
                         rect.Height = e.Y - displayRect.Rectangle.Top;
                         break;
                 }
                 // 确保宽度和高度不为负
                 if (rect.Width > 0 && rect.Height > 0)
                 {
                     displayRect.RectangleF = ScaleDown(rect);
                     displayRect.Rectangle = rect;
                 }
             }
             // 形状判断选择
             else
             {
                 selectedIndex = -1;
                 foreach (var shape in ShapeDictionary.Values)
                 {
                     if (shape is URectangle uRectangle)
                     {
                         if (uRectangle.Rectangle.Contains(e.Location)
                             || uRectangle.GetHandleType(e.Location) != HandleType.None)
                         {
                             selectedIndex = uRectangle.ID;
                             displayRect = uRectangle;
                             startPoint = e.Location;
                             handleType = uRectangle.GetHandleType(e.Location);
                             CurrentMode = handleType != HandleType.None ? DrawMode.Resizing : DrawMode.Moving;
                             break;
                         }
                     }
                 }
             }
         }
         //右键菜单
         if (e.Button == MouseButtons.Right)
         {
             if (selectedIndex != -1)
             {
                 rightKeyMenuStrip.Show(container, e.Location);
             }
         }
         container.Invalidate();
     }
     private void Container_MouseMove(object sender, MouseEventArgs e)
     {
         if (e.Button == MouseButtons.Left)
         {
             if (CurrentMode == DrawMode.Drawing)
             {
                 int x = Math.Min(startPoint.X, e.X);
                 int y = Math.Min(startPoint.Y, e.Y);
                 int width = Math.Abs(startPoint.X - e.X);
                 int height = Math.Abs(startPoint.Y - e.Y);
                 currentRect.Rectangle = new Rectangle(x, y, width, height);
             }
             else if (CurrentMode == DrawMode.Moving && selectedIndex >= 0)
             {
                 int dx = e.X - startPoint.X;
                 int dy = e.Y - startPoint.Y;
                 displayRect.X += dx;
                 displayRect.Y += dy;
                 ShapeDictionary[selectedIndex] = displayRect;
                 displayRect.RectangleF = ScaleDown(displayRect.Rectangle);
                 startPoint = e.Location;
             }
             else if (CurrentMode == DrawMode.Resizing && selectedIndex >= 0)
             {
                 Rectangle rect = displayRect.Rectangle;
                 switch (handleType)
                 {
                     case HandleType.TopLeft:
                         rect.X = e.X;
                         rect.Y = e.Y;
                         rect.Width = displayRect.Rectangle.Right - e.X;
                         rect.Height = displayRect.Rectangle.Bottom - e.Y;
                         break;
                     case HandleType.TopRight:
                         rect.Y = e.Y;
                         rect.Width = e.X - displayRect.Rectangle.Left;
                         rect.Height = displayRect.Rectangle.Bottom - e.Y;
                         break;
                     case HandleType.BottomLeft:
                         rect.X = e.X;
                         rect.Width = displayRect.Rectangle.Right - e.X;
                         rect.Height = e.Y - displayRect.Rectangle.Top;
                         break;
                     case HandleType.BottomRight:
                         rect.Width = e.X - displayRect.Rectangle.Left;
                         rect.Height = e.Y - displayRect.Rectangle.Top;
                         break;
                 }
                 if (rect.Width > 0 && rect.Height > 0)
                 {
                     displayRect.Rectangle = rect;
                     displayRect.RectangleF = ScaleDown(rect);
                     ShapeDictionary[selectedIndex] = displayRect;
                 }
             }
         }
         else
         {
             if (selectedIndex >= 0)
             {
                 handleType = displayRect.GetHandleType(e.Location);
                 switch (handleType)
                 {
                     case HandleType.TopLeft:
                     case HandleType.BottomRight:
                         container.Cursor = Cursors.SizeNWSE;
                         break;
                     case HandleType.TopRight:
                     case HandleType.BottomLeft:
                         container.Cursor = Cursors.SizeNESW;
                         break;
                     default:
                         container.Cursor = displayRect.Rectangle.Contains(e.Location) ?
                             Cursors.SizeAll : Cursors.Default;
                         break;
                 }
             }
             else
             {
                 container.Cursor = Cursors.Default;
             }
         }
         container.Invalidate();
     }
     private void Container_MouseUp(object sender, MouseEventArgs e)
     {
         if (e.Button == MouseButtons.Left)
         {
             if (CurrentMode == DrawMode.Drawing && currentRect.Width > 0 && currentRect.Height > 0)
             {
                 currentRect.RectangleF = ScaleDown(currentRect.Rectangle);
                 ShapeDictionary.Add(currentRect.ID, currentRect);
                 selectedIndex = currentRect.ID;
                 displayRect = currentRect;
                 startPoint = e.Location;
                 handleType = currentRect.GetHandleType(e.Location);
                 CurrentMode = handleType != HandleType.None ? DrawMode.Resizing : DrawMode.Moving;
             }
             CurrentMode = DrawMode.None;
             container.Invalidate();
         }
     }
     private void Container_Paint(object sender, PaintEventArgs e)
     {
         foreach (var shape in ShapeDictionary.Values)
         {
             if (shape.ID == selectedIndex)
             {
                 shape.IsSelected = true;
                 shape.ShapeColor = Color.Red;
                 shape.HandleColor = Color.White;
             }
             else
             {
                 shape.IsSelected = false;
                 shape.ShapeColor = Color.Blue;
                 shape.HandleColor = Color.White;
             }
             shape.DrawShapeWithHandles(e.Graphics);
         }
         if (currentRect == null) return;
         if (CurrentMode == DrawMode.Drawing)
         {
             using (var brush = new SolidBrush(Color.FromArgb(50, 0, 0, 255)))
             {
                 e.Graphics.FillRectangle(brush, currentRect.Rectangle);
             }
             e.Graphics.DrawRectangle(Pens.Blue, currentRect.Rectangle);
         }
     }
     private void Container_MouseWheel(object sender, MouseEventArgs e)
     {
         if (e.Delta > 0) ZoomOut();
         else if (e.Delta < 0) ZoomIn();
     }
     #endregion
 }
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.
  • 111.
  • 112.
  • 113.
  • 114.
  • 115.
  • 116.
  • 117.
  • 118.
  • 119.
  • 120.
  • 121.
  • 122.
  • 123.
  • 124.
  • 125.
  • 126.
  • 127.
  • 128.
  • 129.
  • 130.
  • 131.
  • 132.
  • 133.
  • 134.
  • 135.
  • 136.
  • 137.
  • 138.
  • 139.
  • 140.
  • 141.
  • 142.
  • 143.
  • 144.
  • 145.
  • 146.
  • 147.
  • 148.
  • 149.
  • 150.
  • 151.
  • 152.
  • 153.
  • 154.
  • 155.
  • 156.
  • 157.
  • 158.
  • 159.
  • 160.
  • 161.
  • 162.
  • 163.
  • 164.
  • 165.
  • 166.
  • 167.
  • 168.
  • 169.
  • 170.
  • 171.
  • 172.
  • 173.
  • 174.
  • 175.
  • 176.
  • 177.
  • 178.
  • 179.
  • 180.
  • 181.
  • 182.
  • 183.
  • 184.
  • 185.
  • 186.
  • 187.
  • 188.
  • 189.
  • 190.
  • 191.
  • 192.
  • 193.
  • 194.
  • 195.
  • 196.
  • 197.
  • 198.
  • 199.
  • 200.
  • 201.
  • 202.
  • 203.
  • 204.
  • 205.
  • 206.
  • 207.
  • 208.
  • 209.
  • 210.
  • 211.
  • 212.
  • 213.
  • 214.
  • 215.
  • 216.
  • 217.
  • 218.
  • 219.
  • 220.
  • 221.
  • 222.
  • 223.
  • 224.
  • 225.
  • 226.
  • 227.
  • 228.
  • 229.
  • 230.
  • 231.
  • 232.
  • 233.
  • 234.
  • 235.
  • 236.
  • 237.
  • 238.
  • 239.
  • 240.
  • 241.
  • 242.
  • 243.
  • 244.
  • 245.
  • 246.
  • 247.
  • 248.
  • 249.
  • 250.
  • 251.
  • 252.
  • 253.
  • 254.
  • 255.
  • 256.
  • 257.
  • 258.
  • 259.
  • 260.
  • 261.
  • 262.
  • 263.
  • 264.
  • 265.
  • 266.
  • 267.
  • 268.
  • 269.
  • 270.
  • 271.
  • 272.
  • 273.
  • 274.
  • 275.
  • 276.
  • 277.
  • 278.
  • 279.
  • 280.
  • 281.
  • 282.
  • 283.
  • 284.
  • 285.
  • 286.
  • 287.
  • 288.
  • 289.
  • 290.
  • 291.
  • 292.
  • 293.
  • 294.
  • 295.
  • 296.
  • 297.
  • 298.
  • 299.
  • 300.
  • 301.
  • 302.
  • 303.
  • 304.
  • 305.
  • 306.
  • 307.
  • 308.
  • 309.
  • 310.
  • 311.
  • 312.
  • 313.
  • 314.
  • 315.
  • 316.
  • 317.
  • 318.
  • 319.
  • 320.
  • 321.
  • 322.
  • 323.
  • 324.
  • 325.
  • 326.
  • 327.
  • 328.
  • 329.
  • 330.
  • 331.
  • 332.
  • 333.
  • 334.
  • 335.
  • 336.
  • 337.
  • 338.
  • 339.
  • 340.
  • 341.
  • 342.
  • 343.
  • 344.
  • 345.
  • 346.
  • 347.
  • 348.
  • 349.
  • 350.
  • 351.
  • 352.
  • 353.
  • 354.
  • 355.
  • 356.
  • 357.
  • 358.
  • 359.
  • 360.
  • 361.
  • 362.
  • 363.
  • 364.
  • 365.
  • 366.
  • 367.
  • 368.
  • 369.
  • 370.
  • 371.
  • 372.

用到的枚举

/// <summary>
/// 绘制模式
/// </summary>
public enum DrawMode
{
    None,
    Drawing,
    Moving,
    Resizing,
}
/// <summary>
/// 手柄类型
/// </summary>
public enum HandleType
{
    None,
    TopLeft,
    TopRight,
    BottomLeft,
    BottomRight
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.

用户界面代码

using CustomControls;
using Shapes;
using System;
using System.Drawing;
namespace CS学习之绘制形状
{
    public partial class MainForm : WinFormBase
    {
        ShapeModule shapeModule;
        string imageFile = AppDomain.CurrentDomain.BaseDirectory + "source.png";
        public MainForm()
        {
            InitializeComponent();
            this.CenterToParent();
            shapeModule = new ShapeModule(uc_Canvas);
            uc_Canvas.Image = Image.FromFile(imageFile);
        }
        private void btn_Draw_Click(object sender, System.EventArgs e)
        {
            shapeModule.CurrentMode = DrawMode.Drawing;
        }
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.

双缓存图像控件

public class UImageControl : PictureBox
{
    public UImageControl()
    {
        this.DoubleBuffered = true; 
        SizeMode = PictureBoxSizeMode.StretchImage;
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.

用户界面

【C#】Winform窗体任意控件绘制形状图形(实现添加、删除、选中、移动、缩放功能)_控件绘制_06

用户界面

  • 该用户界面为前几期的内容创建,如想使用可翻阅前面的内容查看代码。
  • 不使用该窗体也可以使用自定义的Form窗体,只需添加按钮,添加任意控件即可,注意设置Dock属性为Fill。
  • 控件最好设置双缓冲,否则会出现界面闪烁。
  • 设计缺陷:当用户自定义控件绘制图像时,如果也创建了下面实现的事件如鼠标按下事件(MouseDown),可能会起冲突。
DoubleBuffered  = true;  //启用双缓冲
  • 1.

结语

  • 使用方法,将自定义控件创建在同一个命名空间下,点击生成无报错后,即可在工具箱中查看选择自定义控件。
  • 拖拽到当前窗体即可。如果是创建自己的类库,并引用这个类库,引用时可能得报错原因,目标框架不同。
  • 公众号:编程笔记in

最后