[C#.NET 4.0]
我正在学习C#,我正在尝试使用具有FormBorderStyle = FormBorderStyle.None
的C#构建Windows窗体,并且可以使用Windows API移动/调整大小。例如,我使用谷歌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的代码的两个部分。我有一个针对Windows API的WM_NCHITTEST的公共枚举...您可以看到值 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;
}
}
}
}
感谢您的帮助。
答案 0 :(得分:1)
闪烁发生是因为你的显示器区域正在快速改变颜色,而这反过来又是因为你正在透支 - 在同一个像素上绘制不止一个东西。
这是因为:
要解决这些问题,您需要组合使用(越多越好)
答案 1 :(得分:1)
虽然这是一个相当古老的线程,并且OP可能已经找到了解决他的问题的方法并继续前进,但是我想添加一些额外的点,以防它们证明对正在开发的.NET开发人员有益。类似的问题。
首先,我试图在Windows XP上尝试解决此问题。我去过那里,在那里度过了几个小时,结果学到了所有的艰苦教训。不幸的是,由于Windows XP缺乏我们大多数人已经习以为常的DWM,因此没有简单的解决方案。
正确设置ControlStyles绝对至关重要 - 我还要包括:
SetStyle(ControlStyles.Opaque, True)
对要绘制的控件进行双缓冲非常重要,因为闪烁主要是由于在显示器垂直回扫中间重新绘制的控件造成的。仅仅因为你调用了Invalidate(),它并不一定意味着你需要重新绘制控件 - 你受Windows的支配,操作系统会在它准备就绪时执行。您可以通过利用DirecDraw 7中的WaitForVerticalBlank等功能(在Windows XP上为该API提供大量支持)以及使用GetVerticalBlankStatus和GetScanLine来相应地计算渲染和演示时间,在Windows XP上解决这个问题(就像我一样)。
答案 2 :(得分:0)
仅在Form实际更改 SIZE 时设置Region,而不是每次都在Paint()事件中设置:
protected override void OnSizeChanged(EventArgs e)
{
base.OnSizeChanged(e);
System.IntPtr ptrBorder = CreateRoundRectRgn(0, 0,
this.ClientSize.Width, this.ClientSize.Height, 15, 15);
SetWindowRgn(this.Handle, ptrBorder, true);
}
protected override void OnPaint(PaintEventArgs e)
{
Rectangle rc = new Rectangle(this.ClientSize.Width - cGrip,
this.ClientSize.Height - cGrip, cGrip, cGrip);
ControlPaint.DrawSizeGrip(e.Graphics, this.BackColor, rc);
}
答案 3 :(得分:0)
尝试一下:
how to stop flickering C# winforms
我在无边界表单上使用面板作为标题栏,并且在标题栏面板上出现闪烁问题,并在窗体加载中添加了此代码,并且闪烁消失了。
var prop = TitleBar_panel.GetType().GetProperty("DoubleBuffered", BindingFlags.Instance | BindingFlags.NonPublic);
prop.SetValue(TitleBar_panel, true, null);
TitleBar_panel
是闪烁的控件。
编辑:现在,仅当我从窗体左侧调整大小时,它才会闪烁。因此,此代码无法100%解决