简体   繁体   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);            
    }

I am able to draw the string but it is writing on top of itself. 我能够绘制字符串,但是它是在自身之上编写的。

How can I clear it? 我该如何清除? Basically I want the countdown to appear on the screen then take a screenshot. 基本上,我希望倒数出现在屏幕上,然后截图。

Right now the number is overwritten by another. 现在,该号码已被另一个覆盖。

我目前的结果

You can do the following: create an additional transparent form, and it will display timer values. 您可以执行以下操作:创建其他透明窗体,它将显示计时器值。 This will allow you to erase the previous value. 这将允许您删除以前的值。 In addition, this will allow to get rid of the function call GetDC via PInvoke. 此外,这将允许通过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();

Change the method DrawLetter as follows 如下更改方法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);
    }
}

We must release all used resources like fonts and brushes. 我们必须释放所有使用过的资源,例如字体和画笔。 For this I applied using . 为此,我using

Change the timer tick event handler as follows 更改计时器滴答事件处理程序,如下所示

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

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

FindBestFitFont and TakeScreenShot methods remain unchanged. FindBestFitFontTakeScreenShot方法保持不变。

Draw your font to a different bitmap. 将字体绘制到其他位图。 Transparent background (or whatever doesn't invert, see below - perhaps black). 透明背景(或任何不会反转的背景,请参见下文-可能是黑色)。

(now you could also draw it with a different colored shadow to mitigate drawing on similar colored background - but the natures of SRCINVERT/XOR, below, will mitigate this as well) (现在,您还可以使用其他彩色阴影来绘制它,以减轻在相似彩色背景上的绘制-但是下面的SRCINVERT / XOR的性质也会减轻这种情况)

Use BitBlt to copy it to the screen 使用BitBlt将其复制到屏幕

Use the SRCINVERT raster op. 使用SRCINVERT栅格操作。 (note: the colors may be different as it is XORing it with pixels underneath) (注意:颜色可能会与下面的像素进行XOR运算而不同)

Now when is is time to erase, just make the same bitblt with the same contents as previous , the double XOR effect caused by SRCINVERT will have the effect of erasing it. 现在是时候擦除了,只需使用与以前相同的内容制作相同的bitblt,由SRCINVERT引起的双重XOR效果将具有擦除效果。

Then draw the next font. 然后绘制下一个字体。

Note: if desktop is updated between calls, all bets are off. 注意:如果在两次通话之间更新了桌面,则所有投注均关闭。

better... 更好...

Rather than attempting a transparent background, draw it on a white background. 与其尝试使用透明背景,不如在白色背景上绘制它。 This will eliminate contrast issues with the font, eliminate concern with dynamic updates, and eliminate problems with erasing. 这将消除字体的对比度问题,消除对动态更新的关注,并消除擦除问题。 Sometimes you have to admit - the method & code isn't the problem, the requirements are the problem. 有时您不得不承认-方法和代码不是问题,需求才是问题。 This all depends of course on the source of the requirements, etc. 这当然取决于需求的来源等。

If it needs to look professional, don't put the content on the screen, draw it after you take the screen capture. 如果需要看起来很专业,请不要将内容放在屏幕上,而是在截取屏幕后绘制它。

If you end up using the transparent window approach, the screen shot may miss the transparent window. 如果最终使用透明窗口方法,则屏幕截图可能会错过透明窗口。 To get it, see this question: Capture screenshot Including Semitransparent windows in .NET . 要获得它,请参见以下问题: 捕获屏幕截图,包括.NET中的半透明窗口 (could be fixed by newer .net / newer windows versions) (可以由更新的.net /更新的Windows版本修复)

You need to invalidate all the windows on the desktop by using the InvalidateRect function to erase the previously drawn letter. 您需要通过使用InvalidateRect函数来擦除先前绘制的字母来使桌面上的所有窗口无效

See additional codes below for the DrawLetter method. 请参阅以下有关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);
}

A solution is: 一个解决方案是:

You must take a snapshot of that area you want to show counter before all things. 您必须先对要显示的区域进行快照,然后再进行所有操作。 Then call DrawImage function to draw snapshot image before call DrawString function every time. 然后,在每次调用DrawString函数之前,先调用DrawImage函数绘制快照图像。

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

相关问题 如何在不清晰的情况下绘制当前 Graphics 对象? - How can I draw the current Graphics object without clear? 在 C#.NET5.0 中 Windows Forms - 如何让面板在绘画事件中绘制之前不使用 BackColor 清除自身? - In C#/NET5.0 Windows Forms - How can I get a panel to NOT clear itself with the BackColor before drawing in the paint event? 如何使用图形对象的clear函数(需要color参数)来清除表单的图形? - How can I use a graphic object's clear function(which requires a color argument) to clear the graphics of a form? 如何调整e.Graphics将在其中绘制的区域(视口)? - How can I adjust the area into which e.Graphics will be drawing (viewport)? 如何将绘图图形保存到位图? - How to save drawing Graphics to bitmap? 如何单元测试绘图图形? - How to unit test drawing graphics? 在自定义控件上绘制新内容之前,应该怎么做才能清除已绘制的所有内容? - What should I do to clear everything I have drawn before drawing new things on custom control? 如何清除文本框? - How can I clear a TextBox? 如何使用 C# 查找符号后面的字母是大写还是另一个符号 - How can I find if a letter following a symbol is in uppercase OR is another symbol using C# 为什么图形没有绘制到面板上 - How come the graphics is not drawing onto the panel
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM