C# 使用可拖动和可调整大小的选择窗口创建自定义Picturebox

C# 使用可拖动和可调整大小的选择窗口创建自定义Picturebox,c#,.net,winforms,gdi+,picturebox,C#,.net,Winforms,Gdi+,Picturebox,我使用以下代码在picturebox上绘制一个选择矩形,并允许用户选择并将其拖动到所需位置 我想要实现的是允许用户通过实现调整矩形大小的选项来调整矩形大小。目前,我已成功实现以下目标 如何解决这个问题 您有不同的选择: 您可以在图片框上绘制可调整大小的边框 您可以创建一个可调整大小的控件并将其添加到图片框中 在这个答案中,我选择了第二个选项,以便能够使用控件的内置大小调整功能。下面是一个屏幕截图,显示了它在运行中的样子: 示例-创建帧控件 例如,我将创建一个可调整大小的控件,并将其添加到

我使用以下代码在picturebox上绘制一个选择矩形,并允许用户选择并将其拖动到所需位置

我想要实现的是允许用户通过实现调整矩形大小的选项来调整矩形大小。目前,我已成功实现以下目标

如何解决这个问题


您有不同的选择:

  • 您可以在图片框上绘制可调整大小的边框
  • 您可以创建一个可调整大小的控件并将其添加到图片框中
在这个答案中,我选择了第二个选项,以便能够使用控件的内置大小调整功能。下面是一个屏幕截图,显示了它在运行中的样子:

示例-创建帧控件

例如,我将创建一个可调整大小的控件,并将其添加到图片框中

using System;
using System.Drawing;
using System.Windows.Forms;
public class FrameControl : Control
{
    public FrameControl()
    {
        SetStyle(ControlStyles.SupportsTransparentBackColor, true);
        DoubleBuffered = true;
        ResizeRedraw = true;
        BackColor = Color.Transparent;
    }
    protected override void OnPaint(PaintEventArgs e)
    {
        base.OnPaint(e);
        using (var p = new Pen(Color.Black, 4))
        {
            p.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;
            e.Graphics.DrawRectangle(p, 0, 0, Width - 1, Height - 1);
        }
    }
    const int WM_NCHITTEST = 0x84;
    const int WM_SETCURSOR = 0x20;
    const int WM_NCLBUTTONDBLCLK = 0xA3;
    protected override void WndProc(ref Message m)
    {
        int borderWidth = 10;
        if (m.Msg == WM_SETCURSOR)  /*Setting cursor to SizeAll*/
        {
            if ((m.LParam.ToInt32() & 0xffff) == 0x2 /*Move*/)
            {
                Cursor.Current = Cursors.SizeAll;
                m.Result = (IntPtr)1;
                return;
            }
        }
        if ((m.Msg == WM_NCLBUTTONDBLCLK)) /*Disable Mazimiz on Double click*/
        {
            m.Result = (IntPtr)1;
            return;
        }
        base.WndProc(ref m);
        if (m.Msg == WM_NCHITTEST)
        {
            var pos = PointToClient(new Point(m.LParam.ToInt32() & 0xffff,
                m.LParam.ToInt32() >> 16));
            if (pos.X <= ClientRectangle.Left + borderWidth &&
                pos.Y <= ClientRectangle.Top + borderWidth)
                m.Result = new IntPtr(13); //TOPLEFT
            else if (pos.X >= ClientRectangle.Right - borderWidth &&
                pos.Y <= ClientRectangle.Top + borderWidth)
                m.Result = new IntPtr(14); //TOPRIGHT
            else if (pos.X <= ClientRectangle.Left + borderWidth &&
                pos.Y >= ClientRectangle.Bottom - borderWidth)
                m.Result = new IntPtr(16); //BOTTOMLEFT
            else if (pos.X >= ClientRectangle.Right - borderWidth &&
                pos.Y >= ClientRectangle.Bottom - borderWidth)
                m.Result = new IntPtr(17); //BOTTOMRIGHT
            else if (pos.X <= ClientRectangle.Left + borderWidth)
                m.Result = new IntPtr(10); //LEFT
            else if (pos.Y <= ClientRectangle.Top + borderWidth)
                m.Result = new IntPtr(12); //TOP
            else if (pos.X >= ClientRectangle.Right - borderWidth)
                m.Result = new IntPtr(11); //RIGHT
            else if (pos.Y >= ClientRectangle.Bottom - borderWidth)
                m.Result = new IntPtr(15); //Bottom
            else
                m.Result = new IntPtr(2); //Move
        }
    }
}
要添加用半透明颜色填充框架外部的奇特效果,请执行以下操作:

private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
    e.Graphics.ExcludeClip(pictureBox1.Controls[0].Bounds);
    using (var b = new SolidBrush(Color.FromArgb(100, Color.Black)))
        e.Graphics.FillRectangle(b, pictureBox1.ClientRectangle);
}
正如您在绘制事件中所看到的,您可以使用
pictureBox1.Controls[0]
找到
FrameControl
。所以你可以找到它的位置和大小

您可以将图片框的所有逻辑封装在派生图片框中

注意:无闪烁渲染

如果在移动帧时出现闪烁,请在表单中使用以下代码:

protected override CreateParams CreateParams
{
    get
    {
        CreateParams cp = base.CreateParams;
        cp.ExStyle |= 0x02000000;   // WS_EX_COMPOSITED       
        return cp;
    }
}

a) 忘了修剪吧。您需要的是一个选择工具。以后如何处理选择并不重要。b) mousemove活动在哪里?没有它,就无法显示中间步骤。。c) 对于一个rubberband示例或@TaW,我认为您应该将您的链接作为一个示例(是的,我喜欢这样:)谢谢您的好话。是的,用一个实际的持久化控件代替矩形也是一个有趣的选择。@TaW我还没有实现这些事件。@TaW我正在寻找每4个角的箭头或大小调整,或者类似于我们在photoshop中使用选择工具的方法。初始选择矩形将是预先确定的,用户只能调整其大小。非常感谢。这正是我想要的。您的代码中似乎有一个小错误,图像右上角的大小调整选项不正确。欢迎您。确保使用了最新的代码。我也会检查的。还有一件事。我需要确定所选区域的位置和大小,我如何实现这一点。修复了调整。另外,请阅读最后一段关于框架控件的大小和位置的内容。我已经接受了答案。当用户尝试移动控件时,如何将光标更改为移动光标?我在picturebox的mousemove事件中尝试了以下操作`if(pictureBox1.Controls[0].Bounds.Contains(e.Location)){this.Cursor=Cursors.SizeAll;}`但这似乎不起作用。
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
    e.Graphics.ExcludeClip(pictureBox1.Controls[0].Bounds);
    using (var b = new SolidBrush(Color.FromArgb(100, Color.Black)))
        e.Graphics.FillRectangle(b, pictureBox1.ClientRectangle);
}
protected override CreateParams CreateParams
{
    get
    {
        CreateParams cp = base.CreateParams;
        cp.ExStyle |= 0x02000000;   // WS_EX_COMPOSITED       
        return cp;
    }
}