c#:在绘制时避免闪烁

本文关键字:闪烁 绘制 | 更新日期: 2023-09-27 18:18:32

我想做一个简单的应用程序,允许绘制一条线。当你用鼠标点击时,你设置了线的初始坐标。然后,通过移动鼠标,可以延长或缩短这条线。因此,每次我的面板(我使用的是System.Windows.Forms)检测到我的鼠标移动时,它应该画一条新线,因为这条线与前一条线不同(即使是一个像素)。主要问题是,首先,我不知道如何在c#中处理重绘(我曾经使用Java,在某些方面重绘更容易),其次,当我调用panel.Invalidate()方法时,一切都在闪烁。我还尝试使用面板。使用矩形作为参数使(区域r)方法无效,但它仍然闪烁。

这是我的面板操作的类。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;
    }
}

这是Road类:

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);
    }
}

c#:在绘制时避免闪烁

Panel控件具有DoubleBuffered属性,但它是受保护的。最好的解决方案是扩展它以覆盖属性为true,并使用新类来绘制:

创建一个继承Panel的类:

//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;
    }
}

用前面创建的类的实例替换表单中的面板。

只有这个小的改变,你应该看到零闪烁的绘图。

希望这对你有帮助!

两周前我也有同样的问题。问题是你必须设置自定义控件样式来允许双缓冲区。

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()方法。

希望对你有帮助