1

I have to write program in Delphi using VCL forms. Three figures which are square, hexagon and octagonal must move to up border, then to bottom border and so on. The problem is that my program freezes, when I'm trying to put values in condition operators to stop moving, if coordinate Y = 0. Though it works(strangely) if I put value = 180, for example.

unit Main;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls;

type
TMainForm = class(TForm)
Image: TImage;
BeginButton: TButton;
EndButton: TButton;
Timer1: TTimer;
Edit1: TEdit;
procedure FormActivate(Sender: TObject);
procedure BeginButtonClick(Sender: TObject);
procedure EndButtonClick(Sender: TObject);
procedure Timer1Timer(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
MainForm: TMainForm;

implementation

uses Figure;

{$R *.dfm}
Var
t:single=0.0;
L:TSquare;
S:THexagon;
C:TOctagon;
Moving:Boolean=true;

procedure TMainForm.FormActivate(Sender: TObject);
begin
 Image.Canvas.Brush.Color:=clWhite;
end;

procedure TMainForm.Timer1Timer(Sender: TObject);
begin
    L.Move(t);
    S.Move(-0.2*t);
    C.Move(0.5*t);
    t:=t+0.5;
end;

procedure TMainForm.BeginButtonClick(Sender: TObject);
begin
    L:=TSquare.Create(60,35,Image);
    S:=THexagon.Create(180,100,Image);
    C:=TOctagon.Create(300,100,Image);
    Timer1.Enabled:=true;
end;

procedure TMainForm.EndButtonClick(Sender: TObject);
begin
    Close;
end;

initialization

finalization
 L.Free;
 S.Free;
 C.Free;

end.

And second Unit:

Unit Figure;
Interface
 uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls,         Forms,
 Dialogs, StdCtrls, ExtCtrls;
Type
 TFigure=Class
  private  x,y, b,
    dx:integer;
    Image:TImage;
    procedure Draw;virtual;abstract;
    procedure Rel(t:real);virtual;
  public
    constructor Create(ax,ay:integer;aImage:TImage);
    procedure Move(t:single);
 end;

 THexagon=Class(TFigure)
     private procedure Draw;override;
 end;

 TSquare=Class(TFigure)
     private procedure Draw;override;
 end;

 TOctagon=Class(TFigure)
     private procedure Draw;override;
 end;


Implementation

Constructor TFigure.Create;
Begin
   inherited Create;
   x:=ax; y:=ay;  Image:=aImage;
End;

Procedure TFigure.Rel;
Begin
   dx:=5*round(t);
End;

Procedure TFigure.Move;
Begin
   Image.Canvas.Pen.Color:=clWhite;
   Draw;
   Image.Canvas.Pen.Color:=clBlack;
   Rel(t);
   Draw;
End;

Procedure TSquare.Draw;
Begin
  b:=70;
  Image.Canvas.MoveTo(x+round(0.5*b),y-round(0.5*b));
  Image.Canvas.LineTo(x-round(0.5*b),y-round(0.5*b));
  Image.Canvas.LineTo(x-round(0.5*b),y+round(0.5*b));
  Image.Canvas.LineTo(x+round(0.5*b),y+round(0.5*b));
  Image.Canvas.LineTo(x+round(0.5*b),y-round(0.5*b));
End;

Procedure THexagon.Draw;
Begin
  b:=70;
  repeat
  begin
  Image.Canvas.MoveTo(x+round(0.5*b),y+dx);
  Image.Canvas.LineTo(x+round(0.25*b),y+round(0.5*b)+dx);
  Image.Canvas.LineTo(x-round(0.25*b),y+round(0.5*b)+dx);
  Image.Canvas.LineTo(x-round(0.5*b),y+dx);
  Image.Canvas.LineTo(x-round(0.25*b),y-round(0.5*b)+dx);
  Image.Canvas.LineTo(x+round(0.25*b),y-round(0.5*b)+dx);
  Image.Canvas.LineTo(x+round(0.5*b),y+dx);
  end;
  until ((y+round(0.5*b)+dx)<180);
End;




Procedure TOctagon.Draw;
var
 I: Integer;
 p: array[1..9] of tpoint;
 u:extended;
 Begin
  x:=300;
  y:=100;
  u:=0;
  for I := 1 to 8  do
  begin
  p[i].X:=x+round(40*cos(u));
  p[i].Y:=y-round(40*sin(u));
  u:=u+pi/4;
  end;
  repeat
    begin
  Image.Canvas.MoveTo(p[8].x,p[8].y-dx);
  for I := 1 to 8  do
    Image.Canvas.LineTo(p[i].X,p[i].y-dx);
    end;
  until (p[3].y>50);

End;
end.
Taxidermic
  • 88
  • 7
  • Your hexagon draw routine is a repeat until loop where nothing changes to stop the loop. – LU RD Mar 02 '15 at 16:09
  • @LURD yes, because the program won't start, if I put for example ((y+round(0.5*b)+dx)=0) as condition to stop. – Taxidermic Mar 02 '15 at 16:28
  • The draw routine should draw the shape only once, that was my point. – LU RD Mar 02 '15 at 16:50
  • Welcome to Stack Overflow. You have neglected to actually ask a question, so I have assumed your question was this: "How do I debug a program that appears to hang?" If that isn't really your question, then please [edit] to clarify what you have done, what you expected to happen, and what actually happened instead. – Rob Kennedy Mar 02 '15 at 17:18
  • You can stop changing the title. @Rob has already written a good tutorial on how to debug your code, and we're *not* going to do it for you. Follow the steps Rob gave you and work it out yourself, exactly as he explained. – Ken White Mar 02 '15 at 17:58
  • @KenWhite the thing is I can't do it, because when I press "pause" button, list of binary codes is shown. And values and variables can't be observed for some reason. I'm stuck here and would be glad to get another hint. – Taxidermic Mar 02 '15 at 19:21
  • 1
    Did you follow my instructions and run until you reached a function that *you* wrote? The source code of that function will be available. Also, you could have posted a comment to my answer asking for clarification instead of just changing the title to be less accurate. – Rob Kennedy Mar 02 '15 at 19:25
  • @RobKennedy yes. I didn't understand how to work out mistakes with call stack, but I finally found mistakes and made program work by observing code. But anyway big thanks! I'll try to understand your message, it seems to be really important knowledge. :> – Taxidermic Mar 02 '15 at 20:33

2 Answers2

10

Delphi comes with an integrated debugger. You should use it. Here's how to start investigating a case where a program seems to hang.

  1. Start your program under control of the debugger with the "play" button.
  2. Reproduce the situation you're trying to investigate.
  3. When the program hangs, switch to the debugger and press the "pause" button. The debugger will interrupt the execution of your program so you can investigate the current state.
  4. Look at the call stack. (If the call-stack window isn't already visible, you can show it by using the "debug windows" menu option in the IDE.)

    The call stack will show the list of functions your program has called. At the top of the stack will be the function your program was running at the moment you paused. The function below it will be the function that called the current function, and so on until you reach the bottom of the stack, which represents the main function of your program.

    The function you stop in probably won't be one you wrote. Instead, it's usually a function provided by the OS or by the Delphi run-time library. You don't want to debug those. Generally, you can assume they already work properly. You're looking for a bug in your code instead.

  5. Use the "run until return" command to let the topmost function continue running. Repeat that until you reach one of your functions on the call stack. That's probably the culprit.

Now that you've identified the problematic function, it's time to investigate it further.

  1. Use the "step over" debugger command to run each line of your function one by one. (There's also a "step into" command, but that will step into functions that aren't yours, and you're not interested in those now.)
  2. Observe the current values of variables in your code. You can hover the mouse over a variable to let the debugger display its value in a tool tip, or you can use the "watches" debug window to display multiple variables at once. They'll be updated after each step in your program.

    Pay attention to the variables' values. You should already have some expectation of how their values should progress over the course of your program. You probably thought about that progression while you were writing the code. Think back to that time and compare the results you observe in the debugger with your previous expectations. Do they match? If so, then keep stepping through the code. If they don't match, though, then you've found a bug. Fix it.

    Another source of unexpected behavior is to reach a point in your program that you didn't expect to reach. Maybe the program called a function it shouldn't have, or maybe you've executed a loop more times you wanted to. If you can work out the reason, then fix the bug. Otherwise, you might need to back up a little ways.

  3. Identify a point in your program earlier than where you have observed the unexpected behavior. Look for the blue dots in the left margin of the code editor. Those dots represent places where you can set a breakpoint. Click one of the dots, and you should notice the line be highlighted (probably in red).

  4. Terminate your program, and run it again.

    This time, you should see the debugger stop before the program appears to hang because execution will have reached the breakpoint first. The debugger interrupts your program there.

  5. Step through the lines of your code as you did before, and watch for the condition that causes your program to veer from the expected path of execution. When you've identified the bug, fix it.

Rob Kennedy
  • 161,384
  • 21
  • 275
  • 467
0

It freezes because your repeat-until loop will never end.

  repeat
  begin
  Image.Canvas.MoveTo(x+round(0.5*b),y+dx);
  Image.Canvas.LineTo(x+round(0.25*b),y+round(0.5*b)+dx);
  Image.Canvas.LineTo(x-round(0.25*b),y+round(0.5*b)+dx);
  Image.Canvas.LineTo(x-round(0.5*b),y+dx);
  Image.Canvas.LineTo(x-round(0.25*b),y-round(0.5*b)+dx);
  Image.Canvas.LineTo(x+round(0.25*b),y-round(0.5*b)+dx);
  Image.Canvas.LineTo(x+round(0.5*b),y+dx);
  end;
  until ((y+round(0.5*b)+dx)<180);

Its condition is based on y, b and dx values but they never change in your loop.

To confirm where it hangs, use the Pause command in Delphi, then press F7/F8 to run it step by step.

djsoft
  • 1,051
  • 8
  • 19