我的 C# 窗体闪烁,我无法修复它。我什么都试过了
My C# form flickers and I can't fix it. I've tried everything
我已经为这个程序工作了大约一个月,尝试了一切。无论我做什么,我的程序都会闪烁,即使在其他机器上也是如此。它只是一个背景、一个图像和一个矩形。没有什么大的或昂贵的。然而它仍然闪烁。我试过将 DoubleBuffered 设置为 true,我试过覆盖 CreateParams(它使我的 window 变黑),我试过使用一种方法进行反射,我试过 SetStyle 来设置 DoubleBuffer、OptimizedDoubleBuffer、UserPaint,当设置为 true 时,AllPaintingInWmPain、Opaque 和 none 会执行任何操作。我已经在 google 和 Whosebug 上搜索了答案,其中 none 有效。我不明白我做错了什么。我已经添加了代码、exe、编译脚本和图像的 zip。在我和其他人的电脑上发生的事情就是 gif 上的事情。程序每秒更新 4 次,足够绘制背景、图像和正方形的时间,但它仍然闪烁。我需要帮助。
Main.cs:
using System;
using System.Threading;
using System.Windows.Forms;
public class main{
public static void Main(string[] args){
Console.WriteLine("START");
Engine.Init();
while(true){
Engine.MainDraw();
Application.DoEvents();
Thread.Sleep(250);
}
Console.WriteLine("END");
}
}
Engine.cs:
using System;
using System.IO;
using System.Windows;
using System.Windows.Forms;
using System.Drawing;
public class Engine : Form{
public static Engine EngineForm = new Engine();
public static Graphics g;
/*
protected override CreateParams CreateParams{
get{
CreateParams cp = base.CreateParams;
cp.ExStyle |= 0x02000000;
return cp;
}
}
//*/
/*
public static void enableDoubleBuff(System.Windows.Forms.Control cont){
System.Reflection.PropertyInfo DemoProp = typeof(System.Windows.Forms.Control).GetProperty("DoubleBuffered", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
DemoProp.SetValue(cont, true, null);
}
//*/
public Engine(){
this.DoubleBuffered = true;
//enableDoubleBuff(this);
this.SetStyle(
ControlStyles.DoubleBuffer |
ControlStyles.OptimizedDoubleBuffer |
ControlStyles.UserPaint |
ControlStyles.AllPaintingInWmPaint |
ControlStyles.Opaque
,
true);
this.UpdateStyles();
}
public static void Init(){
EngineForm.Enabled = true;
EngineForm.Visible = true;
EngineForm.Activate();
g = EngineForm.CreateGraphics();
}
public static Pen pen = new Pen(Color.FromArgb(255, 0, 0, 0), 5);
public static Image image = Image.FromFile("bulbasaur.png");
public static Color color = Color.FromArgb(200, 200, 255, 255);
public static void MainDraw(){
g.Clear(color);
g.DrawImage(image, new PointF(0, 0));
g.DrawRectangle(pen, 100, 100, 100, 100);
}
}
程序的样子:
您看到的问题是因为 CreateGraphics
创建了一个绕过双缓冲的 Graphics
实例,让您可以直接访问 window 的 canvas .无论您对该 Graphics
对象做什么,都会立即出现在屏幕上。
要解决此问题,您需要覆盖在正常更新过程中调用的表单方法之一:OnPaint
或 OnPaintBackground
。这些接收一个 Graphics
对象,它将按照你想要的方式工作,包括处理双缓冲:
protected override void OnPaintBackground(PaintEventArgs e)
{
base.OnPaintBackground(e);
var g = e.Graphics;
g.Clear(color);
g.DrawImage(image, 0, 0);
g.DrawRectangle(pen, 100, 100, 100, 100);
}
只要重绘窗体,在绘制控件之前等,就会调用它。您可以通过调用 Invalidate()
:
来重绘窗体
public static void MainDraw()
{
EngineForm.Invalidate();
}
这会向 window 发送一条消息,告诉它重绘。下一次通过您的事件循环将处理该消息并调用 OnPaintBackground()
。
结果是平滑、无闪烁的更新。您可以制作动画和其他内容,而不会 Clear
导致背景闪烁等。
我已经为这个程序工作了大约一个月,尝试了一切。无论我做什么,我的程序都会闪烁,即使在其他机器上也是如此。它只是一个背景、一个图像和一个矩形。没有什么大的或昂贵的。然而它仍然闪烁。我试过将 DoubleBuffered 设置为 true,我试过覆盖 CreateParams(它使我的 window 变黑),我试过使用一种方法进行反射,我试过 SetStyle 来设置 DoubleBuffer、OptimizedDoubleBuffer、UserPaint,当设置为 true 时,AllPaintingInWmPain、Opaque 和 none 会执行任何操作。我已经在 google 和 Whosebug 上搜索了答案,其中 none 有效。我不明白我做错了什么。我已经添加了代码、exe、编译脚本和图像的 zip。在我和其他人的电脑上发生的事情就是 gif 上的事情。程序每秒更新 4 次,足够绘制背景、图像和正方形的时间,但它仍然闪烁。我需要帮助。
Main.cs:
using System;
using System.Threading;
using System.Windows.Forms;
public class main{
public static void Main(string[] args){
Console.WriteLine("START");
Engine.Init();
while(true){
Engine.MainDraw();
Application.DoEvents();
Thread.Sleep(250);
}
Console.WriteLine("END");
}
}
Engine.cs:
using System;
using System.IO;
using System.Windows;
using System.Windows.Forms;
using System.Drawing;
public class Engine : Form{
public static Engine EngineForm = new Engine();
public static Graphics g;
/*
protected override CreateParams CreateParams{
get{
CreateParams cp = base.CreateParams;
cp.ExStyle |= 0x02000000;
return cp;
}
}
//*/
/*
public static void enableDoubleBuff(System.Windows.Forms.Control cont){
System.Reflection.PropertyInfo DemoProp = typeof(System.Windows.Forms.Control).GetProperty("DoubleBuffered", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
DemoProp.SetValue(cont, true, null);
}
//*/
public Engine(){
this.DoubleBuffered = true;
//enableDoubleBuff(this);
this.SetStyle(
ControlStyles.DoubleBuffer |
ControlStyles.OptimizedDoubleBuffer |
ControlStyles.UserPaint |
ControlStyles.AllPaintingInWmPaint |
ControlStyles.Opaque
,
true);
this.UpdateStyles();
}
public static void Init(){
EngineForm.Enabled = true;
EngineForm.Visible = true;
EngineForm.Activate();
g = EngineForm.CreateGraphics();
}
public static Pen pen = new Pen(Color.FromArgb(255, 0, 0, 0), 5);
public static Image image = Image.FromFile("bulbasaur.png");
public static Color color = Color.FromArgb(200, 200, 255, 255);
public static void MainDraw(){
g.Clear(color);
g.DrawImage(image, new PointF(0, 0));
g.DrawRectangle(pen, 100, 100, 100, 100);
}
}
程序的样子:
您看到的问题是因为 CreateGraphics
创建了一个绕过双缓冲的 Graphics
实例,让您可以直接访问 window 的 canvas .无论您对该 Graphics
对象做什么,都会立即出现在屏幕上。
要解决此问题,您需要覆盖在正常更新过程中调用的表单方法之一:OnPaint
或 OnPaintBackground
。这些接收一个 Graphics
对象,它将按照你想要的方式工作,包括处理双缓冲:
protected override void OnPaintBackground(PaintEventArgs e)
{
base.OnPaintBackground(e);
var g = e.Graphics;
g.Clear(color);
g.DrawImage(image, 0, 0);
g.DrawRectangle(pen, 100, 100, 100, 100);
}
只要重绘窗体,在绘制控件之前等,就会调用它。您可以通过调用 Invalidate()
:
public static void MainDraw()
{
EngineForm.Invalidate();
}
这会向 window 发送一条消息,告诉它重绘。下一次通过您的事件循环将处理该消息并调用 OnPaintBackground()
。
结果是平滑、无闪烁的更新。您可以制作动画和其他内容,而不会 Clear
导致背景闪烁等。