调整控件大小时出现奇怪的效果
Strange effect when resizing Control
我创建了两个自定义控件。一个长方形和一个椭圆。我可以通过用鼠标拖动来移动它们,但我也想调整它们的大小。调整矩形大小效果很好,但调整椭圆大小会产生奇怪的效果。当我在调整大小后单击椭圆并再次拖动它时,椭圆看起来又正常了。这里的 link 和 gif 显示了我所说的 'strange' 效果 http://gyazo.com/319adb7347ed20fe28b6b93ced8744eb 的意思。这个效果怎么修?此外,椭圆的角部有一些白色 space,因为它是以矩形绘制的,也许也有办法解决这个问题?
Control.cs
class Ellipse : Control
{
Point mDown { get; set; }
public Ellipse()
{
MouseDown += shape_MouseDown;
MouseMove += shape_MouseMove;
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
// Draw a black ellipse in the rectangle represented by the control.
e.Graphics.FillEllipse(Brushes.Black, 0, 0, Width, Height);
//Set transparent background
SetStyle(ControlStyles.SupportsTransparentBackColor | ControlStyles.DoubleBuffer, true);
this.BackColor = Color.Transparent;
}
public void shape_MouseDown(object sender, MouseEventArgs e)
{
mDown = e.Location;
}
public void shape_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
Location = new Point(e.X + Left - mDown.X, e.Y + Top - mDown.Y);
}
}
/* Allow resizing at the bottom right corner */
protected override void WndProc(ref Message m)
{
const int wmNcHitTest = 0x84;
const int htBottomLeft = 16;
const int htBottomRight = 17;
if (m.Msg == wmNcHitTest)
{
int x = (int)(m.LParam.ToInt64() & 0xFFFF);
int y = (int)((m.LParam.ToInt64() & 0xFFFF0000) >> 16);
Point pt = PointToClient(new Point(x, y));
Size clientSize = ClientSize;
if (pt.X >= clientSize.Width - 16 && pt.Y >= clientSize.Height - 16 && clientSize.Height >= 16)
{
m.Result = (IntPtr)(IsMirrored ? htBottomLeft : htBottomRight);
return;
}
}
base.WndProc(ref m);
}
}
}
Form1.cs
通过这种方式,我创建了 Ellipse
的这段代码来自 panel_MouseUp (object sender, MouseEventArgs e)
方法。
case Item.Ellipse:
var el = new Ellipse();
panel.Controls.Add(el);
el.Location = new Point(x, y);
el.Width = (xe - x);
el.Height = (ye - y);
break;
您需要告诉控件在调整大小时完全重新绘制自身。将其 ResizeRedraw 属性 设置为 true。您还需要小心您在 Paint 事件处理程序中所做的事情,它不应该有全局状态副作用。正如所写,当我尝试时,您的控件立即使设计器崩溃。
从 OnPaint 中删除最后两行并使您的构造函数如下所示:
public Ellipse() {
MouseDown += shape_MouseDown;
MouseMove += shape_MouseMove;
SetStyle(ControlStyles.SupportsTransparentBackColor, true);
this.BackColor = Color.Transparent;
this.DoubleBuffered = true;
this.ResizeRedraw = true;
}
通过覆盖 OnMouseDown/Move() 而不是使用事件来进一步改进这一点。并查看 ControlPaint.DrawGrabHandle() 以使调整大小更直观。
我创建了两个自定义控件。一个长方形和一个椭圆。我可以通过用鼠标拖动来移动它们,但我也想调整它们的大小。调整矩形大小效果很好,但调整椭圆大小会产生奇怪的效果。当我在调整大小后单击椭圆并再次拖动它时,椭圆看起来又正常了。这里的 link 和 gif 显示了我所说的 'strange' 效果 http://gyazo.com/319adb7347ed20fe28b6b93ced8744eb 的意思。这个效果怎么修?此外,椭圆的角部有一些白色 space,因为它是以矩形绘制的,也许也有办法解决这个问题?
Control.cs
class Ellipse : Control
{
Point mDown { get; set; }
public Ellipse()
{
MouseDown += shape_MouseDown;
MouseMove += shape_MouseMove;
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
// Draw a black ellipse in the rectangle represented by the control.
e.Graphics.FillEllipse(Brushes.Black, 0, 0, Width, Height);
//Set transparent background
SetStyle(ControlStyles.SupportsTransparentBackColor | ControlStyles.DoubleBuffer, true);
this.BackColor = Color.Transparent;
}
public void shape_MouseDown(object sender, MouseEventArgs e)
{
mDown = e.Location;
}
public void shape_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
Location = new Point(e.X + Left - mDown.X, e.Y + Top - mDown.Y);
}
}
/* Allow resizing at the bottom right corner */
protected override void WndProc(ref Message m)
{
const int wmNcHitTest = 0x84;
const int htBottomLeft = 16;
const int htBottomRight = 17;
if (m.Msg == wmNcHitTest)
{
int x = (int)(m.LParam.ToInt64() & 0xFFFF);
int y = (int)((m.LParam.ToInt64() & 0xFFFF0000) >> 16);
Point pt = PointToClient(new Point(x, y));
Size clientSize = ClientSize;
if (pt.X >= clientSize.Width - 16 && pt.Y >= clientSize.Height - 16 && clientSize.Height >= 16)
{
m.Result = (IntPtr)(IsMirrored ? htBottomLeft : htBottomRight);
return;
}
}
base.WndProc(ref m);
}
}
}
Form1.cs
通过这种方式,我创建了 Ellipse
的这段代码来自 panel_MouseUp (object sender, MouseEventArgs e)
方法。
case Item.Ellipse:
var el = new Ellipse();
panel.Controls.Add(el);
el.Location = new Point(x, y);
el.Width = (xe - x);
el.Height = (ye - y);
break;
您需要告诉控件在调整大小时完全重新绘制自身。将其 ResizeRedraw 属性 设置为 true。您还需要小心您在 Paint 事件处理程序中所做的事情,它不应该有全局状态副作用。正如所写,当我尝试时,您的控件立即使设计器崩溃。
从 OnPaint 中删除最后两行并使您的构造函数如下所示:
public Ellipse() {
MouseDown += shape_MouseDown;
MouseMove += shape_MouseMove;
SetStyle(ControlStyles.SupportsTransparentBackColor, true);
this.BackColor = Color.Transparent;
this.DoubleBuffered = true;
this.ResizeRedraw = true;
}
通过覆盖 OnMouseDown/Move() 而不是使用事件来进一步改进这一点。并查看 ControlPaint.DrawGrabHandle() 以使调整大小更直观。