2017-05-08 2 views
0

Zusammenfassung: ein Formular (Loan Form) erstellt dynamisch ein modales Formular namens DatePickerForm (wenn Benutzer auf eine bestimmte Schaltfläche klickt). Nach der Auswahl eines Datums in der DatePickerForm klickt der Benutzer auf die Schaltfläche "Schließen" des Formulars: (a BitBtn) - dies verursacht einen Zugriffsverletzungsfehler.Delphi (Seattle) - Schließen eines dynamisch erstellten modalen Formulars verursacht Zugriffsverletzung

Details:

Der Zweck des wieder verwendbaren modal DatePickerForm ist der Eingabe Daten unter besonderen Umständen Benutzer eine einheitliche Art und Weise zur Verfügung zu stellen. Es wird in mehreren anderen Situationen verwendet werden - das heißt, wenn ich es wie geplant zum Laufen bekomme.

Genauer Fehlertext ist: "Projekt ABCD.exe ausgelöst Ausnahmeklasse $ C0000005 mit Meldung 'Zugriffsverletzung bei 0x0060d0b1: Lesen der Adresse 0x00000000'."

Der Code kompiliert und das Programm funktioniert gut, bis Schritt 4 unter:

Laufzeit Prozess:

  1. Der Benutzer klickt auf eine Schaltfläche auf der Leihformular (arbeitet)
  2. Das modale Formular DatePickerForm wird erstellt (Besitzer: Application) und dann angezeigt. (funktioniert)
  3. Der Benutzer wählt ein Datum aus dem DatePicker-Steuerelement aus. (arbeitet)
  4. Der Benutzer klickt auf die Schaltfläche OK (nicht)
  5. Die DatePickerForm schließen und wir sollten auf die Loan Form zurückkehren - aber der Fehler auftritt statt.
  6. Der nächste Schritt noch das Datum lesen würde auf dem Formular Datepicker Kontrolle des Datepicker (die Form noch vorhanden ist, ist es an dieser Stelle nur unsichtbar ist)

Meine Fragen:

A) Sollte das funktionieren oder verwende ich dynamische Formularerstellung falsch?

B) Gibt es einen besseren Weg, dies zu erreichen?

Jede Hilfe wird geschätzt.

John

DatePickerForm Code (gesamt):

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. 

Leihformular - Teilcode (vollständige Code ist in etwa 9700 Zeilen lang)

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. 

Antwort

2

Die documentation sagt :

Rufen Sie CloseModal nicht in Ihrer Anwendung auf. CloseModal wird von der VCL verwendet, wenn ein modales Formular geschlossen werden muss. CloseModal schließt das Formular nicht selbst; Es ruft einfach die registrierten Close-Events auf und aktualisiert die ModalResult-Eigenschaft.

Also, wie es heißt. Schließen Sie ein modales Formular, indem Sie die Eigenschaft ModalResult des Formulars festlegen.

Der einfachste Weg, um dies zu tun ist, um die Schaltfläche Event-Handler zu entfernen. Setzen Sie stattdessen die Eigenschaft ModalResult der Schaltfläche im Designer.

+0

Dank David - das tat es !!!! Ich werde das definitiv weiter studieren müssen (ich hasse es nicht zu verstehen, wie die Dinge funktionieren). Danke - John –

0

Aus der Fehlermeldung geht hervor, dass Sie auf einen Zeiger nil zugreifen. Und der Grund dafür ist, weil Sie CloseModal() fordern (die Sie sollten nicht direkt an erster Stelle anrufen) auf einem globalen fmDatePicker_Popup Objektzeiger, der nicht tatsächlich auf ein gültiges Objekt zeigt beginnen mit:

procedure TfmDatePicker_Popup.btnOKClick(Sender: TObject); 
begin 
    fmDatePicker_Popup.CloseModal; // <-- fmDatePicker_Popup is not assigned! 
end; 

der Grund fmDatePicker_Popup ist nil ist, weil in btnSetDefaultClick(), wenn Sie Ihr TfmDatePicker_Popup-Objekt erstellen, können Sie es auf einen anderen DatePickerForm Variable anstelle den fmDatePicker_Popup Variable zuweisen:

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

TfmDatePicker_Popup sollte sich nicht auf irgendwelche externe Zeiger auf sich selbst verlassen.

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

Oder einfach: Da btnOKClick() ein Mitglied der TfmDatePicker_Popup Klasse ist, sollte es stattdessen mit dem impliziten Self Zeiger sein

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

aber sagen, dass CloseModal() die falsche Sache ist sowieso zu nennen. Das Formular wird nicht geschlossen, sondern nur das Ereignis OnClose des Formulars ausgelöst. Per der ShowModal() Dokumentation:

Um ein modales Formular zu schließen, legen Sie seine ModalResult Eigenschaft auf einen Wert ungleich Null.

ShowModal() ruft intern CloseModal(), wenn es die erkennt ModalResult Nicht-Null geworden ist.Wenn der OnClose Event-Handler seinen Action-Parameter auf caNone setzt, wird ModalResult auf 0 zurückgesetzt und das Formular wird nicht geschlossen.

So das ModalResult Eigenschaft des Formulars verwenden, anstatt wie die Dokumentation sagt:

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

die dann durch Entfernen der OnClick Handler ganz automatisiert werden kann und stattdessen die ModalResult Eigenschaft auf einen Wert ungleich Null der Schaltfläche Einstellung (oder, im Fall von TBitBtn, setzen Sie seine Kind Eigenschaft, die auch seine ModalResult setzt). Wenn auf eine Schaltfläche in einem modalen Formular geklickt wird, weist sie ModalResult dem übergeordneten Formular ModalResult zu, bevor das Ereignis ausgelöst wird.

Und dann sollten Sie auch btnSetDefaultClick() ändern eher wie dieses stattdessen aussehen:

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

Remy - danke für die Erklärung. Das ist genau das, was ich verstehen musste (ich werde einige Zeit darüber nachdenken und experimentieren müssen, bevor ich mich sicher fühle, es mit absoluter Sicherheit zu benutzen, dass ich es richtig mache) –

Verwandte Themen