要点: 一个表单(Loan Form)动态创建一个名为DatePickerForm的模态表单(当用户单击特定按钮时)。 在DatePickerForm中选择日期后,用户点击该表单'关闭' button:(a BitBtn) - 这是导致访问冲突错误的原因。
详细信息:
可重用模式DatePickerForm的目的是为用户提供在特殊情况下输入日期的一致方法。它将用于多种其他情况 - 也就是说,如果我按计划运行它。
确切的错误文本是:"项目ABCD.exe引发异常类$ C0000005,并在0x0060d0b1处发出消息'访问冲突:读取地址0x00000000'。"
代码编译,程序正常工作,直到下面的步骤4:
运行时过程:
我的问题:
A)这应该有效还是我使用动态表单创建不正确?
B)有没有更好的方法来实现这一目标?
任何帮助将不胜感激。
约翰
DatePickerForm代码(完整):
unit DatePicker_PopupForm;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.Buttons, Vcl.ComCtrls;
type
TfmDatePicker_Popup = class(TForm)
DTDatePicker: TDateTimePicker;
lblDatePrompt: TLabel;
btnOK: TBitBtn;
procedure btnOKClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
fmDatePicker_Popup: TfmDatePicker_Popup;
implementation
{$R *.dfm}
procedure TfmDatePicker_Popup.btnOKClick(Sender: TObject);
begin
fmDatePicker_Popup.CloseModal;
end;
end.
贷款表格 - 部分代码(完整代码约为9700行)
unit LoanForm;
interface
uses
Winapi.Windows, ......, DatePicker_PopupForm;
...
implementation
...
procedure TfmLoan.btnSetDefaultClick(Sender: TObject);
begin
DatePickerForm := TfmDatePicker_Popup.Create(Application);
DatePickerForm.DTDatePicker.Date := GD_ProcessDate;
DatePickerForm.ShowModal;
dDefaultDate := DatePickerForm.DTDatePicker.Date;
end;
...
end.
答案 0 :(得分:2)
不要在您的应用程序中调用CloseModal。当需要关闭模态表单时,VCL使用CloseModal。 CloseModal不会自动关闭表单;它只是调用已注册的close事件并更新ModalResult属性。
所以,就像它说的那样。通过设置表单的ModalResult
属性来关闭模式表单。
最简单的方法是删除按钮OnClick
事件处理程序。而是在设计器中设置按钮的ModalResult
属性。
答案 1 :(得分:0)
从错误消息中可以清楚地看到您正在访问nil
指针。原因是你在一个全局CloseModal()
对象指针上调用fmDatePicker_Popup
(你不应该直接调用它),该指针实际上并没有指向一个有效的Form对象来开始用:
procedure TfmDatePicker_Popup.btnOKClick(Sender: TObject);
begin
fmDatePicker_Popup.CloseModal; // <-- fmDatePicker_Popup is not assigned!
end;
fmDatePicker_Popup
nil
的原因是因为在btnSetDefaultClick()
中,当您创建TfmDatePicker_Popup
对象时,您将其分配给不同的DatePickerForm
变量fmDatePicker_Popup
变量:
procedure TfmLoan.btnSetDefaultClick(Sender: TObject);
begin
DatePickerForm := TfmDatePicker_Popup.Create(Application); // <--
...
end;
TfmDatePicker_Popup
根本不应该依赖任何外部指针。由于btnOKClick()
是TfmDatePicker_Popup
类的成员,因此它应该使用隐式Self
指针:
procedure TfmDatePicker_Popup.btnOKClick(Sender: TObject);
begin
Self.CloseModal;
end;
或者简单地说:
procedure TfmDatePicker_Popup.btnOKClick(Sender: TObject);
begin
CloseModal;
end;
话虽如此,CloseModal()
无论如何都是错误的。它实际上并没有关闭表单,只是触发了Form OnClose
事件。根据{{3}}文档:
要关闭模式表单,将其
ModalResult
属性设置为非零值。
ShowModal()
在检测到CloseModal()
已变为非零时在内部调用ModalResult
。如果OnClose
事件处理程序将其Action
参数设置为caNone
,则ModalResult
将重置为0并且表单未关闭。
因此,请使用表单的ModalResult
属性,就像文档中所说:
procedure TfmDatePicker_Popup.btnOKClick(Sender: TObject);
begin
Self.ModalResult := mrOk;
end;
然后可以通过完全删除OnClick
处理程序并将按钮的ModalResult
属性设置为非零值(或者在{{1}的情况下)来实现自动化},设置其TBitBtn
属性,该属性也设置其Kind
)。当点击模态表单上的按钮时,它会在触发其ModalResult
事件之前将其自己的ModalResult
指定给其父表单ModalResult
。
然后,您还应该将OnClick
更改为更像这样:
btnSetDefaultClick()