|
|
Delphi programming step by step program execution |
|
|
In some cases, as in educational software, it is necessary to execute a program step-by-step.
A convenient way to advance each step is by hitting the SPACE bar.
But also is must be possible to terminate the process and return to an input mode or whatever.
A good key for this is ESCAPE.
Implementation of both demands requires two boolean variables.
1.
var stopflag : boolean;
stopflag is normally true.
However, hitting the space bar sets stopflag false, which causes the program to continue.
2.
var runflag : boolean;
Runflag is normally true.
Program execution may proceed in this case.
Hitting ESCAPE clears runflag and the execution of our process stops.
The program itself does not stop, but only waits for new commands after skipping procedures.
A good way to halt program execution is
application.processmessages;
This calls Windows to handle events.
A procedure for the program stop may be
procedure programstep;
begin
stopflag := true;
while stopflag do application.processmessages;
end;
Say we have processes 1..4 to step through.
The program now will look like:
procedure DoJob;
begin
runflag := true;
process1;
programstep;
if runflag then process2;
programstep;
if runflag then process3;
programstep;
if runflag then process4;
programstep;
end;
runflag may also depend on process results such as error codes.
In the case of errors, the processes that follow will be skipped if runflag is set false.
A problem is closing the form while stopped.
So, the Close event must set runflag and stopflag to false, otherwise the program will not close until finished.
Normally a button press will start the job.
It is convenient to use this button as well to continue the program when stopped.
The final program (see below) takes care of that.
In a project, events from keyboard or mouse have a meaning that depends on the state of the program.
Editing input data, processing data, waiting for a command.....
Therefore a variable with name such as programstate is needed.
In this simple case, programstate may be psIdle or psExecute,
to differentiate between executing and not executing the processes 1..4.
On form1 is placed a button (name GO).
Paintbox1 shows some arbitrary actions of procedures 1..4.
A label named msglabel allows for the display of messages.
That's all.
Do not forget to set keypreview true in the form1 object inspector.
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls;
type
TForm1 = class(TForm)
msglabel: TLabel;
GoBtn: TButton;
PaintBox1: TPaintBox;
procedure GoBtnClick(Sender: TObject);
procedure FormKeyPress(Sender: TObject; var Key: Char);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
type Tprogramstate = (psIdle,psExecute);
var runflag : boolean;
stopflag :boolean;
programstate : TProgramstate = psIdle;
procedure programstep;
//stop program execution until step or escape
//do not stop if runflag is dropped
begin
if runflag = false then exit;
form1.msglabel.Caption := 'stop: press to continue, to stop';
stopflag := true;
while stopflag do application.ProcessMessages;
end;
procedure clearpaintbox;
begin
with form1.PaintBox1 do with Canvas do
begin
brush.Color := form1.Color;
brush.Style := bsSolid;
fillrect(rect(0,0,width,height));
font.Height := 20;
font.Name := 'arial';
font.Color := $000000;
end;
end;
procedure process1;
var r : Trect;
begin
with form1.PaintBox1 do with canvas do
begin
r := rect(0,0,width,height);
brush.color := $00ffff;
brush.style := bsSolid;
fillrect(r);
framerect(r);
font.color := $0000ff;
brush.Style := bsClear;
textout(10,10, 'process1 completed');
end;
end;
procedure process2;
begin
with form1.PaintBox1 do with canvas do
begin
brush.Style := bsSolid;
brush.Color := $ff0000;
ellipse(200,10,300,60);
font.Color := $ff0000;
brush.Style := bsClear;
textout(10,40,'process2 completed');
end;
end;
procedure process3;
begin
with form1.PaintBox1 do with canvas do
begin
brush.Style := bsSolid;
brush.Color := $00ff00;
ellipse(200,70,300,120);
font.color := $00ff00;
brush.Style := bsClear;
textout(10,70,'process3 completed');
end;
end;
procedure process4;
begin
with form1.PaintBox1 do with canvas do
begin
brush.Style := bsSolid;
brush.Color := $ff00ff;
ellipse(200,130,300,190);
font.color := $ff00ff;
brush.Style := bsClear;
textout(10,100,'process4 completed');
end;
end;
procedure TForm1.GoBtnClick(Sender: TObject);
//GO button pressed to start or to advance one step
begin
if programstate = psExecute then
begin
stopflag := false; //step thru if waiting
exit;
end;
activecontrol := nil;//prevent space key to activate GO button
runflag := true;
clearpaintbox;
programstate := psExecute;
process1;
programstep;
if runflag then process2;
programstep;
if runflag then process3;
programstep;
if runflag then process4;
programstep;
programstate := psIdle;
if runflag then msglabel.Caption := 'process completed'
else msglabel.Caption := 'process interrupted';
end;
procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char);
begin
if programstate = psExecute then
begin
if key = #32 then stopflag := false; //space
if key = #27 then begin //escape
runflag := false;
stopflag := false;
end;
key := #0;
end;
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
runflag := false;
stopflag := false;
end;
end.
|
|