Delphi-PRAXiS

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/)
-   -   Formular modal öffnen (https://www.delphipraxis.net/186464-formular-modal-oeffnen.html)

Sankt Rochus 4. Sep 2015 11:28

Formular modal öffnen
 
Hallo,

ich bin eigentlich kein grober Neuling in Delphi und scheitere doch an den einfachsten Problemen, dank dieses neuen tollen FireMonkey-Frameworks...

Ich habe eine Formularklasse TfLabTokenMapping. Darin enthalten ist eine Klassenfunktion, die die Klasse instanziiert und das Formular modal anzeigen soll. Es handelt sich um einen Konfigurationsdialog, bei dem ein String mit Einstellungen (MappingList) und ein boolesches Result (False = Klick auf Abbrechen) zurückgegeben werden sollen. Die Klassenfunktion wird von einer Methode im Hauptformular mit einigen, hier im Detail unwichtigen Parametern aufgerufen.

Konkret geht es mir um den hier korrekten Aufruf von ShowModal(...) und bestenfalls noch um das Freigeben des Speichers. Ich habe zwei Varianten ausprobiert.

Variante 1: ShowModal mit anonymer Funktion aufrufen. Ich bin kein Freund davon, doch ist das wohl der von Embarcadero empfohlene Weg. Die Variablen aNewMappingList und Result können nicht direkt von der anonymen Funktion aufgenommen werden (Compilerfehler). Deshalb lege ich sie erst in lokale Variablen ab, die ich anschließend kopiere.

Delphi-Quellcode:
class function TfLabTokensMapping.ChangeMapping(aRequiredLabParams, aCurrentMappingList, aAllLabTokensWithDesc: string; out aNewMappingList: string): Boolean;
var
  fLabTokensMapping: TfLabTokensMapping;
  l_NewMappingList: string;
  l_Result: Boolean;
begin
  // Nur etwas initialisieren und eine Parameterprüfung
  Result := False;
  aNewMappingList := EmptyStr;
  if Length(Trim(aRequiredLabParams)) = 0 then
    Exit;

  // Das Formular erzeugen
  fLabTokensMapping := TfLabTokensMapping.Create(nil, aRequiredLabParams, aCurrentMappingList, aAllLabTokensWithDesc);

  // Das Formular anzeigen
  fLabTokensMapping.ShowModal(
    procedure(ModalResult: TModalResult)
    begin
      if (ModalResult = mrOk) then
      begin
        l_NewMappingList := fLabTokensMapping.Mapping;
        l_Result := True;
      end
      else
      begin
        l_Result := False;
      end;
    end);

  // Werte zurück geben
  aNewMappingList := l_NewMappingList;
  Result := l_Result;
end;
Problem dabei ist, dass ShowModal in diesem Fall nicht modal / blockierend ausgeführt wird. Frechheit von FireMonkey. Damit rattert mein Code durch und selbst die aufrufende Methode wird weiter fortgesetzt. Natürlich sind aNewMappingList und Result dann noch nicht gesetzt worden. Kann ich das Blockieren irgendwie erzwingen?

Variante 2: So, wie ich das aus der VCL gewohnt bin:

Delphi-Quellcode:
class function TfLabTokensMapping.ChangeMapping(aRequiredLabParams, aCurrentMappingList, aAllLabTokensWithDesc: string; out aNewMappingList: string): Boolean;
var
  fLabTokensMapping: TfLabTokensMapping;
  l_NewMappingList: string;
  l_Result: Boolean;
begin
  // Nor Initialisierungen und eine Parameterprüfung
  Result := False;
  aNewMappingList := EmptyStr;
  if Length(Trim(aRequiredLabParams)) = 0 then
    Exit;

  // Das Formular erzeugen
  fLabTokensMapping := TfLabTokensMapping.Create(nil, aRequiredLabParams, aCurrentMappingList, aAllLabTokensWithDesc);

  // Formular anzeigen und Ergebnis zurück geben
  if (fLabTokensMapping.ShowModal = mrOk) then
  begin
    aNewMappingList := fLabTokensMapping.Mapping;
    Result := True;
  end
  else
  begin
    Result := False;
  end;
end;
Jetzt blockiert ShowModal auch. Jedoch bekommen ich nun seltsames Verhalten nach Rückkehr zu meinem Hauptformular. Irgendwie scheinen einige Messages nicht mehr verarbeitet zu werden. Button-Klicks machen nichts mehr, Hover-Events und das Verschieben des Formulars funktionieren noch. Seltsam.

Das modale Fenster gebe ich übrigens in beiden Varianten per FormClose() frei:

Delphi-Quellcode:
procedure TfLabTokensMapping.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action := TCloseAction.caFree;
end;
Was kann ich tun? Weiß irgendjemand Rat?

Vielen Dank schon einmal.

Uwe Raabe 4. Sep 2015 11:44

AW: Formular modal öffnen
 
Zitat:

Zitat von Sankt Rochus (Beitrag 1314679)
Problem dabei ist, dass ShowModal in diesem Fall nicht modal / blockierend ausgeführt wird. Frechheit von FireMonkey. Damit rattert mein Code durch und selbst die aufrufende Methode wird weiter fortgesetzt. Natürlich sind aNewMappingList und Result dann noch nicht gesetzt worden. Kann ich das Blockieren irgendwie erzwingen?

Das ist nicht FireMonkey geschuldet, sondern der Zielplattform, die sowas wie einen modalen Dialog nicht kennt. Ein blockierendes ShowModal kann auf einem solchen System schlichtweg nicht implementiert werden. Du musst also notgedrungen die eingefahrenen VCL/Windows-Wege verlassen und Neuland betreten. Das heißt eben auch, daß man die gewohnten Abläufe durch andere Ansätze ersetzt.

Rollo62 4. Sep 2015 11:51

AW: Formular modal öffnen
 
Du musst dich besser generell dran gewöhnen das ShowModal auf iOS und Android verboten ist.
Also besser so machen wie Sir Rufo das hier schön beschreibt.
Oder direkt mit einer anonymen Prozedur hinten dran.

Rollo

Sankt Rochus 4. Sep 2015 13:15

AW: Formular modal öffnen
 
Okay, danke schon mal für eure Antworten.

Das ist aber natürlich schade, dass es kein ShowModal mehr gibt ): Ich bin immer mehr der Meinung, dass sich der Einsatz von FireMonkey nur lohnt (und sonst nur Ärger macht), wenn man wirklich für verschiedene Plattformen entwickelt, was wir leider nicht tun. Wieso dann Firemonkey? War nicht meine Entscheidung, und lässt sich jetzt auch nicht mehr so schnell umändern. Okay, zur Sache...

Aktuell werden vom Hauptformular, das die beschriebene Mathode aufruft, die Einstellungen entgegen genommen und in einer Datei gespeichert. Jetzt würde ich das spontan so umbauen, dass das Hauptformular die Methode aufruft und wie von Sir Rufo beschrieben eine Call-Back-Funtion übergibt, die dann von der anonymen Funktion im ShowModal(...) aufgerufen wird und die die Einstellungen in die Datei schreibt.

Hoffe, dass das funktionieren wird.

Danke euch vielmals.

Mavarik 4. Sep 2015 13:23

AW: Formular modal öffnen
 
Zitat:

Zitat von Sankt Rochus (Beitrag 1314707)
Wieso dann Firemonkey?

:glaskugel: Ein Grund könnte sein, damit man weg kommt von der strengen Bindung zur Windows API/VCL. Ist sicherlich Zukunftsorientiert!

Rollo62 4. Sep 2015 14:29

AW: Formular modal öffnen
 
Zitat:

Das ist aber natürlich schade, dass es kein ShowModal mehr gibt ):
Das fehlt mir nicht:
Denn mit den neuen anonymen Prozeduren bleiben ShowMessage etc. erhalten wie bisher,
nur eben nicht Modal --> so das die Anwendung responsiv bleibt.

Das ist nicht nur gut für iOS und Android, auch Win Anwendungen sind besser wenn nicht bis zum Klick alles
blockiert wird.

Da muss man mal ein bischen Umdenken, aber es lohnt sich die alten Zöpfe abzuschneiden.

Rollo

Sankt Rochus 4. Sep 2015 14:43

AW: Formular modal öffnen
 
Zitat:

Ein Grund könnte sein, damit man weg kommt von der strengen Bindung zur Windows API/VCL. Ist sicherlich Zukunftsorientiert!
Klar, für Windows 11 hat Microsoft ja bereits die Windows API abgekündigt :wink:

Das Projekt, das ich betreue, habe ich von meinem Kollegen übernommen, der (meine ich) auf FireMonkey aufgestiegen ist, weil er neugierig war. Finde ich grundsätzlich auch die richtige Einstellung. Nur gingen bei uns einfach schon etliche Stunden / Tage ins Land, um Firemonkey-Probleme zu lösen, die aus meiner Sicht sich nicht immer mit unserer anfänglichen FMX-Unkenntnis begründen liesen.

Um ganz ehrlich zu sein ... würde ich heute ein Projekt ganz neu starten, und wäre Plattformunabhängigkeit kein Thema, wohl aber Effizienz und Zukunftssicherheit, ich ginge vermutlich auf die Microsoft-Schiene, C#.NET oder so. Das ist jetzt natürlich meine ganz persönliche Meinung und wurde hier bestimmt schon ganz oft diskutiert :-D Als mehrjähriger Delphi-Entwickler kann ich sagen, dass Delphi an sich toll ist :) Doch den immer von Embarcadero propagierten "stark wachsenden Markt" kann ich bei den Embarcadero-Produkten aktuell leider nicht sehen. Ich habe die Befürchtung, dass Embarcadero weiterhin Marktanteile verlieren wird und deshalb letztlich zuerst die Qualitätssicherung, später dann die komplette Neuentwicklung bei Embarcadero zurückgehen wird. Ersteres ist IMHO jetzt schon teilweise der Fall. Zumindest die Codegear-Zeiten haben Delphi wirklich nicht gut getan. Microsoft dagegen ist für mich bekannt für einwandfrei integrierte (Microsoft-Landschaft halt), robuste und effiziente Lösungen für die Entwicklung. Microsoft ist stark hinterher, Fehler zu korrigieren, und die Dokumentationen sind sehr ausführlich. Zudem bietet Microsoft das meiste kostenlos an (Windows wird billger / kostenloses Upgrade, Visual-Studio Express-Editions, Dreamspark für Schüler / Studenten) etc.. . Und auch wenn Microsoft der "böse Gigant" ist, gefällt mir Microsofts Produktstrategie meistens ganz gut.

Okay, entschuldigt den Off-Topic :)

Uwe Raabe 4. Sep 2015 15:17

AW: Formular modal öffnen
 
Zitat:

Zitat von Sankt Rochus (Beitrag 1314707)
Das ist aber natürlich schade, dass es kein ShowModal mehr gibt ): Ich bin immer mehr der Meinung, dass sich der Einsatz von FireMonkey nur lohnt (und sonst nur Ärger macht), wenn man wirklich für verschiedene Plattformen entwickelt, was wir leider nicht tun.

Dann verstehe ich das Problem nicht: Unter Windows funktioniert das alte parameterlose FMX-ShowModal doch genauso wie in der VCL!

Sankt Rochus 7. Sep 2015 13:12

AW: Formular modal öffnen
 
Zitat:

Dann verstehe ich das Problem nicht: Unter Windows funktioniert das alte parameterlose FMX-ShowModal doch genauso wie in der VCL!
Hallo Uwe Raabe,

danke für deine Antwort.

Ich dachte auch zunächst, das ShowModal ohne anonyme Funktion entspräche absolut der Fuktionalität wie in der VCL. Tatsächlich bekomme ich, sofern ich das Formular auch irgendwie freigeben möchte, jedoch immer unerwartetes Verhalten. Ich habe schon verschiedene Möglichkeiten ausprobiert, bis hin das Formular gar nicht freizugeben (Nicht schön, aber besser als nichts.).

Das modale Fenster mag sich auch schließen, doch mal bekomme ich dann in Events (Hover etc...) des Hauptformulars seltsame Zugriffsverletzungen, mal frieren Teile der UI ein, da manche Events offenbar gar nicht mehr getriggert werden (z.B. Click bei manchen Buttons), mal läuft irgendwas mit den Styles schief, sodass anstatt des Iceberg-Blaus plötzlich alles schwarz wird, mal crasht die ganze Anwendung.

Kurzum, alles lässt mich darauf schließen, dass Firemonkey intern ein per ShowModal(<Keine Parameter>) angezeigtes Fenster nicht richtig verwaltet, zumindest nicht so wie in der VCL. Ich habe schon jahrelange VCL-Erfahrung und müsste eigentlich wissen, wie man ein Fenster auf macht (Wenn die Luft im Büro stickig ist ;) ), aber ich lass mich natürlich gerne eines besseren belehren, vlt. mache ich tatsächlich etwas falsch.

Ich habe in meinem Eingangspost unter "Variante 2" meinen VCL-Code gepostet. Siehst du (oder jemand anders) darin einen Fehler?

Danke schon einmal.

himitsu 7. Sep 2015 15:03

AW: Formular modal öffnen
 
Man könnte auch auf die saudumme Idee kommen und dem blöden FMX modal beizubringen? :freak:

z.B. in etwa so (rein schematisch)
Delphi-Quellcode:
var
  WarteVariable: TModalResult;

WarteVariable := mrNone;
MeinDialog.ShowModal(
  procedure(ModalResult: TModalResult)
  begin
    WarteVariable := ModalResult;
  end);
while (WarteVariable = mrNone) and not Application.Terminated do begin
  Application.ProgressMessages;
  Sleep(10);
end;
case WarteVariable of
  mrNone: Exit;
  mrOK: DoA;
  else DoB;
end;
Natürlich schön als als Methode "RealShowModal" per Class-Helper an alle Forms drangehangen.



"ShowModal" ist jedenfalls ein voll bescheuerter Name, denn eigentlich ist es doch ein
Delphi-Quellcode:
xxx.Show(OnClose: TCloseEvent);
.
Kein Wunder, wenn sich dann welche wundern, daß es doch nicht modal ist. :wall:

Mavarik 7. Sep 2015 16:48

AW: Formular modal öffnen
 
Zitat:

Zitat von himitsu (Beitrag 1314987)
Man könnte auch auf die saudumme Idee kommen und dem blöden FMX modal beizubringen? :freak:

FMX ist nicht blöde... Sondern Cross-Plattform compatible...

Um mit berühmten Worten zu Antworten : "Kaum macht man's richtig - schon funktioniert's"

Ein Repeat Processmessage Construct geht natürlich rein technisch gesehen... Aber wenn man so etwas braucht ist es einfach ein Designfehler! Vielleicht nicht unter Windows, aber auf jeden Fall um iOS/Android Umfeld.

Aber daher Funktioniert ein ShowModal unter Windows auch wie gewohnt...

Sankt Rochus 8. Sep 2015 11:18

AW: Formular modal öffnen
 
Danke euren Beiträgen.

Zitat:

Man könnte auch auf die saudumme Idee kommen und dem blöden FMX modal beizubringen?
:-D Das dachte ich mir auch schon. War mir dann aber wirklich zu dreckig diese Lösung :)
Ich weiß auch nicht, wie sich das von der Performance her verhalten würde.

Zitat:

"ShowModal" ist jedenfalls ein voll bescheuerter Name, denn eigentlich ist es doch ein xxx.Show(OnClose: TCloseEvent);
Meine Rede...

Zitat:

Um mit berühmten Worten zu Antworten : "Kaum macht man's richtig - schon funktioniert's"
Ja, wie denn?

Zitat:

Aber daher Funktioniert ein ShowModal unter Windows auch wie gewohnt...
Unter FMX? Wirklich? Dann sage mir bitte, wo bei mir der Fehler lag, oder wie du ein einfaches Fenster unter Nur-Windows-FMX auf und zu machen und anschließend freigeben würdest, ohne dass es mir danach an ganz anderen Stellen scheppert. Ich probiere das gerne aus.

Vielen Dank schon einmal.

Sankt Rochus 8. Sep 2015 15:01

AW: Formular modal öffnen
 
Ich habe das mit dem reinen ShowModal() ohne Parameter jetzt nochmals ausprobiert. Dazu habe ich auf mein Hauptformular einen Button btn1 gelegt das ein Testformular öffnet. Ich bekomme es nicht hin :cry:

Delphi-Quellcode:
procedure TfMain.btn1Click(Sender: TObject);
var
  l_TestFormular: TTestFormular;
begin
  l_TestFormular := TTestFormular.Create(nil);
  l_TestFormular.ShowModal;
  l_TestFormular.Release;
end;
Das Testformular selbst enthält wirklich NUR einen Label mit dem Text "Dies ist ein Testformular" und einen Button, bei dessen Klick Close() aufgerufen wird. Das Fenster öffnet auch und schließt sich wieder, doch dann bekomme ich plötzlich herbe Style-Fehler in meinem Hauptformular. Kann das so schwer sein?

Muss ich vlt. einen Owner mit angeben? Das war so weit ich weiß in der VCL nicht nötig. Muss ich etwa statt Release Free oder FreeAndNil verwenden oder gar das Formular an dieser Stelle gar nicht freigeben, sondern stattdessen im FormClose-Event ein
Delphi-Quellcode:
Action := TCloseAction.caFree;
? Alles ausprobiert, doch ohne Erfolg.

Edit:
Okay, ich habe nun einen sicheren Verdacht. Wir verwenden auf dem Hauptformular ein StyleBook als Non-visible-Component, die ich bisher immer im Designer auf neue Formulare kopiert habe. Jedoch scheinen die Kopien keine echten Kopien zu sein, sondern Referenzen, sodass beim Free das Stylebook mit freigegeben wird. Wie mache ich so etwas denn richtig? Es mag sein, dass das Stylebook-Copy-Past nicht der beste Weg ist.

Sir Rufo 8. Sep 2015 15:28

AW: Formular modal öffnen
 
Also es gibt im Prinzip erst einmal kein Problem mit dem ShowModal:
Delphi-Quellcode:
unit Dialogs.FooDialog;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs,
  FMX.Controls.Presentation, FMX.StdCtrls;

type
  TFooDialog = class( TForm )
    Button1: TButton; { ModalResult := mrOK; }
    procedure FormDestroy( Sender: TObject );
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  FooDialog: TFooDialog;

implementation

{$R *.fmx}

procedure TFooDialog.FormDestroy( Sender: TObject );
begin
  ShowMessage( 'Going to Nirwana' );
end;

end.
und
Delphi-Quellcode:
unit Forms.MainForm;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs,
  FMX.Controls.Presentation, FMX.StdCtrls;

type
  TMainForm = class( TForm )
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click( Sender: TObject );
    procedure Button2Click( Sender: TObject );
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  MainForm: TMainForm;

implementation

{$R *.fmx}

uses
  Dialogs.FooDialog;

{Variante 1}
procedure TMainForm.Button1Click( Sender: TObject );
var
  LDialog: TFooDialog;
begin
  LDialog := TFooDialog.Create( nil );
  try
    LDialog.ShowModal;
  finally
    LDialog.DisposeOf;
  end;
end;

{Variante 2}
procedure TMainForm.Button2Click( Sender: TObject );
var
  LOuter, LInner: TFooDialog;
begin
  LOuter := TFooDialog.Create( nil );
  try
    LInner := LOuter;
    LInner.ShowModal(
      procedure( r: TModalResult )
      begin
        LInner.Release;
      end );
    LOuter := nil;
  finally
    LOuter.DisposeOf;
  end;
end;

end.
Sowohl Variante1 als auch Variante2 funktionieren erstmal ohne Auffälligkeiten.

Aber bei Variante2 (unter Windows/OSX)
  • ist die Form nicht wirklich modal! Man kann zwischen den Formularen hin und her wechseln
  • ruft ein simples
    Delphi-Quellcode:
    Close
    nicht die
    Delphi-Quellcode:
    ResultProc
    auf

himitsu 9. Sep 2015 10:36

AW: Formular modal öffnen
 
Zitat:

Zitat von Mavarik (Beitrag 1315000)
FMX ist nicht blöde... Sondern Cross-Plattform compatible...

Um mit berühmten Worten zu Antworten : "Kaum macht man's richtig - schon funktioniert's"

Doch?

FMX hat einen Befehl der ShowModal heißt, aber nicht Modal ist.
Entweder umbenennen/weglassen oder irgendwie dafür sorgen, daß er "wie" modal arbeitet, also auf das Schließen des Dialogs wartet.
Somit stimmt der Satz ... würde jemand (Emba) es richtig machen, dann würde es bestimmt auch funktionieren. :zwinker:


Alle Zeitangaben in WEZ +1. Es ist jetzt 22:00 Uhr.

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