且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

使用可拖动和可调整大小的选择窗口创建自定义图片框

更新时间:2023-02-05 22:07:08

您有不同的选择:

  • 您可以在图片框上绘制可调整大小的框架
  • 您可以创建可调整大小的控件并将其添加到图片框

在此答案中,我采用了第二个选项,以便能够使用控件的内置大小调整功能.这是一个截屏,显示了它的实际效果:

In this answer, I've taken the second option to be able to use built-in sizing features of the controls. Here is a screen capture which shows how it looks like in action:

示例-创建框架控件

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

As an example, I'll create a resizable control and will add it to the picture box.

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
        }
    }
}

然后将控件添加到图片框中:

Then add the control to the picture box:

var s = 100;
var c = new FrameControl();
c.Size = new Size(s, s);
c.Location = new Point((pictureBox1.Width - s) / 2, (pictureBox1.Height - s) / 2);
pictureBox1.Controls.Add(c);

要添加奇特的效果,以半透明的颜色填充框架外部:

To add a fancy effect of filling outside of the frame with semi-transparent color:

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.这样您就可以找到它的位置和大小.

As you can see in the paint event, you can find the FrameControl using pictureBox1.Controls[0]. So you can find its location and size.

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

You can encapsulate all the logic of the picture box in a derived picture box.

注意:无闪烁渲染

如果在移动框架时遇到闪烁,请在表单中使用以下代码:

If you experience flickering when moving the frame, use the following code in your form:

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