AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren

Semi-Modalen Dialog erstellen

Ein Thema von BigAl · begonnen am 18. Okt 2021 · letzter Beitrag vom 18. Okt 2021
Antwort Antwort
BigAl

Registriert seit: 6. Sep 2008
Ort: Kehl
485 Beiträge
 
Delphi 12 Athens
 
#1

Semi-Modalen Dialog erstellen

  Alt 18. Okt 2021, 07:50
Hallo zusammen,

ich benötige immer wieder einen Fortschrittsdialog wie "Aktion läuft, bitte warten" etc. Dafür habe ich ein Formular erstellt bei dem ich bei Bedarf einen Fortschrittsbalken einblenden oder einen Abbruch-Button anzeigen kann. Das ganze wird dann über einen managed record gewrappt, damit der Dialog einfach verwendet werden kann. Im einfachsten Fall einfach den Dialog als lokale Variable definieren und die Updates aufrufen. Beim verlassen des Gültigkeitsbereich wird dann automatisch aufgeräumt...

Bei den Updates (Fortschrittstext, Fortschrittsbalken) wird dann jeweils ein "Application.ProcessMessages" durchgeführt, damit z.B. der Abbruch-Button aktualisiert wird und auch Windows mitbekommt, dass die Anwendung noch am Leben ist. Hier kommt aber schon das Problem. Der Dialog sollte eigentlich den Rest der Applikation sperren, also Modal sein. Allerdings soll das Programm, welches den Dialog nutz weiter ausgeführt werden. ShowModal fällt also flach, da dann die Kontrolle an den Dialog geht und das aufrufende Programm dann warten muss bis der Dialog beendet ist.

Wie löst ihr sowas in VCL?

Alex
Man sollte nie so viel zu tun haben, dass man zum Nachdenken keine Zeit mehr hat. (G.C. Lichtenberg)
  Mit Zitat antworten Zitat
hoika

Registriert seit: 5. Jul 2006
Ort: Magdeburg
8.269 Beiträge
 
Delphi 10.4 Sydney
 
#2

AW: Semi-Modalen Dialog erstellen

  Alt 18. Okt 2021, 07:57
Hallo,
benutze die Suchfunktion des Forums.

https://www.delphipraxis.net/79498-i...showmodal.html
Heiko

Geändert von hoika (18. Okt 2021 um 07:59 Uhr)
  Mit Zitat antworten Zitat
BigAl

Registriert seit: 6. Sep 2008
Ort: Kehl
485 Beiträge
 
Delphi 12 Athens
 
#3

AW: Semi-Modalen Dialog erstellen

  Alt 18. Okt 2021, 08:25
Hast ja recht Habe aber entweder die falschen Suchparameter eingegeben oder war zu dämlich... Damit dieser Thread aber nicht ganz nutzlos bleibt hier die Lösung die ich mir jetzt zusammengesucht habe:

TfrmProgress:
Delphi-Quellcode:
  TfrmProgress = class(TForm)
  private
    FWindowList: Pointer;
  protected
    procedure DoShow; override;
    procedure DoHide; override;
  end;
Und dann implementiert wie folgt:
Delphi-Quellcode:
procedure TfrmProgress.DoShow;
// Make the dialog "semi modal".
begin
  FWindowList := DisableTaskWindows(Application.Handle);
  inherited;
end;

procedure TfrmProgress.DoHide;
// Ensure the application gets back the control...
begin
  inherited;
  if Assigned(FWindowList) then
  begin
    EnableTaskWindows(FWindowList);
    FWindowList := nil;
  end;
end;
Funktioniert hervorragend. Genau was ich wollte.
Man sollte nie so viel zu tun haben, dass man zum Nachdenken keine Zeit mehr hat. (G.C. Lichtenberg)

Geändert von BigAl (18. Okt 2021 um 08:28 Uhr)
  Mit Zitat antworten Zitat
BerndS

Registriert seit: 8. Mär 2006
Ort: Jüterbog
477 Beiträge
 
