[C#.NET 4.0]如何防止调整大小(C#)时无边界Windows窗体闪烁?
我学习C#,我试图建立有FormBorderStyle = FormBorderStyle.None
和可移动/使用Windows API调整Windows窗体中使用C#。举个例子,我使用圆角或用于Google Chrome和Norton 360的自定义(可移动/可调整大小)边框设计作为我的表单的基础。
我已经取得了很大的进步,到目前为止,并得到的一切工作,除了当我调整的形式,有黑/白一起闪烁当调整表格右侧和底部边框的长度快速。
我尝试添加在构造函数中this.DoubleBuffer = true
,并且还试图this.SetStyles(ControlStyles.AllPaintInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw | ControlStyles.UserPaint, true);
。
因为我是图形方面的东西,我喜欢控制窗体的完整设计,所以我可以看到这是永远困扰我的东西... 所以如果有人可以帮助我解决这个问题,所以闪烁不再发生,这将对我的学习过程非常有用。
我还要提到的是,我使用的是Windows XP,所以我不知道this post会帮助我,因为它似乎集中在Vista/7的(与DWM)......不是我”米先进到足以理解这篇文章中的所有内容。
与该API工作的代码的两个部分的下方。我有一个WM_NCHITTEST的Windows API公开枚举...你可以看到值in this link。
的OnPaint重写方法:
protected override void OnPaint(PaintEventArgs e)
{
System.IntPtr ptrBorder = CreateRoundRectRgn(0, 0,
this.ClientSize.Width, this.ClientSize.Height, 15, 15);
SetWindowRgn(this.Handle, ptrBorder, true);
Rectangle rc = new Rectangle(this.ClientSize.Width - cGrip,
this.ClientSize.Height - cGrip, cGrip, cGrip);
ControlPaint.DrawSizeGrip(e.Graphics, this.BackColor, rc);
rc = new Rectangle(0, 0, this.ClientSize.Width, 32);
e.Graphics.FillRectangle(Brushes.SlateGray, rc);
}
WNDPROC覆盖方法:
protected override void WndProc(ref Message m)
{
if (m.Msg == (int)HitTest.WM_NCHITTEST)
{
// Trap WM_NCHITTEST
Point pos = new Point(m.LParam.ToInt32() & 0xffff, m.LParam.ToInt32() >> 16);
pos = this.PointToClient(pos);
if (pos.Y < cCaption)
{
m.Result = (IntPtr)HitTest.HTCAPTION;
return;
}
if (pos.X <= cGrip && pos.Y >= this.ClientSize.Height - cGrip)
{
m.Result = (IntPtr)HitTest.HTBOTTOMLEFT;
return;
}
if (pos.X >= this.ClientSize.Width - cGrip &&
pos.Y >= this.ClientSize.Height - cGrip)
{
m.Result = (IntPtr)HitTest.HTBOTTOMRIGHT;
return;
}
if (pos.X >= this.ClientSize.Width - cBorder)
{
m.Result = (IntPtr)HitTest.HTRIGHT;
return;
}
if (pos.Y >= this.ClientSize.Height - cBorder)
{
m.Result = (IntPtr)HitTest.HTBOTTOM;
return;
}
if (pos.X <= cBorder)
{
m.Result = (IntPtr)HitTest.HTLEFT;
return;
}
}
base.WndProc(ref m);
}
下面是完整的代码:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace PracticeForm
{
public partial class Form2 : Form
{
[DllImport("user32.dll")]
private static extern int SetWindowRgn(IntPtr hWnd, IntPtr hRgn, bool bRedraw);
[DllImport("gdi32.dll")]
private static extern IntPtr CreateRoundRectRgn(int x1, int y1, int x2, int y2, int cx, int cy);
[DllImport("gdi32.dll", EntryPoint = "DeleteObject")]
private static extern bool DeleteObject(System.IntPtr hObject);
private const int cGrip = 20;
private const int cCaption = 35;
private const int cBorder = 7;
private Point mouseOffset;
public Form2()
{
InitializeComponent();
this.FormBorderStyle = FormBorderStyle.None;
this.MaximumSize = new Size(670, 440);
this.DoubleBuffered = true;
this.SetStyle(ControlStyles.ResizeRedraw |
ControlStyles.OptimizedDoubleBuffer |
ControlStyles.AllPaintingInWmPaint |
ControlStyles.UserPaint, true);
}
protected override void OnPaint(PaintEventArgs e)
{
System.IntPtr ptrBorder = CreateRoundRectRgn(0, 0,
this.ClientSize.Width, this.ClientSize.Height, 15, 15);
SetWindowRgn(this.Handle, ptrBorder, true);
Rectangle rc = new Rectangle(this.ClientSize.Width - cGrip,
this.ClientSize.Height - cGrip, cGrip, cGrip);
ControlPaint.DrawSizeGrip(e.Graphics, this.BackColor, rc);
}
protected override void WndProc(ref Message m)
{
if (m.Msg == (int)HitTest.WM_NCHITTEST)
{
// Trap WM_NCHITTEST
Point pos = new Point(m.LParam.ToInt32() & 0xffff, m.LParam.ToInt32() >> 16);
pos = this.PointToClient(pos);
if (pos.Y < cCaption)
{
m.Result = (IntPtr)HitTest.HTCAPTION;
return;
}
if (pos.X <= cGrip && pos.Y >= this.ClientSize.Height - cGrip)
{
m.Result = (IntPtr)HitTest.HTBOTTOMLEFT;
return;
}
if (pos.X >= this.ClientSize.Width - cGrip &&
pos.Y >= this.ClientSize.Height - cGrip)
{
m.Result = (IntPtr)HitTest.HTBOTTOMRIGHT;
return;
}
if (pos.X >= this.ClientSize.Width - cBorder)
{
m.Result = (IntPtr)HitTest.HTRIGHT;
return;
}
if (pos.Y >= this.ClientSize.Height - cBorder)
{
m.Result = (IntPtr)HitTest.HTBOTTOM;
return;
}
if (pos.X <= cBorder)
{
m.Result = (IntPtr)HitTest.HTLEFT;
return;
}
}
base.WndProc(ref m);
}
private void button1_Click(object sender, EventArgs e)
{
this.Close();
}
private void button2_MouseClick(object sender, MouseEventArgs e)
{
this.WindowState = FormWindowState.Minimized;
}
private void panel1_MouseDown(object sender, MouseEventArgs e)
{
mouseOffset = new Point(-e.X, -e.Y);
}
private void panel1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
Point p = Control.MousePosition;
p.Offset(mouseOffset.X, mouseOffset.Y);
Location = p;
}
}
private void label1_MouseDown(object sender, MouseEventArgs e)
{
mouseOffset = new Point(-e.X, -e.Y);
}
private void label1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
Point p = Control.MousePosition;
p.Offset(mouseOffset.X, mouseOffset.Y);
Location = p;
}
}
}
}
感谢您的帮助。
这可能会稍微好一些,但它仍然闪烁非常糟糕。另外,出于某种原因,您的代码似乎已经覆盖了我的表单开始位置(CenterScreen)。 – user2063351 2013-05-09 18:00:25
您是否有图像作为表单的背景?或者可能是Paint()事件中的一些更复杂的绘画? – 2013-05-09 18:25:39
不,表单中的所有内容都是在代码中创建的(除了枚举类以外,我的所有代码都列在了我的文章中)。这只是一个矩形区域,覆盖无边界形式来创建圆角(据我了解)。当然,还有自定义SizeGrip的附加矩形。我认为创建圆角的矩形是导致问题的原因,因为当我完全删除该CreateRoundRectRgn代码时,它看起来不会闪烁(或闪烁几乎不如坏)。但圆角对我来说是一个重要的视觉实现。 – user2063351 2013-05-09 19:03:57