You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C#中通过鼠标事件调整PictureBox上多个矩形的大小?

实现PictureBox中多矩形的鼠标调整大小功能

我来帮你搞定这个多矩形调整大小的需求!基于你给出的代码片段,咱们一步步完善功能:

第一步:补充必要的状态变量

你现有的变量不足以支持调整大小的逻辑,需要新增几个变量来跟踪选中的矩形、拖动的手柄位置等:

// 新增状态变量
private int selectedRectIndex = -1; // 当前选中的矩形索引,-1表示未选中
private enum DragHandle { None, TopLeft, TopRight, BottomLeft, BottomRight, Top, Bottom, Left, Right }
private DragHandle currentDragHandle = DragHandle.None;
private Point dragStartPoint; // 拖动开始时的鼠标位置

第二步:处理MouseDown事件——识别选中的矩形和拖动手柄

当鼠标按下时,我们需要判断点击的是哪个矩形的哪个部位(边角、边框或内部),以此确定后续的操作逻辑:

private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
    // 从后往前遍历,确保最上层的矩形优先被选中
    for (int i = listRec.Count - 1; i >= 0; i--)
    {
        Rectangle rect = listRec[i];
        var handleSize = 8; // 手柄大小,可根据需求调整
        
        // 检查四个边角手柄
        if (new Rectangle(rect.Left, rect.Top, handleSize, handleSize).Contains(e.Location))
        {
            selectedRectIndex = i;
            currentDragHandle = DragHandle.TopLeft;
            dragStartPoint = e.Location;
            return;
        }
        if (new Rectangle(rect.Right - handleSize, rect.Top, handleSize, handleSize).Contains(e.Location))
        {
            selectedRectIndex = i;
            currentDragHandle = DragHandle.TopRight;
            dragStartPoint = e.Location;
            return;
        }
        if (new Rectangle(rect.Left, rect.Bottom - handleSize, handleSize, handleSize).Contains(e.Location))
        {
            selectedRectIndex = i;
            currentDragHandle = DragHandle.BottomLeft;
            dragStartPoint = e.Location;
            return;
        }
        if (new Rectangle(rect.Right - handleSize, rect.Bottom - handleSize, handleSize, handleSize).Contains(e.Location))
        {
            selectedRectIndex = i;
            currentDragHandle = DragHandle.BottomRight;
            dragStartPoint = e.Location;
            return;
        }
        // 检查四条边框
        if (e.X >= rect.Left - handleSize && e.X <= rect.Left + handleSize && e.Y >= rect.Top && e.Y <= rect.Bottom)
        {
            selectedRectIndex = i;
            currentDragHandle = DragHandle.Left;
            dragStartPoint = e.Location;
            return;
        }
        if (e.X >= rect.Right - handleSize && e.X <= rect.Right + handleSize && e.Y >= rect.Top && e.Y <= rect.Bottom)
        {
            selectedRectIndex = i;
            currentDragHandle = DragHandle.Right;
            dragStartPoint = e.Location;
            return;
        }
        if (e.Y >= rect.Top - handleSize && e.Y <= rect.Top + handleSize && e.X >= rect.Left && e.X <= rect.Right)
        {
            selectedRectIndex = i;
            currentDragHandle = DragHandle.Top;
            dragStartPoint = e.Location;
            return;
        }
        if (e.Y >= rect.Bottom - handleSize && e.Y <= rect.Bottom + handleSize && e.X >= rect.Left && e.X <= rect.Right)
        {
            selectedRectIndex = i;
            currentDragHandle = DragHandle.Bottom;
            dragStartPoint = e.Location;
            return;
        }
        // 可选:点击矩形内部可以拖动整个矩形
        if (rect.Contains(e.Location))
        {
            selectedRectIndex = i;
            currentDragHandle = DragHandle.None;
            dragStartPoint = e.Location;
            return;
        }
    }
    // 如果没选中任何矩形,回到你原来的绘制新矩形逻辑
    startPos = e.Location;
    drawing = true;
}

第三步:处理MouseMove事件——调整矩形大小/位置

根据选中的手柄类型,实时更新矩形的尺寸或位置:

