如何在绘制另一个字母之前清除图形?

时间:2016-06-06 20:04:40

标签: c# graphics drawstring

    private void timer1_Tick(object sender, EventArgs e)
    {
        counter--;
        DrawLetter();
        if (counter == 0)
        {
            t.Stop();
            TakeScreenShot();
        }
    }

    private void DrawLetter()
    {
        var letter = counter.ToString();
        Graphics g = Graphics.FromHdc(GetDC(IntPtr.Zero));
        float width = ((float)this.ClientRectangle.Width);
        float height = ((float)this.ClientRectangle.Width);
        float emSize = height;
        Font font = new Font(FontFamily.GenericSansSerif, emSize, FontStyle.Regular);
        font = FindBestFitFont(g, letter.ToString(), font, this.ClientRectangle.Size);
        SizeF size = g.MeasureString(letter.ToString(), font);
        g.DrawString(letter, font, new SolidBrush(Color.White), (width - size.Width) / 2, 0);
    }

    private Font FindBestFitFont(Graphics g, String text, Font font, Size proposedSize)
    {
        // Compute actual size, shrink if needed
        while (true)
        {
            SizeF size = g.MeasureString(text, font);

            // It fits, back out
            if (size.Height <= proposedSize.Height &&
                 size.Width <= proposedSize.Width) { return font; }

            // Try a smaller font (90% of old size)
            Font oldFont = font;
            font = new Font(font.Name, (float)(font.Size * .9), font.Style);
            oldFont.Dispose();
        }
    }

    void TakeScreenShot()
    {
        bmpScreenshot = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, PixelFormat.Format32bppArgb);
        gfxScreenshot = Graphics.FromImage(bmpScreenshot);
        gfxScreenshot.CopyFromScreen(Screen.PrimaryScreen.Bounds.X, Screen.PrimaryScreen.Bounds.Y, 0, 0, Screen.PrimaryScreen.Bounds.Size, CopyPixelOperation.SourceCopy);
        bmpScreenshot.Save(Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory) + @"\ScreenCaptures\newfile.png", ImageFormat.Png);            
    }

我能够绘制字符串,但它正在自己写作。

我该如何清除它?基本上我希望倒计时出现在屏幕上,然后截取屏幕截图。

现在这个号码被另一个号码覆盖了。

my current results

4 个答案:

答案 0 :(得分:4)

您可以执行以下操作:创建其他透明表单,它将显示计时器值。这将允许您删除以前的值。另外,这将允许通过PInvoke去掉函数调用GetDC

Form timerForm; // main form field
// Create and show additional transparent form before starting the timer
timerForm = new Form
{
    FormBorderStyle = FormBorderStyle.None,
    WindowState = FormWindowState.Maximized,
    TransparencyKey = SystemColors.Control,
    ShowInTaskbar = false
};
timerForm.Show();
timer.Start();

按如下方式更改方法DrawLetter

private void DrawLetter()
{
    var letter = counter.ToString();
    Graphics g = timerForm.CreateGraphics();

    float width = ClientRectangle.Width;
    float height = ClientRectangle.Width;
    float emSize = height;

    using (Font font1 = new Font(FontFamily.GenericSansSerif, emSize, FontStyle.Regular))
    using (Font font2 = FindBestFitFont(g, letter, font1, ClientRectangle.Size))
    using (var brush = new SolidBrush(Color.White))
    {
        SizeF size = g.MeasureString(letter, font2);
        g.Clear(SystemColors.Control);
        g.DrawString(letter, font2, brush, (width - size.Width) / 2, 0);
    }
}

我们必须释放所有使用的资源,如字体和画笔。为此,我申请了using

更改计时器刻度事件处理程序,如下所示

private void timer1_Tick(object sender, EventArgs e)
{
    counter--;
    DrawLetter();
    if (counter == 0)
    {
        timer.Stop();
        TakeScreenShot();

        timerForm.Dispose(); // must release
    }
}

FindBestFitFontTakeScreenShot方法保持不变。

答案 1 :(得分:1)

将字体绘制到不同的位图。透明背景(或任何不反转的,见下文 - 也许是黑色)。

(现在你也可以使用不同颜色的阴影绘制它以减轻相似颜色背景上的绘图 - 但下面的SRCINVERT / XOR的性质也将减轻这种情况)

使用BitBlt将其复制到屏幕

使用SRCINVERT光栅操作。 (注意:颜色可能不同,因为它与下面的像素进行异或)

现在是时候擦除,只需使用与前一个相同的内容进行相同的bitblt,由SRCINVERT引起的双XOR效果将具有擦除它的效果。

然后绘制下一个字体。

注意:如果在通话之间更新桌面,则所有投注均已关闭。

更好...

不是尝试透明背景,而是在白色背景上绘制。这将消除字体的对比度问题,消除对动态更新的关注,并消除擦除问题。有时你必须承认 - 方法&amp;代码不是问题,要求是问题。这一切当然取决于要求的来源等。

如果需要看起来很专业,请不要将内容放在屏幕上,在进行屏幕截图后绘制。

如果您最终使用透明窗口方法,屏幕截图可能会错过透明窗口。要获得它,请看这个问题: Capture screenshot Including Semitransparent windows in .NET。 (可以通过更新的.net /更新的Windows版本修复)

答案 2 :(得分:1)

您需要使用InvalidateRect功能删除以前绘制的字母,从而使桌面上的所有窗口无效。

请参阅以下附加代码了解DrawLetter方法。

[DllImport("user32")]
private static extern bool InvalidateRect(IntPtr hwnd, IntPtr rect, bool bErase);

private void DrawLetter()
{
    var letter = counter.ToString();
    Graphics g = Graphics.FromHdc(GetDC(IntPtr.Zero));
    float width = ((float)this.ClientRectangle.Width);
    float height = ((float)this.ClientRectangle.Width);
    float emSize = height;
    Font font = new Font(FontFamily.GenericSansSerif, emSize, FontStyle.Regular);
    font = FindBestFitFont(g, letter.ToString(), font, this.ClientRectangle.Size);
    SizeF size = g.MeasureString(letter.ToString(), font);

    // Invalidate all the windows.
    InvalidateRect(IntPtr.Zero, IntPtr.Zero, true);

    // Sometimes, the letter is drawn before the windows are invalidated.
    // To fix that, add a small delay before drawing the letter.
    System.Threading.Thread.Sleep(100);

    // Finally, draw the letter.
    g.DrawString(letter, font, new SolidBrush(Color.White), (width - size.Width) / 2, 0);
}

答案 3 :(得分:0)

解决方案是:

在所有事情发生之前,您必须拍摄想要显示计数器区域的快照。然后调用DrawImage函数在每次调用DrawString函数之前绘制快照图像。