【问题标题】:How to reduce flickering when using Graphics.DrawString in C#, for a timer?在 C# 中使用 Graphics.DrawString 时如何减少闪烁?
【发布时间】:2015-07-15 00:08:03
【问题描述】:

以下是在进度条上绘制文本的 C# 代码。它用于向进度条添加文本,显示剩余时间倒计时。我使用 Graphics 类来绘制字符串而不是 Windows 窗体标签,因为标签背景在放置在进度条上时无法设置为透明。

但是,使用此代码,文本在每次更新时都会闪烁(此方法在每秒计时一次的计时器内调用),因此它几乎一直在闪烁并且无法使用。

/// <summary>
    /// Adds time remaining text into a System.Windows.Forms.ProgressBar
    /// </summary>
    /// <param name="target">The target progress bar to add text into</param>
    /// <param name="remainingTimeText">The text to add into the progress bar.</param>
    private void set_progress_bar_text( System.Windows.Forms.ProgressBar target, string remainingTimeText )
    {
        // Make sure we do not have a null progress bar.
        if( target == null )
        {
            throw new ArgumentException( "Null Target" );
        }

        // Use the progress bar label font and size.
        Font textFont = new Font( labelProgress.Font.Name, labelProgress.Font.Size );

        // gr will be the graphics object we use to draw on the progress bar.
        using( Graphics gr = target.CreateGraphics() )
        {
            gr.DrawString( remainingTimeText,
                textFont,
                new SolidBrush( Color.Black ), // The brush we will use to draw the string, using a black colour.

                // The position on the progress bar to put the text.
                new PointF(
                // X location of text, to be placed at the centre of the progress bar.
                    progressBar.Width / 2 - ( gr.MeasureString( remainingTimeText,
                    textFont ).Width / 2.0F ),
                // Y Location
                progressBar.Height / 2 - ( gr.MeasureString( remainingTimeText,
                    textFont ).Height / 2.0F ) ) );
        }
    }

我已尝试按照 Stack Overflow 上相关问题的建议在此方法中设置 DoubleBuffered = true,但它并不能防止闪烁。我无法减少文本更新的次数,因为文本是一个必须每秒更新一次的倒计时时钟。有没有办法通过双缓冲来防止闪烁,或者有其他潜在的解决方案吗?

【问题讨论】:

  • 您应该从该进度条的绘制事件内部调用 set_progress_bar_text 并绘制到通过 EventArgs 提供给您的图形对象上。然后优化的绘画有机会工作。您的计时器应该只触发 ProgressBar 的重绘。
  • 据我所知@Ralf,进度条没有自己的绘制事件。
  • 看过另一个问题后,那里的解决方案根本无法显示我的文本。 CreateParams 阻止所有文本显示在进度条上,我是否缺少某些步骤?谢谢@MatthewWatson
  • 嗯,你必须在绘画事件中进行绘画,而不是像现在这样。

标签: c# winforms windows-forms-designer flicker text-rendering


【解决方案1】:

ProgressBar 似乎是那些试图隐藏绘画的控件之一。所以我们需要自己动手。只需将您的 ProgressBar 与此交换即可。

添加了 CreateParams 覆盖以减少在 cmets 中提到的闪烁。

public class MyLovelyProgressBar : ProgressBar
{
    public MyLovelyProgressBar()
    {
        SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
    }

    private string foregroundText;
    public string ForegroundText 
    {
        get { return foregroundText;  }
        set 
        {
            if (foregroundText != value)
            {
                Invalidate();
                foregroundText = value;
            }
        } 
    }

    protected override CreateParams CreateParams
    {
        get
        {
            CreateParams result = base.CreateParams;
            result.ExStyle |= 0x02000000; // WS_EX_COMPOSITED 
            return result;
        }
    }

    protected override void WndProc(ref Message m)
    {
        base.WndProc(ref m);
        switch (m.Msg)
        {
            case 15: //WmPaint
                using (var graphics = Graphics.FromHwnd(Handle))
                    PaintForeGroundText(graphics);
                break;
        }
    }

    private void PaintForeGroundText(Graphics graphics)
    {
        if (!string.IsNullOrEmpty(ForegroundText))
        {
            var size = graphics.MeasureString(ForegroundText, this.Font);
            var point = new PointF(Width / 2.0F - size.Width / 2.0F, Height / 2.0F - size.Height / 2.0F);
            graphics.DrawString(ForegroundText, this.Font, new SolidBrush(Color.Black), point);
        }
    }
}

然后只需在 Timer Event 中更改 ProgressBar 的 ForegroundText。

myLovelyProgressBar1.ForegroundText = "A constantly changing lovely text";

【讨论】:

  • 这非常适合在进度条上添加文本,但仍然存在闪烁问题,除非同时使用link 中使用的方法。现在完美运行,谢谢。
  • 如果您有声誉,请编辑我的答案并添加您的更改。如果不是,您是在谈论设置有帮助的 WS_EX_COMPOSITED 样式吗?
  • 我似乎无法编辑您添加的代码,但需要的是 WS_EX_COMPOSITED,如下代码所示:protected override CreateParams CreateParams { get { CreateParams result = base.CreateParams; result.ExStyle |= 0x02000000; // WS_EX_COMPOSITED return result; } }
猜你喜欢
  • 1970-01-01
  • 2010-09-16
  • 2011-08-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-01
  • 1970-01-01
相关资源
最近更新 更多