不在 OnPaint() 中绘图时进行双缓冲:为什么它不起作用?

发布于 2024-09-07 02:38:49 字数 1083 浏览 3 评论 0原文

我正在 C#/.Net 中开发一个简单的矢量绘图应用程序。绘图是在面板中完成的,但我没有使用 OnPaint() 事件来完成所有操作 - 事实上 OnPaint() 甚至只是调用另一个方法来实际绘制文档中的所有内容。

我尝试添加双缓冲,但是当我将 DoubleBuffered 设置为 true 时,闪烁问题更加严重。这是为什么呢?如果我想对控件进行双缓冲,我是否绝对必须使用提供的 Graphics 对象在 OnPaint() 事件中完成所有绘图,而不是使用 Panel.CreateGraphics() 然后绘图?

编辑:这是我正在使用的基本代码。

private void doc_Paint(object sender, PaintEventArgs e)
{
    g = doc.CreateGraphics();
    Render(ScaleFactor, Offset);
}    

private void Render(float ScaleFactor, PointF offset)
{
    foreach (Line X in Document.Lines) { DrawLine(X.PointA, X.PointB, X.Color, X.LineWidth); }
}
private void DrawLine(PointF A, PointF B, Color Color, float Width)
{
    Pen p = new Pen(Color, Width);
    PointF PA = new PointF(((A.X + Offset.X) * ScaleFactor), ((A.Y + Offset.Y) * ScaleFactor));
    PointF PB = new PointF(((B.X + Offset.X) * ScaleFactor), ((B.Y + Offset.Y) * ScaleFactor));
    g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
    g.DrawLine(p, PA, PB);
}

总体思路是,ScaleFactor 和 Offset 这两个变量指的是 UI 中的缩放级别和平移级别。 g 是一个 Graphics 对象。

I'm working on a simple vector drawing app in C#/.Net. The drawing is done in a panel, but I'm not using the OnPaint() event for all of it - in fact the OnPaint() even just calls another method which actually draws everything in the document.

I tried to add double buffering, but when I set DoubleBuffered to true, the flicker issue is even worse. Why is this? If I want to double buffer the control, do I absolutely have to do all my drawing in the OnPaint() event, with the supplied Graphics object, instead of using Panel.CreateGraphics() and then drawing to that?

EDIT: This is the basic code I am using.

private void doc_Paint(object sender, PaintEventArgs e)
{
    g = doc.CreateGraphics();
    Render(ScaleFactor, Offset);
}    

private void Render(float ScaleFactor, PointF offset)
{
    foreach (Line X in Document.Lines) { DrawLine(X.PointA, X.PointB, X.Color, X.LineWidth); }
}
private void DrawLine(PointF A, PointF B, Color Color, float Width)
{
    Pen p = new Pen(Color, Width);
    PointF PA = new PointF(((A.X + Offset.X) * ScaleFactor), ((A.Y + Offset.Y) * ScaleFactor));
    PointF PB = new PointF(((B.X + Offset.X) * ScaleFactor), ((B.Y + Offset.Y) * ScaleFactor));
    g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
    g.DrawLine(p, PA, PB);
}

The general idea is that the two variables, ScaleFactor and Offset, refer to the zoom level and pan level in the UI. g is a Graphics object.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

寻梦旅人 2024-09-14 02:38:49
g = doc.CreateGraphics();

这就是错误。仅当您绘制到缓冲区时,双缓冲才能起作用。 e.Graphics 引用的那个。修复:

g = e.Graphics;

请注意,Panel 默认情况下没有打开双缓冲。您需要自己派生。将其粘贴到一个新类中:

using System;
using System.Windows.Forms;

class BufferedPanel : Panel {
    public BufferedPanel() {
        this.DoubleBuffered = true;
        this.ResizeRedraw = true;
    }
}

Compile。将其从工具箱顶部放下。

g = doc.CreateGraphics();

That's the mistake. Double-buffering can only work if you draw into the buffer. The one that e.Graphics references. Fix:

g = e.Graphics;

Beware that Panel doesn't have double-buffering turned on by default. You'll need to derive your own. Paste this into a new class:

using System;
using System.Windows.Forms;

class BufferedPanel : Panel {
    public BufferedPanel() {
        this.DoubleBuffered = true;
        this.ResizeRedraw = true;
    }
}

Compile. Drop it from the top of the toolbox.

み格子的夏天 2024-09-14 02:38:49

就我个人而言,我不关心 DoubleBuffered 设置。我只是将所有内容绘制到位图,然后在绘制事件中将该位图绘制在屏幕上。

Bitmap BackBuffer;

private void MainFormSplitContainerPanel1Paint(object sender, PaintEventArgs e)
{
    e.Graphics.Clear(MainFormSplitContainer.Panel1.BackColor);
    if (BackBuffer != null)
        e.Graphics.DrawImage(BackBuffer, positionX, positionY, SizeX, SizeY);
}

Personally I don't bother with the DoubleBuffered setting. I just draw everything to a bitmap and then in the paint event draw that bitmap on the screen.

Bitmap BackBuffer;

private void MainFormSplitContainerPanel1Paint(object sender, PaintEventArgs e)
{
    e.Graphics.Clear(MainFormSplitContainer.Panel1.BackColor);
    if (BackBuffer != null)
        e.Graphics.DrawImage(BackBuffer, positionX, positionY, SizeX, SizeY);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文