[英]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. FindBestFitFont
和TakeScreenShot
方法保持不变。
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. 注意:如果在两次通话之间更新了桌面,则所有投注均关闭。
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.