gpt4 book ai didi

c# - Invalidate()将东西留在屏幕上

转载 作者:太空宇宙 更新时间:2023-11-03 21:17:27 30 4
gpt4 key购买 nike

我对invalidate的理解是,它向区域添加了一个标志,表明该区域需要更新,然后当无其他事情可做时,该区域将被更新。
发生这种情况时,该区域中的所有内容都将被删除,然后由订户重画到paint-event,如forms-class的构造函数中所定义。

但是,当我单击程序的反向板(Windows窗体应用程序)时,在单击的位置会绘制反向块,但是有效移动的指示符(由DrawEllipse绘制)仍然保留在屏幕上,即使它们重新绘制时的方法与绘制块的方法相同。当我将窗口从屏幕上移开并移回时,有效的移动指示器确实消失了。

我究竟做错了什么?

为了完整起见,我的代码在这里(最重要的注释是英文,有些注释仍是荷兰语):

 void tekenGrid(object obj, PaintEventArgs pea)
{
int vakjeBreedte = speelbordPanel.Width / Math.Max(r, k);
int speelstukDiameter = vakjeBreedte - 6;

Pen mijnPen = new Pen(Color.Black, 2);
Graphics gr = speelbordGraphics; //we use the graphics object specifically made for the playing board
gr.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;

for (int rij = 0; rij < r; rij++) //lets make the grid, in this for-loop

{
for (int kolom = 0; kolom < k; kolom++)
{
{
int x = vakjeBreedte * kolom + 3; //x,y coordinaat van de vierhoek waar de cirkel in zit
int y = vakjeBreedte * rij + 3;

gr.DrawRectangle(mijnPen, vakjeBreedte * kolom, vakjeBreedte * rij, vakjeBreedte, vakjeBreedte); //gives the playing board black rectangles around every position

if (speelbord[kolom, rij] == speelstuk.Blauw) //draw the blue pieces
{
gr.FillEllipse(Brushes.Blue, x, y, speelstukDiameter, speelstukDiameter);
}

else if (speelbord[kolom, rij] == speelstuk.Rood) //draw the red pieces
{
gr.FillEllipse(Brushes.Red, x, y, speelstukDiameter, speelstukDiameter);
}

if (laatHintsZien == true) //the legal move function indicator is here
{
if (checkLegaalheid(kolom, rij))
{
gr.DrawEllipse(mijnPen, x, y, speelstukDiameter, speelstukDiameter);
}

}
}
}
}
}

最佳答案

该区域中的所有内容都将被删除


这可能是产生此类问题的最大误解。您无法“删除”屏幕上的像素。它总是在那里并且具有特定的颜色。如果颜色错误,则您的工作就是再给它一个。

Windows中的绘制周期如下:


只要窗口的内容过期,就需要对其进行绘制。可以通过调用Invalidate(),您的案例或当窗口管理器自己解决问题时明确地做到这一点,例如,将窗口拖出屏幕并向后拖动或用户调整窗口大小时。在Aero之前的旧Windows版本上,当另一个窗口在您的整个窗口上移动时也是如此。
操作系统要做的第一件事是为窗口创建“设备上下文”,它将您绘制的所有内容定向到窗口表面。 Graphics类是设备上下文的.NET包装器。此时,您应该“ u​​h-oh”,该设备上下文当然与您之前创建并存储在speelbordGraphics变量中的设备上下文不匹配。特别是,其ClipBounds属性可能是错误的,这种错误会在窗口大小更改时发生。
接下来,通过PaintEventArgs.ClipRectangle属性公开确定需要重画窗口的哪个部分。您应该在这里再次“呃-哦”​​。您在该剪辑矩形之外绘制的任何内容实际上都不会到达窗口表面。这是一种优化,无法在您的代码中使用。
如果将DoubleBuffered属性设置为true,则Winforms将创建另一个设备上下文,它将油漆引导到内存中的位图,因此绘制的所有内容都不会直接进入屏幕,而是直接进入位图。它有助于抑制可见的绘画伪影,通常称为“闪烁”。您会为游戏板真正喜欢的东西。您应该在这里再次惊叹“呃-哦”​​,通过speelbordGraphics绘制的内容将进入屏幕表面,而不是位图。
接下来,运行表单的OnPaintBackground()方法。如果未覆盖它,则使用Graphics.FillRectangle()将剪辑矩形中的像素设置为BackColor颜色。这与“该区域的所有内容均被删除”最接近。继续使用“ uh-oh”的另一个原因是,您的speelbordGraphics允许您直接将像素猛击到屏幕上,而无需绘制背景。这样做的副作用是您不会看到像素被设置回预期的BackColor。看起来他们没有被“擦除”。与您观察到的结果非常匹配。
接下来,运行窗体的OnPaint()方法。它会触发Paint事件,无疑您的tekenGrid方法会运行。
如果DoubleBuffered属性设置为true,则Winforms现在将使用快速的bitblt将位图复制到屏幕表面。这里的另一个“呃-哦”​​,覆盖了您通过speelbordGraphics绘制的所有内容。这很容易注意到,您会在短短的一秒钟内看到绘制的内容,看起来就像是大量闪烁的情况。与DoubleBuffered应该完成的事情完全相反:)


收集前面的项目符号中的所有“呃”,它们都有一个单独的原因。它们都是由speelbordGraphics引起的。您称它为“方便”,但一点也不方便,它会导致错误。更糟糕的是,它效率低下。设备上下文的创建非常便宜,不到一微秒,但保持环境昂贵。无论如何,创建在项目符号中提到的那些设备上下文,您的变量不会对其进行优化。而且它会占用同一台式机上所有进程从中分配的堆中的内存。堆大小是有限的,出于应用程序兼容性原因,它只能存储65535个图形对象。

因此,修复非常简单,只需删除变量即可。现在没有办法弄错了。编译器会告诉您您在哪里做错了,它将迫使您在Paint事件处理程序中使用从e.Graphics获取的Graphics对象。您将不可避免地发现并修复您的错误。

关于c# - Invalidate()将东西留在屏幕上,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33079532/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com