Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi Form dynamisch erzeugen (https://www.delphipraxis.net/190567-form-dynamisch-erzeugen.html)

whiteF 16. Okt 2016 22:35

Form dynamisch erzeugen
 
Hallo,
ich möchte eine Form dynamisch erstellen lassen. Die dynamische Form namens "FormMessengerNW" habe ich bereits in Delphi erstellt und mit labels bestückt. Über eine public Variable bestimme ich einen Text den ich bei der Form "FormMessengerNW" beim OnShow einlesen/anzeigen möchte.
Die "FormMessengerNW" ist ein Hinweisfenster das am Rand eingeblendet wird und mit einem Timer nach ein paar sekunden wieder verschwindet (oder mittels close button).
Diese Form funktionierte an sich bereits als ich sie direkt aufrief, jedoch bekomme ich den dynamischen Aufruf nicht ganz hin.

Das hatte ich bereits probiert:

Form1
Delphi-Quellcode:
...
var
  FormMessengerNW_Instanz : TFormMessengerNW;
begin
...
    try
      showmessage('0');
      FormMessengerNW_Instanz := FormMessengerNW.Create(Application.MainForm);
      FormMessengerNW_Instanz.OnCreate:= FormMessengerNW.OnCreate;
      FormMessengerNW_Instanz.OnShow := FormMessengerNW.OnShow;
      FormMessengerNW_Instanz.OnClose := FormMessengerNW.OnClose;
    finally
    showmessage('1');
      FormMessengerNW_Instanz.Show;
      showmessage('2');
    end;
...
FormDyn
Delphi-Quellcode:
procedure TFormMessengerNW.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action := caFree;
  //FormMessengerNW.Release;
end;

procedure TFormMessengerNW.FormShow(Sender: TObject);
begin
  showmessage('form open');
end;

procedure TFormMessengerNW.FormCreate(Sender: TObject);
begin

  (Sender as TForm).AlphaBlendValue := 235;

  lblTitle.Left := 35;

  imgClose0.Top := imgClose0.Top;
  imgClose0.Left := 324;
  imgClose1.Top := imgClose0.Top;
  imgClose1.Left := imgClose0.Left;

  reMessage.Width := 323;
  reMessage.Left  := 15;
  reMessage.Top   := 30;
  reMessage.Height := 62;
end;
das showmessage "2" wird nicht mehr eingeblendet.
Es kommt immer "EAcces Vioalation"


Wie würdet ihr soetwas lösen?

VG

Jim Carrey 16. Okt 2016 22:38

AW: Form dynamisch erzeugen
 
Da es das Formular ja bereits gibt, probier statt
Delphi-Quellcode:
FormMessengerNW_Instanz := FormMessengerNW.Create(Application.MainForm);
FormMessengerNW_Instanz.Show;
mal
Delphi-Quellcode:
Application.CreateForm(TFormMessengerNW, FormMessengerNW);
FormMessengerNW_Instanz.Show;

Fritzew 16. Okt 2016 23:00

AW: Form dynamisch erzeugen
 
Deine Klasse ist ja TFormMessengerNW

Also musst Du auch eine Instance davon erzeugen.

Dein Aufruf von:


Delphi-Quellcode:
 FormMessengerNW_Instanz := FormMessengerNW.Create(Application.MainForm);
ruft auf der bestehenden Instance Create auf nicht den von der Klasse!!!
also ändere einfach zu:

Delphi-Quellcode:
 FormMessengerNW_Instanz := TFormMessengerNW.Create(Application.MainForm);
Achte auf das "T" in TFormMessengerNW.Create :-)

Meiner Meinung nach sollte das Aufrufen eines Constructors zumindest eine Hint liefern, aber man kann ja nicht alles haben ;-)

Jim Carrey 16. Okt 2016 23:17

AW: Form dynamisch erzeugen
 
Warum aber eine neue Variable der Klasse anlegen, wenn er doch eh schon eine hat?
Dann wäre folgendes doch viel sinniger:

Delphi-Quellcode:
Application.CreateForm(TFormMessengerNW, FormMessengerNW);

whiteF 17. Okt 2016 07:35

AW: Form dynamisch erzeugen
 
oh nein,
ich habe tatsächlich nur das "T" vergessen... vielen Dank! 4 Augen sehen mehr als 2. Jetzt klappts ohne EAccess Violation.

Da hätte ich dann noch eine kleine Anschlussfrage:

Wie spreche ich diese dynamisch erzeugte Form dann am besten an?

ich beende über ein ImgClick diese Form, das hatte bei direkter Formnutzung ja so geklappt (FormMessengerNW.Close;) und bei dynamischer?
und bei dynForm?
(Sender as TForm).Close; //wobei Sender nicht immer TForm ist
ThisForm.Close; // ;)


Ich steh da etwas auf dem Schlauch...

Ghostwalker 17. Okt 2016 08:27

AW: Form dynamisch erzeugen
 
Hi,

im Endeffekt genauso, wie du auf alle anderen Eigenschaften und Methoden zugreifen kannst, über die Instanz :)

Code:
FormMessengerNW.Close
bzw. über

Code:
FormMessengerNW.Hide
kannst du die Form wieder verschwinden lassen, ohne die Instanz zu löschen und beim nächsten
mal neu erzeugen zu müssen.

Jim Carrey 17. Okt 2016 11:08

AW: Form dynamisch erzeugen
 
Zitat:

Da hätte ich dann noch eine kleine Anschlussfrage:

