我遇到过一些我不知道如何解释的行为。当我反复绘制到System.Windows.Forms.Form
而不小心不挂线时,几秒钟后绘图输出冻结,我看到标题中可怕的(无响应)文本:
此屏幕截图不是中画;它绘制的图像在程序结束时是完全红色的,但是绘图已经停止了大约一半。 奇怪的是,如果我在绘制之前跳过设置Form.Text
属性,它就不会冻结。有人可以解释原因吗?
我使用循环来绘制一些多线程图形填充算法的进度,但是看到屏幕输出冻结了。由于我正在绘制,然后在循环中调用Thread.Sleep()
,我应该预料到这种行为(other posts指出我可能应该使用BackgroundWorker
,但只是停止使用Application.DoEvents()
冻结了我)。
但是当我删除代码以找到我的错误时,真正让我感到惊讶的是,当我删除了更改form.Text
的调用时,它不会再冻结了!它并没有要求制定者做任何事情;分配空字符串(form.Text = "";
)也会导致它不冻结。因此,出于某种原因,当Text
为空时,Windows并不关心程序没有响应,并且很乐意继续显示绘图进度! 发生了什么事? Windows是否以不同的方式处理空标题的程序?
我将代码缩减到了查看冻结所需的最低限度。当程序运行时,表单图像将被循环填充为红色。即使循环继续运行,大约中途填充它也会停止!你看到它完成后它会处理事件并再抽出一次来显示整个图像是红色的,然后再停留两秒钟。
(如果你运行调试(F5)它不会冻结;你必须在没有调试的情况下运行(Ctrl-F5)。这使得所有这一切都变得更难了!)
using System.Drawing;
using System.Threading;
using System.Windows.Forms;
// Include resources System.Drawing, System.Windows.Forms in VS before compiling
class Program
{
static void Main(string[] args) {
Bitmap image = new Bitmap(400, 20);
Form form = new Form();
form.Text = "some title"; // Comment this out to avoid the freeze
form.SetBounds(30, 30, image.Width + 16, image.Height + 38);
form.Show();
Graphics graphics = Graphics.FromHwnd(form.Handle);
for (int x = 0; x < 400; ++x)
for (int y = 0; y < 20; ++y) {
image.SetPixel(x, y, Color.Red);
graphics.DrawImage(image, 0, 0);
Thread.Sleep(1);
// Calling this would prevent the freeze:
//Application.DoEvents();
}
Application.DoEvents();
graphics.DrawImage(image, 0, 0);
Thread.Sleep(2000);
}
}
答案 0 :(得分:2)
Thread.Sleep();
将阻止你的gui线程。您的表单未更新,您的消息循环(处理鼠标/绘画/键盘事件)被阻止。
调用Application.DoEvents将处理来自消息循环的消息,但这是一种不好的做法。即使你没有准备好循环,也允许关闭表单。
我认为问题是,form.Text = "some title";
向窗口发送消息(WM_PAINT)以重新绘制窗口,但它永远不会被处理。事实证明没有反应。可能将Application.DoEvents
置于form.Text = "some title";
后面,可以解决这个问题。
如果要在一段时间内更新图形,则应该查看Timer类。 http://msdn.microsoft.com/en-us/library/system.windows.forms.timer.aspx