C#:绘画时避免闪烁?
C#: Avoid flickering when painting?
我想制作一个可以画线的简单应用程序。当您用鼠标单击时,您设置了线的初始坐标。然后,通过移动鼠标,您可以延长或缩短线条。因此,每次我的面板(我正在使用 System.Windows.Forms)检测到我的鼠标在移动时,它应该绘制一条新线,因为这将与前一条不同(即使是一个像素)。主要问题是,首先,我不知道如何在 C# 中处理重绘(我曾经使用 Java,并且在某些方面重绘更容易),其次,当我调用 panel.Invalidate()方法,一切都是忽悠。我还尝试通过使用矩形作为参数来使用 panel.Invalidate(Region r) 方法,但它仍然闪烁。
这是我的面板运行的 class。 Road 对象包含绘制线条的方法。在 panel1_paint(object sender, PaintEventArgs e) 方法中,我只为背景着色。在 panel1_MouseMove(object sender, MouseEventArgs e) 方法中,我绘制了线条。
partial class Form1 : Form
{
Manager manager;
Graphics g;
Road road;
Point initPosition;
bool roadOn;
bool mouseDown;
public Form1(Manager manager)
{
InitializeComponent();
this.manager = manager;
g = panel1.CreateGraphics();
road = new Road(0, 0, 0, 0, new Pen(Color.Gray, 10));
initPosition = new Point(0, 0);
roadOn = false;
mouseDown = false;
}
private void panel1_Paint(object sender, PaintEventArgs e)
{
panel1.BackColor = Color.LightGray;
}
private void Form1_KeyPress(object sender, KeyPressEventArgs e)
{
Point position = Cursor.Position;
if(panel1.ClientRectangle.Contains(position))
{
if(e.KeyChar.ToString() == Keys.R.ToString().ToLower())
{
roadOn = true;
}
}
}
private void panel1_MouseDown(object sender, MouseEventArgs e)
{
mouseDown = true;
initPosition = Cursor.Position;
road.X = initPosition.X;
road.Y = initPosition.Y;
}
private void panel1_MouseMove(object sender, MouseEventArgs e)
{
panel1.Invalidate();
panel1.Dispose();
panel1.Update();
Point position = Cursor.Position;
if(roadOn)
{
if(mouseDown)
{
road.X2 = position.X;
road.Y2 = position.Y;
road.paint(g);
}
}
}
private void panel1_MouseUp(object sender, MouseEventArgs e)
{
mouseDown = false;
}
}
这是路class:
class Road : GameObject
{
Pen pen;
public Pen Pen
{
get { return pen; }
set { pen = value; }
}
int x2;
public int X2
{
get { return x2; }
set { x2 = value; }
}
int y2;
public int Y2
{
get { return y2; }
set { y2 = value; }
}
public Road(int x1, int y1, int x2, int y2, Pen pen) : base(x1, y1)
{
this.pen = pen;
}
override public void paint(Graphics g)
{
g.DrawLine(pen, x, y, x2, y2);
}
}
两周前我遇到了同样的问题。问题是您必须设置自定义控件样式以允许双缓冲。
SetStyle( ControlStyles.OptimizedDoubleBuffer, true );
并且您可以像这样覆盖 CreateParams 属性:
protected override CreateParams CreateParams
{
get {
CreateParams cp = base.CreateParams; cp.ExStyle = cp.ExStyle | 0x20;
return cp;
}
}
另一个问题是您使用 Invalidate() 方法请求对控件进行完全验证。改用 Refresh() 方法并删除 Invalidate() 和 Update() 方法。
希望这会有所帮助:)
Panel
控件有一个 DoubleBuffered
属性 但它是受保护的。最好的解决方案是扩展它以将 属性 覆盖为 true 并使用新的 class 绘制:
创建一个 class 继承自面板:
//Make it sealed so you can call DoubleBuffered from the constructor safely.
public sealed class DoubleBufferedPanel : Panel
{
public DoubleBufferedPanel()
{
//I want this class only for drawing so force the value to true here
DoubleBuffered = true;
}
}
将表单中的面板替换为之前创建的 class 的实例。
仅通过这个小改动,您应该会看到零闪烁绘图。
希望对您有所帮助!
我想制作一个可以画线的简单应用程序。当您用鼠标单击时,您设置了线的初始坐标。然后,通过移动鼠标,您可以延长或缩短线条。因此,每次我的面板(我正在使用 System.Windows.Forms)检测到我的鼠标在移动时,它应该绘制一条新线,因为这将与前一条不同(即使是一个像素)。主要问题是,首先,我不知道如何在 C# 中处理重绘(我曾经使用 Java,并且在某些方面重绘更容易),其次,当我调用 panel.Invalidate()方法,一切都是忽悠。我还尝试通过使用矩形作为参数来使用 panel.Invalidate(Region r) 方法,但它仍然闪烁。
这是我的面板运行的 class。 Road 对象包含绘制线条的方法。在 panel1_paint(object sender, PaintEventArgs e) 方法中,我只为背景着色。在 panel1_MouseMove(object sender, MouseEventArgs e) 方法中,我绘制了线条。
partial class Form1 : Form
{
Manager manager;
Graphics g;
Road road;
Point initPosition;
bool roadOn;
bool mouseDown;
public Form1(Manager manager)
{
InitializeComponent();
this.manager = manager;
g = panel1.CreateGraphics();
road = new Road(0, 0, 0, 0, new Pen(Color.Gray, 10));
initPosition = new Point(0, 0);
roadOn = false;
mouseDown = false;
}
private void panel1_Paint(object sender, PaintEventArgs e)
{
panel1.BackColor = Color.LightGray;
}
private void Form1_KeyPress(object sender, KeyPressEventArgs e)
{
Point position = Cursor.Position;
if(panel1.ClientRectangle.Contains(position))
{
if(e.KeyChar.ToString() == Keys.R.ToString().ToLower())
{
roadOn = true;
}
}
}
private void panel1_MouseDown(object sender, MouseEventArgs e)
{
mouseDown = true;
initPosition = Cursor.Position;
road.X = initPosition.X;
road.Y = initPosition.Y;
}
private void panel1_MouseMove(object sender, MouseEventArgs e)
{
panel1.Invalidate();
panel1.Dispose();
panel1.Update();
Point position = Cursor.Position;
if(roadOn)
{
if(mouseDown)
{
road.X2 = position.X;
road.Y2 = position.Y;
road.paint(g);
}
}
}
private void panel1_MouseUp(object sender, MouseEventArgs e)
{
mouseDown = false;
}
}
这是路class:
class Road : GameObject
{
Pen pen;
public Pen Pen
{
get { return pen; }
set { pen = value; }
}
int x2;
public int X2
{
get { return x2; }
set { x2 = value; }
}
int y2;
public int Y2
{
get { return y2; }
set { y2 = value; }
}
public Road(int x1, int y1, int x2, int y2, Pen pen) : base(x1, y1)
{
this.pen = pen;
}
override public void paint(Graphics g)
{
g.DrawLine(pen, x, y, x2, y2);
}
}
两周前我遇到了同样的问题。问题是您必须设置自定义控件样式以允许双缓冲。
SetStyle( ControlStyles.OptimizedDoubleBuffer, true );
并且您可以像这样覆盖 CreateParams 属性:
protected override CreateParams CreateParams
{
get {
CreateParams cp = base.CreateParams; cp.ExStyle = cp.ExStyle | 0x20;
return cp;
}
}
另一个问题是您使用 Invalidate() 方法请求对控件进行完全验证。改用 Refresh() 方法并删除 Invalidate() 和 Update() 方法。
希望这会有所帮助:)
Panel
控件有一个 DoubleBuffered
属性 但它是受保护的。最好的解决方案是扩展它以将 属性 覆盖为 true 并使用新的 class 绘制:
创建一个 class 继承自面板:
//Make it sealed so you can call DoubleBuffered from the constructor safely.
public sealed class DoubleBufferedPanel : Panel
{
public DoubleBufferedPanel()
{
//I want this class only for drawing so force the value to true here
DoubleBuffered = true;
}
}
将表单中的面板替换为之前创建的 class 的实例。
仅通过这个小改动,您应该会看到零闪烁绘图。
希望对您有所帮助!