繁体   English   中英

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

[英]How can I clear the Graphics before drawing another letter?

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

我能够绘制字符串,但是它是在自身之上编写的。

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

现在,该号码已被另一个覆盖。

我目前的结果

您可以执行以下操作:创建其他透明窗体,它将显示计时器值。 这将允许您删除以前的值。 此外,这将允许通过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方法保持不变。

将字体绘制到其他位图。 透明背景(或任何不会反转的背景,请参见下文-可能是黑色)。

(现在,您还可以使用其他彩色阴影来绘制它,以减轻在相似彩色背景上的绘制-但是下面的SRCINVERT / XOR的性质也会减轻这种情况)

使用BitBlt将其复制到屏幕

使用SRCINVERT栅格操作。 (注意:颜色可能会与下面的像素进行XOR运算而不同)

现在是时候擦除了,只需使用与以前相同的内容制作相同的bitblt,由SRCINVERT引起的双重XOR效果将具有擦除效果。

然后绘制下一个字体。

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

更好...

与其尝试使用透明背景,不如在白色背景上绘制它。 这将消除字体的对比度问题,消除对动态更新的关注,并消除擦除问题。 有时您不得不承认-方法和代码不是问题,需求才是问题。 这当然取决于需求的来源等。

如果需要看起来很专业,请不要将内容放在屏幕上,而是在截取屏幕后绘制它。

如果最终使用透明窗口方法,则屏幕截图可能会错过透明窗口。 要获得它,请参见以下问题: 捕获屏幕截图,包括.NET中的半透明窗口 (可以由更新的.net /更新的Windows版本修复)

您需要通过使用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);
}

一个解决方案是:

您必须先对要显示的区域进行快照,然后再进行所有操作。 然后,在每次调用DrawString函数之前,先调用DrawImage函数绘制快照图像。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM