gpt4 book ai didi

c# - 如何防止无边框 Windows 窗体在调整大小时闪烁(C#)?

转载 作者:行者123 更新时间:2023-12-04 04:58:20 25 4
gpt4 key购买 nike

[C# .NET 4.0]

我正在学习 C#,我正在尝试使用具有 FormBorderStyle = FormBorderStyle.None 并且可以使用 Windows API 移动/调整大小的 C# 构建 Windows 窗体。例如,我使用用于 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 一起使用的两部分代码如下所示。我有一个用于 Windows API 的 WM_NCHITTEST 的公共(public)枚举...您可以看到值 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;
}
}
}
}

谢谢您的帮助。

最佳答案

闪烁的发生是因为您的显示器区域正在迅速改变颜色,而这反过来又是因为您正在过度绘制 - 在同一个像素上绘制不止一件东西。

发生这种情况是因为:

  • 如果您的重绘速度很慢,那么您正在绘制的屏幕上的内容(例如窗口边框)将在一段时间内可见。例如用户可能会看到滚动条的两个副本,直到您用表单内容删除旧的滚动条。
  • windows 会自动为您删除窗口的背景,通常为白色。因此,在您用正确的图像过度绘制之前,绘图中任何不是白色的区域都会闪烁白色。
  • 如果您在同一个地方绘制多个东西,您会看到闪烁,因为您不断更改屏幕该区域的颜色

  • 要解决这些问题,您需要综合考虑(越多越好)
  • 禁用删除背景,或将删除颜色设置为图像中的主色
  • 优化您的重绘代码以使其更快,因此闪烁不那么明显
  • 优化您的重绘代码以消除过度绘制。例如。要在矩形页面周围放置边框,您可以绘制背景颜色并将其与页面过度绘制,但这会闪烁。相反,将顶部边框绘制为矩形,然后绘制左下角和右下角,然后在中间绘制页面。由于 nopixels 被多次绘制,它不会闪烁
  • 在您的控件上启用 DoubleBuffered 模式。有了这个,你所有的绘图实际上都发生在内存中的位图图像中,然后将最终图像复制到屏幕上,这样每个像素只显示一次,没有闪烁。
  • 关于c# - 如何防止无边框 Windows 窗体在调整大小时闪烁(C#)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16466579/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com