2017-05-08 1 views
0

要約: 1つのフォーム(ローンフォーム)は、DatePickerFormという名前のモーダルフォームをユーザーが特定のボタンをクリックすると動的に作成します。 DatePickerFormで日付を選択すると、ユーザーはそのフォームの「閉じる」ボタンをクリックします。(BitBtn) - これが原因でアクセス違反エラーが発生します。- 動的に作成されたモーダルフォームを閉じるとアクセス違反が発生する

詳細:

再利用可能なモーダルDatePickerFormの目的は、特別な状況で日付を入力する一貫した方法をユーザーに提供することです。それは、他の複数の状況で使用されます。つまり、計画通りに動作させるとします。

正確なエラーテキストは次のとおりです: "プロジェクトABCD.exeが例外クラス$ C0000005を発生させました。 '0x0060d0b1にアクセス違反がありました:0x00000000のアドレスが読み取られました。

コードをコンパイルし、プログラムが正常に動作するまで以下のステップ4:

ランタイムプロセス:

  1. ローンフォーム上のボタンをユーザがクリック(作品)
  2. モーダルフォームDatePickerFormが作成され(所有者:アプリケーション)、次に表示されます。 (works
  3. ユーザーは、DatePickerコントロールから日付を選択します。 OKボタンを
  4. ユーザーがクリック(を失敗した)
  5. を作品)DatePickerFormを閉じる必要がありますし、我々はローンのフォームに戻す必要があります - しかし、エラーが代わりに発生します。
  6. 次のステップは、日付ピッカーのフォーム日付ピッカーコントロールにはまだ日付を読み込むことになる
  7. (フォームがまだ存在し、それはこの時点でちょうど見えない)

私の質問

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. 

答えて

2

documentationは言います:

アプリケーションでCloseModalを呼び出さないでください。 CloseModalは、モーダルフォームを閉じる必要があるときにVCLによって使用されます。 CloseModalは単独でフォームを閉じません。単に登録された終了イベントを呼び出し、ModalResultプロパティを更新します。

だから、そう言います。フォームのModalResultプロパティを設定してモーダルフォームを閉じます。

これを行う最も簡単な方法は、ボタンOnClickイベントハンドラを削除することです。代わりに、デザイナーのボタンのModalResultプロパティを設定します。

+0

おかげでデビッド - それをやった!!!!私は間違いなくこれをさらに研究しなければなりません(私は物事の仕組みを理解していないのは嫌です)。ありがとう - ジョン –

0

エラーメッセージから、nilポインターにアクセスしていることが明らかです。

procedure TfmDatePicker_Popup.btnOKClick(Sender: TObject); 
begin 
    fmDatePicker_Popup.CloseModal; // <-- fmDatePicker_Popup is not assigned! 
end; 
:あなたが開始するために、実際に有効なFormオブジェクトを指していないグローバル fmDatePicker_Popupオブジェクトポインタに(あなたが最初の場所で直接呼び出すべきではありません) CloseModal()を呼び出しているので、その理由は

procedure TfmLoan.btnSetDefaultClick(Sender: TObject); 
begin 
    DatePickerForm := TfmDatePicker_Popup.Create(Application); // <-- 
    ... 
end; 

:あなたのTfmDatePicker_Popupオブジェクトを作成するときにbtnSetDefaultClick()で、あなたの代わりにfmDatePicker_Popup変数の異なるDatePickerForm変数に代入されているのでfmDatePicker_Popupnilある

理由がありますは、の外部ポインタにはまったく依存してはいけません。

procedure TfmDatePicker_Popup.btnOKClick(Sender: TObject); 
begin 
    Self.CloseModal; 
end; 

それとも単に:btnOKClick()が、それは代わりに暗黙のSelfポインタ使用する必要があり、TfmDatePicker_Popupクラスのメンバーであるので、言われていること

procedure TfmDatePicker_Popup.btnOKClick(Sender: TObject); 
begin 
    CloseModal; 
end; 

を、CloseModal()はとにかく呼び出すために間違ったことです。実際にフォームを閉じるわけではなく、フォームのOnCloseイベントをトリガするだけです。 ShowModal()マニュアルに従って:

モーダルフォームを閉じるには、はゼロ以外の値にそのModalResultプロパティを設定します。それはModalResultがゼロになったことを検出するとき

ShowModal()は、内部CloseModal()を呼び出します。OnCloseイベントハンドラがActionパラメータをcaNoneに設定した場合、ModalResultは0にリセットされ、フォームは閉じられません。ドキュメントがに言うよう

ので、代わりにフォームのModalResultプロパティを使用します。その後、(完全OnClickハンドラを削除し、代わりにゼロ以外の値にボタンのModalResultプロパティを設定することで自動化することができる

procedure TfmDatePicker_Popup.btnOKClick(Sender: TObject); 
begin 
    Self.ModalResult := mrOk; 
end; 

TBitBtnの場合はプロパティを設定し、ModalResultも設定します)。モーダルフォーム上のボタンをクリックすると、OnClickイベントがトリガーされる前に、親フォームのModalResultに自身のModalResultが割り当てられます。

そして、あなたはまた、代わりに、より多くの本のように見えるようにbtnSetDefaultClick()を変更する必要があります。

procedure TfmLoan.btnSetDefaultClick(Sender: TObject); 
var 
    DatePickerForm: TfmDatePicker_Popup; 
begin 
    DatePickerForm := TfmDatePicker_Popup.Create(nil); 
    try 
    DatePickerForm.DTDatePicker.Date := GD_ProcessDate; 
    if DatePickerForm.ShowModal = mrOk then 
     dDefaultDate := DatePickerForm.DTDatePicker.Date; 
    finally 
    DatePickerForm.Free; 
    end; 
end; 
+0

レミー - 説明のためにありがとう。それはまさに私が理解する必要があったものです(私はそれを正しく考えていることを完全に確信して使いこなす前に、それについて考えて実験しなければなりません) –

関連する問題