private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
    if (drawing)
    {
        // 保留你原来的绘制新矩形逻辑
        currentPos = e.Location;
        pictureBox1.Invalidate();
    }
    else if (selectedRectIndex != -1 && currentDragHandle != DragHandle.None)
    {
        Rectangle rect = listRec[selectedRectIndex];
        int deltaX = e.X - dragStartPoint.X;
        int deltaY = e.Y - dragStartPoint.Y;

        switch (currentDragHandle)
        {
            case DragHandle.TopLeft:
                rect.X += deltaX;
                rect.Y += deltaY;
                rect.Width -= deltaX;
                rect.Height -= deltaY;
                break;
            case DragHandle.TopRight:
                rect.Y += deltaY;
                rect.Width += deltaX;
                rect.Height -= deltaY;
                break;
            case DragHandle.BottomLeft:
                rect.X += deltaX;
                rect.Width -= deltaX;
                rect.Height += deltaY;
                break;
            case DragHandle.BottomRight:
                rect.Width += deltaX;
                rect.Height += deltaY;
                break;
            case DragHandle.Left:
                rect.X += deltaX;
                rect.Width -= deltaX;
                break;
            case DragHandle.Right:
                rect.Width += deltaX;
                break;
            case DragHandle.Top:
                rect.Y += deltaY;
                rect.Height -= deltaY;
                break;
            case DragHandle.Bottom:
                rect.Height += deltaY;
                break;
        }

        // 防止矩形缩小到看不见,设置最小宽高
        if (rect.Width < 5) rect.Width = 5;
        if (rect.Height < 5) rect.Height = 5;
        // 更新列表中的矩形
        listRec[selectedRectIndex] = rect;
        // 更新拖动起始点,保证拖动平滑
        dragStartPoint = e.Location;
        // 重绘控件
        pictureBox1.Invalidate();
    }
    // 可选:根据鼠标位置切换光标样式,提升用户体验
    else
    {
        Cursor = Cursors.Default;
        foreach (var rect in listRec)
        {
            var handleSize = 8;
            if (new Rectangle(rect.Left, rect.Top, handleSize, handleSize).Contains(e.Location) ||
                new Rectangle(rect.Right - handleSize, rect.Bottom - handleSize, handleSize, handleSize).Contains(e.Location))
            {
                Cursor = Cursors.SizeNWSE;
                return;
            }
            if (new Rectangle(rect.Right - handleSize, rect.Top, handleSize, handleSize).Contains(e.Location) ||
                new Rectangle(rect.Left, rect.Bottom - handleSize, handleSize, handleSize).Contains(e.Location))
            {
                Cursor = Cursors.SizeNESW;
                return;
            }
            if ((e.X >= rect.Left - handleSize && e.X <= rect.Left + handleSize && e.Y >= rect.Top && e.Y <= rect.Bottom) ||
                (e.X >= rect.Right - handleSize && e.X <= rect.Right + handleSize && e.Y >= rect.Top && e.Y <= rect.Bottom))
            {
                Cursor = Cursors.SizeWE;
                return;
            }
            if ((e.Y >= rect.Top - handleSize && e.Y <= rect.Top + handleSize && e.X >= rect.Left && e.X <= rect.Right) ||
                (e.Y >= rect.Bottom - handleSize && e.Y <= rect.Bottom + handleSize && e.X >= rect.Left && e.X <= rect.Right))
            {
                Cursor = Cursors.SizeNS;
                return;
            }
            if (rect.Contains(e.Location))
            {
                Cursor = Cursors.SizeAll;
                return;
            }
        }
    }
}

第四步:处理MouseUp事件——重置状态

鼠标抬起后,清空选中状态,回到正常模式:

private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
    if (drawing)
    {
        // 保留你原来的添加新矩形到列表的逻辑
        rect = getRectangle();
        listRec.Add(rect);
        drawing = false;
        pictureBox1.Invalidate();
    }
    else
    {
        selectedRectIndex = -1;
        currentDragHandle = DragHandle.None;
        Cursor = Cursors.Default;
    }
}

第五步:完善Paint事件——绘制矩形和选中手柄

在Paint事件里,除了绘制所有矩形,还要给选中的矩形加上可操作的手柄:

private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
    g = e.Graphics;
    // 绘制所有已保存的矩形
    foreach (var rect in listRec)
    {
        g.DrawRectangle(Pens.Blue, rect);
    }
    // 绘制正在创建的临时矩形
    if (drawing)
    {
        rect = getRectangle();
        g.DrawRectangle(Pens.Red, rect);
    }
    // 绘制选中矩形的操作手柄
    if (selectedRectIndex != -1)
    {
        Rectangle selectedRect = listRec[selectedRectIndex];
        var handleSize = 8;
        // 四个白色填充+黑色边框的手柄
        g.FillRectangle(Brushes.White, new Rectangle(selectedRect.Left, selectedRect.Top, handleSize, handleSize));
        g.DrawRectangle(Pens.Black, new Rectangle(selectedRect.Left, selectedRect.Top, handleSize, handleSize));
        
        g.FillRectangle(Brushes.White, new Rectangle(selectedRect.Right - handleSize, selectedRect.Top, handleSize, handleSize));
        g.DrawRectangle(Pens.Black, new Rectangle(selectedRect.Right - handleSize, selectedRect.Top, handleSize, handleSize));
        
        g.FillRectangle(Brushes.White, new Rectangle(selectedRect.Left, selectedRect.Bottom - handleSize, handleSize, handleSize));
        g.DrawRectangle(Pens.Black, new Rectangle(selectedRect.Left, selectedRect.Bottom - handleSize, handleSize, handleSize));
        
        g.FillRectangle(Brushes.White, new Rectangle(selectedRect.Right - handleSize, selectedRect.Bottom - handleSize, handleSize, handleSize));
        g.DrawRectangle(Pens.Black, new Rectangle(selectedRect.Right - handleSize, selectedRect.Bottom - handleSize, handleSize, handleSize));
    }
}

额外注意事项

  1. 确保你的getRectangle()方法是完整的,比如:
private Rectangle getRectangle()
{
    return new Rectangle(
        Math.Min(startPos.X, currentPos.X),
        Math.Min(startPos.Y, currentPos.Y),
        Math.Abs(startPos.X - currentPos.X),
        Math.Abs(startPos.Y - currentPos.Y)
    );
}
  1. 要把这些事件绑定到你的PictureBox控件上,要么在设计器里双击对应事件,要么在窗体构造函数里手动绑定:
public YourForm()
{
    InitializeComponent();
    pictureBox1.MouseDown += pictureBox1_MouseDown;
    pictureBox1.MouseMove += pictureBox1_MouseMove;
    pictureBox1.MouseUp += pictureBox1_MouseUp;
    pictureBox1.Paint += pictureBox1_Paint;
}
  1. 可以调整handleSize变量的值,让手柄更大或更小,适配你的操作习惯。

内容的提问来源于stack exchange,提问作者Fenie Mendawala

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 08:37:28