Delphi 11 Alexandria
 
#4

AW: Semi-Modalen Dialog erstellen

  Alt 18. Okt 2021, 08:42
Ich habe das bei mir so gelöst, dass ich einen modalen Dialog anzeige, während die Arbeit in einen Thread gemacht wird.
Der Thread wird dem Dialog übergeben um über den Abbrechen- Schalter den Thread terminieren zu können.
Gestartet wird den Thread im OnShow.
Der Thread selber schließt den Dialog über OnTerminate.

Der Thread selber führt im Execute eine Klassenmethode aus.
Der Vorteil ist, dass die Anwendung nicht blockiert, wenn es mal etwas länger dauert.
Gerade wenn die nicht klar ist, wie schnell z.B. eine Antwort von einem Server kommt oder es zu einem Timeout kommen kann, ist das von Vorteil.

Das ist sicher etwas aufwendiger als dir vorherige Lösung, zumal hier auch eine eigene Fehlerbehandlung gemacht werden muss.
Bernd
  Mit Zitat antworten Zitat
BigAl

Registriert seit: 6. Sep 2008
Ort: Kehl
485 Beiträge
 
Delphi 12 Athens
 
#5

AW: Semi-Modalen Dialog erstellen

  Alt 18. Okt 2021, 08:48
Hallo Bernd,

Du hast natürlich recht. Solch eine Lösung habe ich auch, aber die ist immer mit mehr Aufwand verbunden. Diese nutze ich ich eigentlich immer nur dann, wenn ich vom übergeordneten Programm kein zyklisches Update sicherstellen kann. Das ist aber sehr selten der Fall, deshalb die zweite Lösung. Hat halt den Vorteil, dass das ganze - speziell mit dem managed record - sehr einfach in der Handhabung ist:

Delphi-Quellcode:
var
  Progress: TProgress;
begin
  for var I := 0 to 1000 do
  begin
    Progress.UpdateProgress(Format('Progress: %.1f', [I / 10]), I / 1000);
    if Progress.Canceled then
      Break;
    Sleep(10);
  end;
end;
Und das könnte man noch weiter optimieren wenn man z.B. das "UpdateProgress" als Funktion macht, welche den Status von "Canceled" zurück gibt... Die managed records waren für mich wirklich ein riesiger Sprung nach vorne und lassen mich C++ doch etwas weniger vermissen .
Man sollte nie so viel zu tun haben, dass man zum Nachdenken keine Zeit mehr hat. (G.C. Lichtenberg)
  Mit Zitat antworten Zitat
BerndS

Registriert seit: 8. Mär 2006
Ort: Jüterbog
477 Beiträge
 
Delphi 11 Alexandria
 
#6

AW: Semi-Modalen Dialog erstellen

  Alt 18. Okt 2021, 09:07
Hallo Alex,
ich habe das auch nicht überall konsequent so gemacht.
Durch das gelegenliche aufrufen von Application.ProcessMessages wirk dann die Animation von TProgessbar etwas hackelig.
Bernd
  Mit Zitat antworten Zitat
BigAl

Registriert seit: 6. Sep 2008
Ort: Kehl
485 Beiträge
 
Delphi 12 Athens
 
#7

AW: Semi-Modalen Dialog erstellen

  Alt 18. Okt 2021, 09:19
Das mit dem "hakelig" hängt von der Anwendung ab, bzw. wie oft man es aufruft. Aber es lässt sich halt sehr gut der tatsächlich Fortschritt anzeigen, da man absolut synchron zu der Verarbeitung ist. Üblicherweise sind die Update-Raten bei mir auch sehr hoch. Da wirke ich dann normalerweise damit entgegen, dass ich nur alle 250ms oder so eine tatsächliche Aktualisierung durchführe. Ansonsten verbraucht der Dialog selbst wieder zu viel Rechenzeit.

