![]() |
Eine Art Semi-ShowModal?
Hallo,
wenn man ShowModal mit einem Dialog macht, ist z.B. das Hauptmenü nicht mehr zu bedienen. Klar.
Code:
Wenn ich das ganze durch Show ersetze, ist klar, rauscht er sofort durch MachDas;
procedure OnClick;
begin MachDies; Form.ShowModal; MachDas; end; Was wäre die eleganteste Variante, um das ShowModal durch Show zu ersetzen (um im Hintergrund das Hauptmenü nutzen zu können) und doch eine Art ShowModal zu haben, die wartet und dann MachDas; aufruft? Threads, Monitor,... Muss ja sicher im MainThread laufen |
AW: Eine Art Semi-ShowModal?
Eine Art OnClose-Handler als anonyme Methode? So ähnlich, wie es auf den mobilen Plattform für die MessageBox umgesetzt wurde. Das Form selbst würde dann mittels .Show() angezeigt und hätte je nach Bedarf sowas wie StayOnTop aktiv.
|
AW: Eine Art Semi-ShowModal?
Und warum nicht einfach "MachDas" in eine separate Unit auslagern, und dann aus der "modalen" Form - die ganz normal mit Show angezeigt wird - aufrufen?
|
AW: Eine Art Semi-ShowModal?
Zitat:
|
AW: Eine Art Semi-ShowModal?
Zitat:
|
AW: Eine Art Semi-ShowModal?
Delphi-Quellcode:
class TSemimodalForm (TForm);
private finished: boolean; public procedure WaitForMe; procedure show; override; procedure close; override; end; implementation procedure TSemimodalForm.WaitForMe; begin repeat sleep(200); application.processmessages; // bin nicht sicher, ob das hier nötig ist until finished; end; procedure TSemimodalForm.show; begin inherited; finished:=false; end; procedure TSemimodalForm.close; inherited; finished:=true; end; Die Forms, bei denen du das brauchst (hier Form2), von TSemiModalForm ableiten und aufrufen mit
Delphi-Quellcode:
Form2.Show;
Form2.WaitForMe; |
AW: Eine Art Semi-ShowModal?
Zitat:
Delphi-Quellcode:
begin
Form2.MyShowModal(Procedure begin // Mach hier das was Du nach dem Showmodal machen wolltest... end); end. |
AW: Eine Art Semi-ShowModal?
Evtl. Einen Timer verwenden der mit .OnShow gestartet wird?
Delphi-Quellcode:
procedure TFormNichtModal.FormShow(Sender: TObject);
begin MyTimer.Interval := 100; MyTimer.Enabled := True; end
Delphi-Quellcode:
procedure TFormNichtModal.MyTimerTimer(Sender: TObject);
begin if not FormNichtModal.Showing then begin Machdas; MyTimer.Enabled := False; end; end; |
AW: Eine Art Semi-ShowModal?
Es geht sogar noch einfacher, weil die Eigenschaft visible ohnehin durch show und close gesetzt wird.
Also kein Überschreiben von show und close nötig, sondern nur repeat ... until not visible. Die Form sollte aber nicht mit caFree geschlossen werden, sonst kann es knallen. |
AW: Eine Art Semi-ShowModal?
Zitat:
Es gibt schon Situationen, wo anonyme Methode etwas bringen, aber hier? Nur, um endlich einmal eine anonyme Methode verwenden zu können? Programmcode sollte meines Erachtens vor allem LESBAR sein, man sollte wenn möglich beim ersten Hinsehen erkennen, was passiert. Das ist bei Code, der als anonyme Methode im Parameter eines MyShowModal übergeben wird, sicher nicht im gleichen Ausmaß gegeben, als wenn man mittel Form.WaitForMe explizit auf das Beenden der Form wartet und dann im Code normal weitermacht. Wenn dich der Aufruf stört, dann könnte man eine Methode ShowSemiModal in Betracht ziehen, die erst zurückkehrt, wenn die Form geschlossen ist, die also den Code von WaitForMe am Ende beinhaltet. Abstrakte Methoden an die Form zu übergeben, trägt hier nichts dazu bei, den Code besser oder lesbarer zu machen. Auch aus der Sicht von OOP ist der Ansatz nicht gut, denn es ist sicher nicht die "Aufgabe" der Form, das zu erledigen, was passieren soll, nachdem die Form geschlossen wurde. |
AW: Eine Art Semi-ShowModal?
Warum zum Geier wollt Ihr alle CPU-Zeit verschwenden mit Abfragen, Timer, Sleep und Application.Processmessages?
Einfach eine {Anonyme}Procedure aufrufen wenn das Fenster geschlossen wird/worden ist. Es gibt doch keinen Grund rumzubasteln. |
AW: Eine Art Semi-ShowModal?
Sehe ich genauso. Das Gebastel macht die Sache doch wirklich nicht einfacher oder weniger fehleranfällig. Auf OnClose reagieren ist doch genau was wir wollen.
Ob man da jetzt eine anonyme Methode oder eine normale oder was auch immer nimmt. Das muss doch keinen kümmern. |
AW: Eine Art Semi-ShowModal?
Es gab Zeiten, da gab es keine Türklingeln und man hat periodisch nachschauen müssen, ob jemand vor der Tür steht.
Türklingeln sind also überflüssig. :mrgreen: |
AW: Eine Art Semi-ShowModal?
Zitat:
Zitat:
|
AW: Eine Art Semi-ShowModal?
Zitat:
Das etwas passieren soll steht fest, aber was exakt passieren soll wird injiziert. Und jeder hat IoC schon verwendet, indem er einen Event belegt hat - ist also ein alter Hut. |
AW: Eine Art Semi-ShowModal?
Zitat:
Ich habe immer gewartet bis ich das Sync-Loch der Diskette gesehen habe und dann meine Daten geschrieben... |
AW: Eine Art Semi-ShowModal?
Meines Erachtens ist ein grundlegender Unterschied zwischen der asynchronen Reaktion auf ein beliebiges Ereignis, und dem Warten auf die Beendigung eines Tasks, um dann mit dem normalen Programmablauf fortzufahren.
Und die Übergabe als Prozedur funktioniert überhaupt nicht, oder nur mit gröbsten Verrenkungen bzw. völlig unnötigen Rekursionen, wenn der Aufruf der Form in einer Schleife stattfindet.
Delphi-Quellcode:
repeat
Berechne; Form1.ShowSemiModal; berechneweiter; until BefriedigendesErgebnis; Zitat:
|
AW: Eine Art Semi-ShowModal?
Zitat:
Seit Borland Pascal für Windows programmiert man aber Event-Orientiert... |
AW: Eine Art Semi-ShowModal?
In so einem Fall sollte man sich auch von einer Schleife verabschieden und das mit etwas ersetzen, was zu dem Use-Case besser passt: Eine State-Machine.
Damit bekommt man dann auch die kompliziertesten Verschachtelungen sauber in den Griff. ![]() ![]() ![]() |
AW: Eine Art Semi-ShowModal?
Zitat:
|
AW: Eine Art Semi-ShowModal?
Code:
ich glaub ich versuch mich mal mit dieser Variante, ich geb dem Formular eine Funktion mit,
function ShowModal: TModalResult; overload;
procedure ShowModal(const ResultProc: TProc<TModalResult>); overload; die nach dem Schließen aufgerufen werden muss. Da muss ich zwar etwas umbauen, sieht aber besser aus.
Code:
wäre auch eine Option, nur gefallen mir die ganzen Konstrukte, wie gewartet wird, nicht.
Show;
WaitForMe; Danke erst mal für die Diskussion |
AW: Eine Art Semi-ShowModal?
@Baumina
Inwieweit widerspricht das eine dem anderen? Das Programm braucht zum Abarbeiten eines Tasks noch Eingaben von mir (und das vielleicht in einer Schleife - ich sage nicht, dass der TE das braucht, aber es geht um den allgemeinen Fall), und kann mit DIESEM Task ohne die Eingaben nicht weitermachen. Mir erscheint es extrem unschön, alles, was nach dieser einen Abfrage passiert, in eine anonyme Routine zu pressen, die man der Abfrage übergibt. Oder nimm einen anderes Beispiel:
Delphi-Quellcode:
Das wird mit so einer anonymen Methode ein völlig undurchsichtiger Wust.
berechne1;
if JetztBrauchIchNochDaten then Form1.ShowSemiModal; berechne2; if JetztBraucheIchNochAndereDaten then Form2.ShowSemiModal; berechne3; Und es kann schon vorkommen, dass der User zum Beantworten der Frage, die ihm das Programm stellt, gerne in irgend einem anderen Menüpunkt des Programms etwas nachschauen würde - geht bei modalen Fenstern nicht. @Sir Rufo Danke für den Link, das ist eine sehr interessante Komponente, die ich bei einigen Gelegenheiten schon gerne gehabt hätte. In der aktuellen Fragestellung geht es aber nicht um komplizierte Verschachtelungen, sondern um eine ganz einfache Schleife. Kompliziert wird es nur, wenn man sich darauf versteift, unter keinen Umständen mehr so programmieren zu dürfen, "wie zu DOS Zeiten". |
AW: Eine Art Semi-ShowModal?
Es geht hier eher um "nicht mehr wollen", denn das führte immer zu Spaghetti-Code.
Hier mal eine schnelle Implementierung, die alle anderen Show-Methoden (
Delphi-Quellcode:
,
Show
Delphi-Quellcode:
) nicht aushebelt.
ShowModal
Delphi-Quellcode:
unit Unit1;
interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.AppEvnts; type TForm1 = class( TForm ) private FApplicationEvents: TApplicationEvents; FSavedFormStyle : TFormStyle; FIsSemiModal : Boolean; FResultProc : TProc<TModalResult>; procedure ApplicationEventsIdle( Sender: TObject; var Done: Boolean ); protected procedure DoClose( var Action: TCloseAction ); override; public procedure ShowSemiModal( const ResultProc: TProc<TModalResult> ); procedure AfterConstruction; override; end; var Form1: TForm1; implementation {$R *.dfm} uses Vcl.Consts; { TForm1 } procedure TForm1.AfterConstruction; begin inherited; FApplicationEvents := TApplicationEvents.Create( Self ); FApplicationEvents.OnIdle := ApplicationEventsIdle; end; procedure TForm1.ApplicationEventsIdle( Sender: TObject; var Done: Boolean ); begin if FIsSemiModal and ( ModalResult <> mrNone ) then begin Exclude( FFormState, fsModal ); FormStyle := FSavedFormStyle; Close; end; end; procedure TForm1.DoClose( var Action: TCloseAction ); begin inherited; if FIsSemiModal then begin FIsSemiModal := False; Hide( ); FResultProc( ModalResult ); end; end; procedure TForm1.ShowSemiModal( const ResultProc: TProc<TModalResult> ); begin if not Enabled or Visible or ( fsModal in FormState ) then raise EInvalidOperation.Create( SCannotShowModal ); if not Assigned( ResultProc ) then raise EArgumentNilException.Create( 'ResultProc' ); FResultProc := ResultProc; FSavedFormStyle := FormStyle; FormStyle := fsStayOnTop; FIsSemiModal := True; Include( FFormState, fsModal ); Show( ); end; end. |
AW: Eine Art Semi-ShowModal?
Obwohl
Zitat:
Da Du ja keine Ruhe gibst... 8-) Zitat:
Allgemein: anonymen Methode bringen den Code lesbar da hin wo er gebraucht wird... Daher auch viel übersichtlicher als immer hin und her zu springen wo die eigentliche Procedure ist. Aber darum geht es nicht... Bleiben wir mal bei Deinem Beispiel... Zitat:
Ich fange den User doch nicht in so einer Schleife... Abgesehen von der UI-Task. Daher die 5 einfachen Regeln für ein reaktives Userinterface: Rule #1 / Führe nie Code in einem ONXYEvent aus der länger als wenige Millisekunden dauert. (Außer #2) Rule #2 / Ich will das Userinterface Updaten? Mach es im OnIdle Rule #3 / Du brauchst Application.Processmessages - Überprüfe Dein Design Rule #4 / Eine Aktion dauert 2xlänger als die Zeit einen Thread zu erzeugen? Erzeuge einen Thread! Rule #5 / Die Zeit eine Thread zu erzeugen ist zu lang. - Erzeuge den Thread vorher und starte ihn nur noch in wenigen (ns) {Auszug aus meinem Vortrag - Firemonkey im realen Crossplattform-Einsatz} Designe den Programm-Ablauf so wie der User es auch bedienen würde. Mavarik PS.: Rule #6 - Schau wie es der SIR macht... |
AW: Eine Art Semi-ShowModal?
Zitat:
![]() |
AW: Eine Art Semi-ShowModal?
Zitat:
Zitat:
Zitat:
Zitat:
|
AW: Eine Art Semi-ShowModal?
Ich glaube ich mach hier dicht, den das Problem ist gelöst und die unterschiedlichen Ansichten werden auch durch weitere Diskzussion nicht abgebaut werden können.
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 23: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-2025 by Thomas Breitkreuz