Borland Delphi:我该如何调试这个程序?

时间:2015-03-02 15:46:01

标签: delphi

我必须使用VCL表单在Delphi中编写程序。三个正方形,六边形和八边形的数字必须向上移动到边界,然后到底部边界,依此类推。问题是我的程序冻结了,当我试图将条件运算符中的值设置为停止移动时,如果坐标Y = 0.虽然如果我将值设置为180,它会工作(奇怪)。

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.

第二单元:

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.

2 个答案:

答案 0 :(得分:10)

Delphi附带一个集成的调试器。你应该使用它。以下是如何开始调查程序似乎挂起的情况。

  1. 使用“播放”按钮在调试器的控制下启动程序。
  2. 重现您正在尝试调查的情况。
  3. 当程序挂起时,切换到调试器并按“暂停”按钮。调试器将中断程序的执行,以便您可以调查当前状态。
  4. 查看调用堆栈。 (如果调用堆栈窗口尚未显示,则可以使用IDE中的“调试窗口”菜单选项显示它。)

    调用堆栈将显示程序调用的函数列表。堆栈顶部将是您暂停时程序运行的功能。它下面的函数将是调用当前函数的函数,依此类推,直到到达堆栈的底部,这代表了程序的主要功能。

    你停下来的功能可能不是你写的那个。相反,它通常是由操作系统或Delphi运行时库提供的功能。你不想调试那些。通常,您可以假设它们已经正常工作。您正在寻找 代码中的错误。

  5. 使用“run until return”命令让最顶层的功能继续运行。重复此操作,直到到达调用堆栈上的某个函数。那可能是罪魁祸首。

  6. 现在您已经确定了有问题的功能,现在是时候进一步调查了它。

    1. 使用“step over”调试器命令逐个运行函数的每一行。 (还有一个“步入”命令,但这将进入不属于你的功能,你现在对这些功能不感兴趣。)
    2. 观察代码中变量的当前值。您可以将鼠标悬停在变量上以让调试器在工具提示中显示其值,或者您可以使用“监视”调试窗口一次显示多个变量。它们将在您的计划中的每个步骤后更新。

      注意变量的值。你应该已经对他们的价值观在你的计划过程中如何取得进展有所期待。在编写代码时,您可能已经考虑过这种进展。回想那段时间,将您在调试器中观察到的结果与之前的预期进行比较。他们匹配吗?如果是这样,那么继续单步执行代码。但是,如果它们不匹配,那么你就发现了一个错误。解决它。

      意外行为的另一个来源是在您的计划中达到您不希望达到的某个点。也许程序调用了一个它不应该具有的功能,或者你可能已经执行过多次你想要的循环。如果你能找出原因,那么修复bug。否则,您可能需要备份一些方法。

    3. 在您观察到意外行为的位置之前,确定程序中的某个点。查找代码编辑器左边距中的蓝点。这些点表示可以设置断点的位置。单击其中一个点,您应该注意到该行突出显示(可能为红色)。

    4. 终止您的程序,然后重新运行。

      这次,您应该看到调试器在程序出现挂起之前停止,因为执行将首先到达断点。调试器会中断你的程序。

    5. 像以前一样逐步执行代码行,并观察导致程序转向预期执行路径的条件。当您确定错误后,请修复它。

答案 1 :(得分:0)

它会冻结,因为你的repeat-until循环永远不会结束。

  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);

它的条件基于 y b dx 值,但它们在循环中永远不会改变。

要确认它挂起的位置,请使用Delphi中的Pause命令,然后按F7 / F8逐步运行它。