透明图形缓冲区清除?

时间:2012-01-14 16:32:42

标签: c# image forms gdi+ transparency

我目前正在开展一个项目,我必须使用GDI +(System.Drawing)。我正在尝试制作一个带有动态neeldes的多功能仪表(一个类似钟表的轮子)。

我不想每帧都绘制背景图像(带有所有标记)。我现在解决这个问题的方法是将它设置为图形“容器”的背景图像,这是一个面板(请记住这一点,我可能不得不这样做。)

然后我画针。针目前每秒更新25次(我可能会优化它,以便它只在必要时更新)。但问题是,我必须在开始使用新帧之前清除缓冲区,导致背景图像被缓冲区的背景颜色覆盖。显然我不想要这个。

我尝试将缓冲区的背景颜色设置为Color.Transparent,但是根据父级的透明度键(在我的情况下,它会变成黑色),它会为缓冲区提供一种颜色。

以下是我当前用于绘制针的代码(在Wheel类中):

    /// <summary>
    /// Draws the wheel and the needles.
    /// </summary>
    public void Draw()
    {
        Graphics.Clear(Color.Transparent);

        // Draws all needles, works fine
        foreach (Needle Ndl in Needles)
        {
            Ndl.Draw(ref this.Graphics);
        }

        // Draws the little circle in the center of the wheel. Looks only.
        Graphics.FillEllipse(new Pen(Color.White).Brush, new Rectangle(120, 120, 16, 16));
    }

是的,我已遵循Stack Overflow规则,我完成了我的作业。其他人通过使用BitBlt每帧绘制图像来解决它,这是我的大脑理解的方法。

我对此非常开放,所以如果你认为我应该使用BitBlt,你知道我在哪里可以找到一些相关的深入例子,我肯定会用BitBlt来做。当然,如果有不使用BitBlt的解决方案,或者无论如何在这里使用它都没有意义,那会更好。

是否可以使缓冲区的背景透明,或者我应采取完全不同的方法?

注意:我最好不要使用XNA,因为此应用程序主要用于简单/旧计算机上的维护,所以我不想与可再发行组件有任何关系。

1 个答案:

答案 0 :(得分:1)

您可以将基本图像放在PictureBox中。然后你的代码可以处理PictureBox的Paint事件来绘制你的针。这样你就不必担心Graphics.Clear()的透明度或运行缓慢:你的代码只需要计算针的位置。

作为一个快速测试,我写了一个小形式的应用程序,创建一个时针(红色),秒针(贪婪)和毫秒手(蓝色)的时钟。分针得不到尊重,因此未显示。背景是在GIMP中创建的黑色圆角矩形的图像。

Clock with millisecond hand

为了模拟您的环境,我添加了一个间隔为10毫秒(100周期/秒)的计时器。处理事件Timer.Tick时,强制重绘PictureBox。

我手动编辑代码,只留下毫秒手的代码:

    public Form1()
    {
        InitializeComponent();

        pictureBox1.Paint += new PaintEventHandler(pictureBox1_Paint);

        Center = new PointF((float)pBox1.Width / 2, (float)pBox1.Height / 2);

        MillisecondLength = (float)pBox1.Width / 4;  //length of millisecond hand

        timer1.Interval = 10;  
        timer1.Enabled = true;
        timer1.Tick += new EventHandler(timer1_Tick);
    }

    PointF Center;

    float MillisecondLength;
    Pen MillisecondsPen = new Pen(Brushes.Blue, (float)3);

    double HALF_PI = Math.PI / 2;
    double TWO_PI = 2 * Math.PI;

    double millisecondHandAngle(DateTime dt)
    {
        //12 o'clock is at the top! (- PI / 2)
        return TWO_PI * dt.Millisecond / 1000 - HALF_PI;
    }

    void pBox1_Paint(object sender, PaintEventArgs e)
    {
        DateTime dt = DateTime.Now;         
        double mangle = millisecondHandAngle(dt);

        SizeF millisecondOffset = new SizeF(
            (float)(MillisecondLength * Math.Cos(mangle)), 
            (float)(MillisecondLength * Math.Sin(mangle))
        );

        PointF endMillisecond = PointF.Add(Center, millisecondOffset);

        e.Graphics.DrawLine(MillisecondsPen, Center, endMillisecond);
    }

    void timer1_Tick(object sender, EventArgs e)
    {
        pBox1.Invalidate();
    }

虽然代码中没有显示,但是我添加了一个System.Diagnostics.Stopwatch和一个计数器变量来计算实际帧速率,这在我的旧笔记本电脑上达到了大约64帧/秒的峰值。即使您将计时器间隔设置得非常小,也会有最大重绘率。