Wie spreche ich diese dynamisch erzeugte Form dann am besten an?
Guck dir mal meinen Lösungsvorschlag an. Dann kannst du das Formular ansprechen wie jedes andere Formular auch und du brauchst keine extra Variable, welche total sinnlos ist.

Darlo 17. Okt 2016 11:12

AW: Form dynamisch erzeugen
 
Zitat:

Zitat von Jim Carrey (Beitrag 1351071)
Zitat:

Da hätte ich dann noch eine kleine Anschlussfrage:

Wie spreche ich diese dynamisch erzeugte Form dann am besten an?
Guck dir mal meinen Lösungsvorschlag an. Dann kannst du das Formular ansprechen wie jedes andere Formular auch und du brauchst keine extra Variable, welche total sinnlos ist.

Kommt natürlich darauf an wieviele parallele Instanzen benötigt werden.

whiteF 17. Okt 2016 22:57

AW: Form dynamisch erzeugen
 
Liste der Anhänge anzeigen (Anzahl: 1)
Also, da ich ja die Form mehrfach eingeblendet werden sollte bei meinem programm, dürfte ich ja für die form keinen festen Namen vergeben, sonst könnte ja in der 2.ten Instanz ja nicht mehr die Form created werden da ja der Name bereits existiert (vermute ich jetzt mal ganz stark).

Es funktionieren beide Varianten:

#1
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var
  FormMessengerNW_Instanz : TFormMessengerNW;
begin
  try
    FormMessengerNW_Instanz := TFormMessengerNW.Create(Application.MainForm);
  finally
    FormMessengerNW_Instanz.Show;
  end;
end;
#2
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
begin
  try
    Application.CreateForm(TFormMessengerNW, FormMessengerNW);
  finally
    FormMessengerNW.Show;
  end;
end;
Um die dynamisch erzeugte Form zu schliessen kommt es zum Teil drauf an wie diese erstellt worden ist.
Das klappt immer:
Delphi-Quellcode:
procedure TFormMessengerNW.Button1Click(Sender: TObject);
begin
  Self.Close;
end;
Das klappt nur in Verbindung mit der #2-Variante:
Delphi-Quellcode:
procedure TFormMessengerNW.Button1Click(Sender: TObject);
begin
  FormMessengerNW.Close; //Wenn mehrere Instanzen erstellt werden, gibt es hiermit jedoch Probleme
//das funktioniert aber auch: Self.Close; //Wenn mehrere Instanzen erstellt werden, gibt es hiermit KEINE Probleme
end;
Variante #2 kann hiermit gefunden (gelistet) werden kann //Variante #1 nicht... wieso nicht? :shock: :
Delphi-Quellcode:
procedure TForm1.Button11Click(Sender: TObject);
var
  i, ii: Integer;
begin
  Memo1.Clear;
  ii := 0;
  for i := 0 to Application.ComponentCount - 1 do
  begin
    if Application.Components[i] is TForm then
    begin
      Memo1.Lines.Add(Application.Components[i].Name);
      ii := ii + 1;
    end;
  end;
  Edit1.Text := IntToStr(ii);
end;
Das hier funktioniert für Variante #1 & #2
Delphi-Quellcode:
procedure TForm1.Button22Click(Sender: TObject);
var
  i, ii: Integer;
begin
  Memo1.Clear;
  ii := 0;
  for i := 0 to Screen.CustomFormCount - 1 do
  begin
    Memo1.Lines.Add(Screen.Forms[i].Name);
    ii := ii + 1;
  end;
  Edit1.Text := IntToStr(ii);
end;

Ein kleines praktisches Beispiel Projekt liegt anbei.

Redeemer 23. Okt 2016 21:35

AW: Form dynamisch erzeugen
 
Man erstellt grundsätzlich mit Application.CreateForm und referenziert die in sich mit Self (wobei man das auch weglassen kann, was das gleiche ergibt). Bei Application.CreateForm ist Application der Besitzer der Form. Beim direkten Aufruf von Create ist halt derjenige der Besitzer, den du angibst. Das Durchlaufen der Kindkomponenten von MainForm oder Application ist auch reichlich ineffizient. Man nimmt sich am ehesten eine TList oder ein Array.
Wenn du eine Form entwirfst, gibt dir Delphi eine Instanzvariable mit dem Namen der Form ohne T dran (denn T ist der uninstanzierte Typ). Heißt deine Form TFormMessengerNW, so heißt diese Variable also FormMessengerNW. Du musst die Instanz erst erstellen, das macht man mit Application.CreateForm.
Wenn du in deinem Code, wie du es machst, nicht Self sondern eine ganz bestimmte Instanzvariable, in dem Fall die vorgegebene FormMessengerNW, schließt, aber eine völlig andere Instanzvariable namens FormMessengerNW_Instanz erstellt hast, klappt das natürlich nicht.

Du benutzt zudem try-finally-Konstrukte komplett falsch. Der finally-Block wird immer aufgerufen, egal was im try-Block passiert. Schlägt das Erstellen der Form fehl, rufst du Show auf. Show schlägt fehl, weil die Instanz gar nicht erstellt wurde. Dein try-finally-Konstrukt bringt also absolut nichts. Daher haut dir der Compiler die erste Variante auch um die Ohren, denn das Create gehört niemals in dasselbe try-finally-Konstrukt wie jegliche Befehle, die darauf zugreifen. Wenn du im finally-Block auf etwas zugreifst, was du im try-Block erstellt hast, hast du ja überhaupt keine Ahnung, ob du das überhaupt erstellt hast oder nicht.


Alle Zeitangaben in WEZ +1. Es ist jetzt 00:16 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz