我正在学习 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
:
tb := TTaskDialogBaseButtonItem.Create(nil);
^^^
TTaskDialogBaseButtonItem
是 TCollectionItem
的后代。 它的构造函数接受 TCollection
作为输入,但您没有传入一个。虽然 TCollectionItem
本身不需要 TCollection
,但 TTaskDialogBaseButtonItem
需要,正如您在其构造函数中看到的那样:
constructor TTaskDialogBaseButtonItem.Create(Collection: TCollection);
begin
inherited;
FCaption := '';
FClient := TCustomtaskDialog(Collection.Owner); // <-- HERE
FEnabled := True;
FModalResult := ID + 100; // Avoid mrNone..mrYesToAll and IDOK..IDCONTINUE
end;
因此,要修复错误,您可能会考虑传入对话框的
Buttons
集合,例如:
tb := TTaskDialogBaseButtonItem.Create(td.Buttons);
但这会引发不同的运行时错误:
无效的属性值
这是因为
Buttons
集合实际上需要 TTaskDialogButtonItem
,它是 TTaskDialogBaseButtonItem
的后代:
tb := TTaskDialogButtonItem.Create(td.Buttons);
现在代码将运行而不会崩溃。 但是,您的对话框将有第三个不需要的按钮!
您还会造成内存泄漏,因为您将
tb
指定为指向一个对象,然后立即将其重新指定为指向这一行上的另一个对象:
tb := td.Buttons.Add;
您根本不需要手动创建任何按钮对象。 让对话框为您创建按钮。
试试这个:
procedure TForm1.ShowDialog(amount: Integer);
var
td: TTaskDialog;
tb: TTaskDialogBaseButtonItem;
begin
td := TTaskDialog.Create(nil);
try
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;
end;
end;