Delphi while循环导致程序停止响应
我正在使用Delphi7,我正在编写的程序需要在屏幕上连续绘制。虽然它目前没有画出任何重要的东西,但这在以后的节目中是必要的。然而,当我把绘制屏幕的程序放在一个while循环中,这个循环只能通过按下任何按钮来停止,程序完全停止响应。我不明白为什么会这样。当然,由于while循环可以退出,程序应该继续正常运行。 以下是源代码:Delphi while循环导致程序停止响应,delphi,while-loop,crash,pascal,Delphi,While Loop,Crash,Pascal,我正在使用Delphi7,我正在编写的程序需要在屏幕上连续绘制。虽然它目前没有画出任何重要的东西,但这在以后的节目中是必要的。然而,当我把绘制屏幕的程序放在一个while循环中,这个循环只能通过按下任何按钮来停止,程序完全停止响应。我不明白为什么会这样。当然,由于while循环可以退出,程序应该继续正常运行。 以下是源代码: unit DD04f1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphi
unit DD04f1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, TeCanvas, ExtCtrls;
type
TForm1 = class(TForm)
Image1: TImage;
Button1: TButton;
procedure Image1OnCreate();
procedure ScreenRender();
procedure OnCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure FormKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
IsDone : Boolean;
implementation
{$R *.dfm}
procedure TForm1.OnCreate(Sender: TObject);
begin
IsDone := False;
end;
procedure TForm1.Image1OnCreate ();
var
Count:Integer;
begin
image1.canvas.Create();
image1.canvas.Pen.Color:=clBlack;
image1.canvas.rectangle(0,0,640,480);
image1.canvas.Pen.Color:=$ed630e; //bgr instead of rgb
Count:=0;
While (Count <> 640) do
begin
image1.Canvas.moveto(Count,0);
image1.Canvas.LineTo(Count,480);
Count:=Count+1;
end;
end;
procedure TForm1.ScreenRender();
var
Count : Integer;
begin
Count:=0;
While(Count<>640) do
begin
image1.Canvas.moveto(Count,0);
image1.Canvas.LineTo(Count,480);
Count:=Count+1;
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
Image1OnCreate();
Button1.Visible := False;
While(IsDone = False) do
begin
ScreenRender();
end;
end;
procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
begin
IsDone := True;
end;
end.
单元DD04f1;
接口
使用
窗口、消息、系统工具、变体、类、图形、控件、窗体、,
对话框、StdCtrls、TeCanvas、ExtCtrls;
类型
TForm1=类(TForm)
图1:TImage;
按钮1:t按钮;
过程Image1OnCreate();
程序ScreenRender();
创建过程(发送方:TObject);
程序按钮1点击(发送方:ToObject);
过程FormKeyDown(发送方:ToObject;变量关键字:Word;
换档:t换档状态);
私有的
{私有声明}
公众的
{公开声明}
结束;
变量
表1:TForm1;
IsDone:布尔型;
实施
{$R*.dfm}
程序TForm1.OnCreate(发送方:TObject);
开始
IsDone:=假;
结束;
程序TForm1.Image1OnCreate();
变量
计数:整数;
开始
image1.canvas.Create();
image1.canvas.Pen.Color:=clBlack;
image1.canvas.rectangle(0,0640480);
image1.canvas.Pen.Color:=$ed630e//bgr代替rgb
计数:=0;
而(数到640)做什么
开始
image1.Canvas.moveto(计数,0);
image1.Canvas.LineTo(计数480);
计数:=计数+1;
结束;
结束;
过程TForm1.ScreenRender();
变量
计数:整数;
开始
计数:=0;
而(Count640)呢
开始
image1.Canvas.moveto(计数,0);
image1.Canvas.LineTo(计数480);
计数:=计数+1;
结束;
结束;
程序TForm1.按钮1单击(发送方:TObject);
开始
Image1OnCreate();
按钮1.可见:=假;
而(IsDone=False)do
开始
ScreenRender();
结束;
结束;
过程TForm1.FormKeyDown(发送方:TObject;变量关键字:Word;
换档:t换档状态);
开始
IsDone:=真;
结束;
结束。
假设IsDone
总是False
(因为否则我们不会进入循环),此循环无法终止。它是无限的
procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
begin
IsDone := True;
end;
您不能从内部t或m1调用此过程。按钮1单击loop,因此在您进入该循环后永远不能调用它。由于您从不退出TForm1.button1单击过程,因此也不允许执行任何外部代理(如VCL中的消息分派循环)并调用该过程。总之,一旦进入循环,就没有任何可执行代码可以更改IsDone
值。因此,它没有改变
事件处理程序应该是非常短的过程,几乎立即执行,并放弃“执行流控制”回到VCL内部。每次长时间(更无限)处理都会导致程序变得不负责任。不管有多少新闻窗口想告诉程序,程序都不会要求他们
曾经有人告诉我们,Windows(GDI对象)处于“消息风暴”的中心,他们必须及时解决这一问题。每秒有数百条这样的消息传入,一个窗口过程(构建在Delphi 7窗体的VCL类中)应该在为时已晚之前接收、发送和处理每一条消息
一旦您通过使某个事件处理程序变长甚至无限长而阻止了该进程,您就打破了操作系统和应用程序之间的基本契约
你必须做“控制反转”,把你的连续工作分成小块,让Windows在合适的时候调用这些小块。
例如,尝试使用TTimer
另外,您可以看到一个非常遥远的问题:
跳过这里所有的多线程处理内容,对于您的情况来说,重要的是,当Windows要求我们以合理的帧速率(不要太快也不要太慢)在窗体上绘制时,其他线程创建我们必须在窗体上绘制的“工作块”。你的工作块是根本不同的,所以所有的线程都与你无关
渲染是在TTimer
事件中进行的。因此,您可能对设置计时器、打开和关闭计时器的“框架”感兴趣。但是,您将在.OnTimer
事件中执行的工作会有很大的不同(只是绘制一些内容,甚至只是使表单的某些部分无效,并等待窗口触发OnPaint
事件)
假设IsDone
总是False
(因为否则我们不会进入循环),此循环无法终止。它是无限的
procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
begin
IsDone := True;
end;
您不能从内部t或m1调用此过程。按钮1单击loop,因此在您进入该循环后永远不能调用它。由于您从不退出TForm1.button1单击过程,因此也不允许执行任何外部代理(如VCL中的消息分派循环)并调用该过程。总之,一旦进入循环,就没有任何可执行代码可以更改IsDone
值。因此,它没有改变
事件处理程序应该是非常短的过程,几乎立即执行,并放弃“执行流控制”回到VCL内部。每次长时间(更无限)处理都会导致程序变得不负责任。不管有多少新闻窗口想告诉程序,程序都不会要求他们
曾经有人告诉我们,Windows(GDI对象)处于“消息风暴”的中心,他们必须及时解决这一问题。每秒有数百条这样的消息传入,并且有一个窗口过程(构建在VCL cla内部)
unit Unit2;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ExtCtrls;
type
TFormMain = class(TForm)
procedure FormCreate(Sender: TObject);
private
Timer1: TTimer;
PaintBox1: TPaintBox;
{ Private declarations }
procedure PaintBox1Paint(Sender: TObject);
procedure Timer1Timer(Sender: TObject);
public
{ Public declarations }
end;
implementation
{$R *.dfm}
procedure TFormMain.FormCreate(Sender: TObject);
begin
PaintBox1 := TPaintBox.Create(Self);
PaintBox1.Parent := Self;
PaintBox1.Align := alClient;
PaintBox1.OnPaint := PaintBox1Paint;
Timer1 := TTimer.Create(Self);
Timer1.Interval := 100;
Timer1.OnTimer := Timer1Timer;
Randomize;
end;
procedure TFormMain.PaintBox1Paint(Sender: TObject);
var
AColor: TColor;
I: Integer;
begin
for I := 0 to PaintBox1.ClientWidth - 1 do
begin
AColor := RGB(Random(256), Random(256), Random(256));
PaintBox1.Canvas.Pen.Color := AColor;
PaintBox1.Canvas.MoveTo(I, 0);
PaintBox1.Canvas.LineTo(I, PaintBox1.ClientHeight);
end;
end;
procedure TFormMain.Timer1Timer(Sender: TObject);
begin
PaintBox1.Invalidate;
end;
end.