Delphi 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

我正在使用Delphi7,我正在编写的程序需要在屏幕上连续绘制。虽然它目前没有画出任何重要的东西,但这在以后的节目中是必要的。然而,当我把绘制屏幕的程序放在一个while循环中,这个循环只能通过按下任何按钮来停止,程序完全停止响应。我不明白为什么会这样。当然,由于while循环可以退出,程序应该继续正常运行。 以下是源代码:

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.