Eine Idee wäre natürlich nur das "ProcessMessages" intern Thread-gesteuert zu machen. Dann wäre der Dialog immer gut bedienbar, auch wenn mal eine Sekunde kein Update vom Hauptprogramm kommt. Modal ist er ja jetzt, was keine unerwünschten Nebeneffekte mehr zulassen sollte. Auch sollte man das nicht zu oft machen (s.o.), da "ProcessMessages" tweilweise doch relativ viel Rechenzeit in Anspruch nimmt. Allerdings ist das "Cancel" bei mir eh nur für Ausnahmesituationen, welche hoffentlich nie benötigt werden...
Man sollte nie so viel zu tun haben, dass man zum Nachdenken keine Zeit mehr hat. (G.C. Lichtenberg)
  Mit Zitat antworten Zitat
Benutzerbild von dummzeuch
dummzeuch

Registriert seit: 11. Aug 2012
Ort: Essen
1.449 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#8

AW: Semi-Modalen Dialog erstellen

  Alt 18. Okt 2021, 09:37
Nur so am Rande bemerkt: Wenn man Application.ProcessMessages zu oft aufruft, kann das die Verarbeitung extrem verlangsamen.

Ein ex-Kollege von mir (Hi Daniel) hat das mal in eine TimedProcessMessages Funktion gekapselt, die sich merkt, wie lange der letzte Application.ProcessMessages Aufruf her ist und nur dann, wenn er mehr als n Millisekunden (200?) her ist, diese Methode wirklich aufruft. Die Umstellung auf diese Aufrufe hat bei einigen Programmen die Verarbeitung enorm beschleunigt (Faktor 5 bis 10).

Über eine ähnliche Vorgehensweise, und warum man das machen oder nicht machen sollte, habe ich mal geblogt in "Calling Application.ProcessMessages in a Delphi program"
(2018? Unglaublich, dass das schon wieder so lange her ist.)
Thomas Mueller
  Mit Zitat antworten Zitat
BigAl

Registriert seit: 6. Sep 2008
Ort: Kehl
485 Beiträge
 
Delphi 12 Athens
 
#9

AW: Semi-Modalen Dialog erstellen

  Alt 18. Okt 2021, 09:44
Nur so am Rande bemerkt: Wenn man Application.ProcessMessages zu oft aufruft, kann das die Verarbeitung extrem verlangsamen.
Das ist ja dass, was ich oben geschrieben habe. ProcessMessages (sowie die gesamte Aktualisierung der Ausgabe) wird bei mir nur in maximal vorgegebenen Intervallen aufgerufen. Üblicherweise habe ich das 250 ms oder 500 ms drin. Glücklicherweise speichert ja Windows die Botschaften in einer Queue, was dann das Drücken der Taste trotzdem erfasst, auch wenn im ersten Moment kein visuelles Feedback kommt...
Man sollte nie so viel zu tun haben, dass man zum Nachdenken keine Zeit mehr hat. (G.C. Lichtenberg)
  Mit Zitat antworten Zitat
BerndS

Registriert seit: 8. Mär 2006
Ort: Jüterbog
477 Beiträge
 
Delphi 11 Alexandria
 
#10

AW: Semi-Modalen Dialog erstellen

  Alt 18. Okt 2021, 09:57
Ich leite alle Dialoge immer von einer eigenen Basisklasse ab.
Hier mal ein vereinfachtes Beispiel für diesem Zweck:
Delphi-Quellcode:
 
TBasicForm = class(TForm)
private
  FStart: Int64;
public
  procedure AntiFreeze; // ruft nur alle 50ms Application.ProcessMessages;
end;

...
procedure TBasicForm .AntiFreeze;
begin
  if FStart = 0 then
    FStart := GetTickCount
  else
    if GetTickCount - FStart > 50 then
    begin
      FStart := GetTickCount;
      Application.ProcessMessages;
    end;
end;
50 Millisekunden habe ich gewählt, damit TProgressbar noch einigermaßen flüssig bleibt.

Bei allem was ich neu schreibe, verwendet das aber nicht mehr.
Bernd
  Mit Zitat antworten Zitat
Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 23:27 Uhr.
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