使用可拖动和可调整大小的选择创建自定义图片框 Window
Creating Custom Picturebox with Draggable and Resizable Selection Window
我正在使用以下代码在图片框上绘制一个 selection 矩形,并允许用户 select 并将其拖动到所需位置。
我打算实现的是允许用户通过实现调整矩形大小的选项来调整矩形大小。目前我已经设法实现了以下目标。
如何解决这个问题?
public class DraggablePictureBox : PictureBox
{
Boolean hit1 = false, hit2 = false;
public Boolean notagimg = true;
public Boolean editedflag = false;
public Boolean notext = false;
public Boolean tdrawflag = false, tdrawflag2 = false;
Bitmap l;
public Form1 LaunchOrigin2 { get; set; }
public Point point = new Point(0, 0);
public Point point2 = new Point(0, 0);
public int sizemode = 1;
public DraggablePictureBox()
{
this.Invalidate();
}
protected override void OnMouseMove(MouseEventArgs e)
{
this.Cursor = Cursors.Arrow;
if (e.Button == MouseButtons.Left)
{
point = e.Location;
base.OnMouseDown(e);
this.Invalidate();
}
}
protected override void OnMouseDown(MouseEventArgs e)
{
PointF x = new PointF(e.X, e.Y);
Pen p = new Pen(Brushes.Red, 2f);
RectangleF rect2 = new RectangleF(1, 1, 1, 1);
RectangleF rect = new RectangleF(1, 1, 1, 1);
if (e.Button == MouseButtons.Left)
{
this.Cursor = Cursors.Hand;
//Creating Rectangles to check to find the selected object
if (notext == false)
{
rect = new RectangleF(point, new Size(400,400));
}
if (rect.Contains(x) && notext == false)
{
hit1 = true;
}
if (hit1 == true )
{
this.Invalidate();
}
this.Invalidate();
}
}
protected override void OnMouseUp(MouseEventArgs e)
{
base.OnMouseUp(e);
tdrawflag = false;
}
if (e.Button == MouseButtons.Left)
{
point = e.Location;
base.OnMouseDown(e);
this.Invalidate();
}
}
protected override void OnPaint(PaintEventArgs pe)
{
base.OnPaint(pe);
Pen p = new Pen(Brushes.Red, 5);
p.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;
Pen p2 = new Pen(Brushes.LightYellow, 5);
p2.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;
if (!hit1)
{
pe.Graphics.DrawRectangle(p, new Rectangle(point, new Size(400, 400)));
}
else
{
pe.Graphics.DrawRectangle(p2, new Rectangle(point, new Size(400, 400)));
hit1 = false;
}
}
}
您有不同的选择:
- 您可以在图片框上绘制可调整大小的边框
- 您可以创建一个可调整大小的控件并将其添加到图片框
在这个回答中,我选择了第二个选项,以便能够使用控件的内置大小调整功能。这是一个屏幕截图,显示了它的实际效果:
示例 - 创建框架控件
例如,我将创建一个可调整大小的控件并将其添加到图片框中。
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
}
}
}
然后给图片框添加控件:
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);
添加用半透明颜色填充框架外部的奇特效果:
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;
}
}
我正在使用以下代码在图片框上绘制一个 selection 矩形,并允许用户 select 并将其拖动到所需位置。
我打算实现的是允许用户通过实现调整矩形大小的选项来调整矩形大小。目前我已经设法实现了以下目标。
如何解决这个问题?
public class DraggablePictureBox : PictureBox
{
Boolean hit1 = false, hit2 = false;
public Boolean notagimg = true;
public Boolean editedflag = false;
public Boolean notext = false;
public Boolean tdrawflag = false, tdrawflag2 = false;
Bitmap l;
public Form1 LaunchOrigin2 { get; set; }
public Point point = new Point(0, 0);
public Point point2 = new Point(0, 0);
public int sizemode = 1;
public DraggablePictureBox()
{
this.Invalidate();
}
protected override void OnMouseMove(MouseEventArgs e)
{
this.Cursor = Cursors.Arrow;
if (e.Button == MouseButtons.Left)
{
point = e.Location;
base.OnMouseDown(e);
this.Invalidate();
}
}
protected override void OnMouseDown(MouseEventArgs e)
{
PointF x = new PointF(e.X, e.Y);
Pen p = new Pen(Brushes.Red, 2f);
RectangleF rect2 = new RectangleF(1, 1, 1, 1);
RectangleF rect = new RectangleF(1, 1, 1, 1);
if (e.Button == MouseButtons.Left)
{
this.Cursor = Cursors.Hand;
//Creating Rectangles to check to find the selected object
if (notext == false)
{
rect = new RectangleF(point, new Size(400,400));
}
if (rect.Contains(x) && notext == false)
{
hit1 = true;
}
if (hit1 == true )
{
this.Invalidate();
}
this.Invalidate();
}
}
protected override void OnMouseUp(MouseEventArgs e)
{
base.OnMouseUp(e);
tdrawflag = false;
}
if (e.Button == MouseButtons.Left)
{
point = e.Location;
base.OnMouseDown(e);
this.Invalidate();
}
}
protected override void OnPaint(PaintEventArgs pe)
{
base.OnPaint(pe);
Pen p = new Pen(Brushes.Red, 5);
p.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;
Pen p2 = new Pen(Brushes.LightYellow, 5);
p2.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;
if (!hit1)
{
pe.Graphics.DrawRectangle(p, new Rectangle(point, new Size(400, 400)));
}
else
{
pe.Graphics.DrawRectangle(p2, new Rectangle(point, new Size(400, 400)));
hit1 = false;
}
}
}
您有不同的选择:
- 您可以在图片框上绘制可调整大小的边框
- 您可以创建一个可调整大小的控件并将其添加到图片框
在这个回答中,我选择了第二个选项,以便能够使用控件的内置大小调整功能。这是一个屏幕截图,显示了它的实际效果:
示例 - 创建框架控件
例如,我将创建一个可调整大小的控件并将其添加到图片框中。
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
}
}
}
然后给图片框添加控件:
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);
添加用半透明颜色填充框架外部的奇特效果:
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;
}
}