我正在学习 Delphi,当我调用执行逻辑的私有函数时,无法显示对话框。它看起来像是一个空指针引用,但我找不到它在哪里。
以下是代码:
unit SandBox;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
type
TForm1 = class(TForm)
AhojButton: TButton;
procedure AhojButtonClick(Sender: TObject);
private
procedure ShowDialog(amount: Integer);
public
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.ShowDialog(amount: Integer);
var td: TTaskDialog;
var tb: TTaskDialogBaseButtonItem;
begin
try
td := TTaskDialog.Create(nil);
tb := TTaskDialogBaseButtonItem.Create(nil);
td.Caption := 'Warning';
td.Text := 'Continue or Close?';
td.MainIcon := tdiWarning;
td.CommonButtons := [];
tb := td.Buttons.Add;
tb.Caption := 'Continue';
tb.ModalResult := 100;
tb := td.Buttons.Add;
tb.Caption := 'Close';
tb.ModalResult := 101;
td.Execute;
if td.ModalResult = 100 then
ShowMessage('Continue')
else if td.ModalResult = 101 then
ShowMessage('Close');
finally
td.Free;
tb.Free;
end;
end;
procedure TForm1.AhojButtonClick(Sender: TObject);
begin
ShowDialog(100);
end;
end.
我试图实例化并释放TTaskDialog
和TTaskDialogBaseButtonItem
。
此行引发错误:
tb := TTaskDialogBaseButtonItem.Create(nil);
您确实有一个指针取消引用,并且您可以在提到的代码行中
nil
看到正确的内容:nil
TTaskDialogBaseButtonItem
是TCollectionItem
后代。它的构造函数接受TCollection
作为输入,但您没有传入。虽然TCollectionItem
它本身不需要TCollection
,但TTaskDialogBaseButtonItem
确实需要,正如您在其构造函数中看到的那样:正如您所见,这
TCollection
不可能nil
!如果您在启用调试 DCU 的情况下编译项目,然后在调试器内运行代码,那么当 AV 发生时,调试器就会直接带您到此行代码。
因此,为了修复错误,您可能会考虑传递对话框的
Buttons
集合,例如:但这会在运行时引发不同的错误:
这是因为该
Buttons
集合实际上需要TTaskDialogButtonItem
,它是 的后代TTaskDialogBaseButtonItem
。因此,请Create
相应地更改调用:现在,代码可以正常运行,不会崩溃。但是,对话框中将出现第三个不需要的按钮!
您的代码也造成了内存泄漏,因为您正在分配
tb
变量以指向上面创建的按钮对象,然后重新分配tb
以指向您要求对话框创建的其他按钮对象,但您从未释放手动创建的按钮:您无需创建实际的按钮对象,只需声明指向按钮对象的变量即可。让对话框为您创建实际的按钮对象,您的
tb
变量只需指向它们即可。尝试一下这个:
现在将显示所需的对话框,不会崩溃,也不会泄漏内存: