![]() |
AW: "Bitte warten"-Formular korrekt anzeigen
Hallo,
auch auf die Gefahr hin, dass ich mich jetzt fürchterlich blamiere, stelle ich diesen Quelltext online. Es ist verdammt spät und ich habe kaum noch Auffassungsgabe. Also, mein Ziel ist es, einen "Bitte-Warten"-Dialog schnell und einfach zu erstellen, auf dem permanent eine Marquee-Bar oder Statusbar zu sehen ist und ein entsprechendes Aktions-Label. Alle drei Komponenten sollen regelmäßig aktualisiert werden, während im Hauptprogramm Berechnungen durchgeführt werden. Also habe ich ein vorgebasteltes Formular, einen Thread und eine "Wrapper-Klasse". Das Formular wird nicht automatisch erstellt. Das Dialog-Fenster wird komplett über die Wraptter-Klasse gesteuert. Es wird durch sie ein Thread erzeugt, der das Formular erzeugt. Der Thread wird mit einer while-Schleife am Leben gehalten, bis in der Wrapper-Klasse "Finished:=True" gesetzt ist. Problem ist, dass die Komponenten nicht aktualisiert werden. Erst, wenn alle Berchnungen fertig sind, werden die Komponenten neu gezeichnet und die Anwendung friert während der Berechnungen ein. Hier der Quelltext, extra schön kommentiert. Anwendung des Warten-Dialogs in der Hauptanwendung
Delphi-Quellcode:
Bevor der Quelltext der Unit kommt, eine kurze Erklärung, wie was abläuft:
procedure TForm1.Button2Click(Sender: TObject);
var w: TWaitForm; i,j: Integer; begin w:=TWaitForm.Create; w.CreateWaitForm; for i:=0 to 100000 do begin randomize(); j:=random(9999); w.AddMessage(IntToStr(j)); end; w.Finished:=True; //w.DestroyWaitForm; end;
Nun endlich der Code, bei dem durch Test noch veraltete Codefragmente bestehen könnten
Delphi-Quellcode:
Wie gesagt, auch wenn ich mich jetzt blamiere. Vielleicht habe ich einen gewaltigen Denkfehler oder doch nur eine Kleinigkeit vergessen. Aber ich finde den Wald vor lauter Bäumen nicht...
type
//Das ist das vorgefertigte Formular TfrmWarten = class(TForm) GroupBox1: TGroupBox; Label1: TLabel; lblAktion: TLabel; Label3: TLabel; StatusBar: TProgressBar; lblPercent: TLabel; MarqueeBar: TUbuntuProgress; private public end; //Eine Forward-Deklaration TWaitThread = class; //Das ist die Wrapper-Klasse, die einfach nur die Handhabung //im Hauptquelltext erleichtern soll TWaitForm = class(TObject) private WartenForm: TfrmWarten; wt: TWaitThread; fFinished: Boolean; public procedure CreateWaitForm; procedure DestroyWaitForm; procedure AddMessage(Value: String); //Prozeduren, die vom Thread per Synchronize aufgerufen werden procedure ThreadCreateWaitForm; procedure ThreadShowWaitForm; procedure ThreadAddMessage; property Finished: Boolean read fFinished write fFinished; end; //Das ist der Thread, der für die Aktualisierung der Komponenten //zuständig ist. TWaitThread = class(TThread) private fCreated: Boolean; fwf: TWaitForm; ffrmWarten: TFrmWarten; fMsg: String; procedure ShowWaitForm; public procedure SetMessage(Value: String); property FormCreated: Boolean read fCreated write fCreated; property WaitFormWrapper: TWaitForm read fwf write fwf; property Msg: String read fMsg write fMsg; protected procedure Execute; override; end; var frmWarten: TfrmWarten; implementation {$R *.dfm} {************** TWaitThread ***************} procedure TWaitThread.Execute; begin inherited; Synchronize(WaitFormWrapper.ThreadCreateWaitForm); Synchronize(WaitFormWrapper.ThreadShowWaitForm); while not (WaitFormWrapper.Finished) do begin //Application.ProcessMessages; Synchronize(WaitFormWrapper.ThreadShowWaitForm); end; end; procedure TWaitThread.ShowWaitForm; begin Synchronize(WaitFormWrapper.ThreadShowWaitForm); end; procedure TWaitThread.SetMessage(Value: string); begin Msg:=Value; Synchronize(WaitFormWrapper.ThreadAddMessage); end; {************** TWaitForm ***************} procedure TWaitForm.CreateWaitForm; begin wt:=TWaitThread.Create(True); wt.FormCreated:=False; wt.WaitFormWrapper:=Self; wt.FreeOnTerminate:=False; //Im Execute des Threads wird das Fenster erstellt und angezeigt wt.Resume; while not (wt.FormCreated) do Application.ProcessMessages; end; procedure TWaitForm.ThreadCreateWaitForm; begin WartenForm:=TFrmWarten.Create(nil); wt.FormCreated:=True; end; procedure TWaitForm.DestroyWaitForm; begin FreeAndNil(WartenForm); wt.Free; end; procedure TWaitForm.AddMessage(Value: String); begin wt.SetMessage(Value); end; procedure TWaitForm.ThreadShowWaitForm; begin if not (WartenForm.Visible) then WartenForm.Show; WartenForm.lblAktion.Caption:=IntToStr(random(999)); WartenForm.lblAktion.Repaint; end; procedure TWaitForm.ThreadAddMessage(); begin WartenForm.lblAktion.Caption:=wt.Msg; end; end. Bitte helft mir und erklärt mir ggf. meinen Gedankenfehler. Danke und gute Nacht. Ich hau ich jetzt endlich hin ;) |
AW: "Bitte warten"-Formular korrekt anzeigen
Liste der Anhänge anzeigen (Anzahl: 1)
Hab jetzt noch nicht genau den Aufbau deiner Idee geblickt, aber ich häng dir mal eine kleine Demo an.
Ausschnitt:
Delphi-Quellcode:
Und im Thread, der die Aufgaben erledigt, dann so:
procedure TfrmMain.Button1Click(Sender: TObject);
var frmWait: TfrmWait; begin // Wartefenster erstellen frmWait := TfrmWait.Create(nil); // Thread starten TWorkerThread.Create(frmWait).OnTerminate := OnWorkerThreadTerminate; // Wartefenster anzeigen frmWait.ShowModal; end;
Delphi-Quellcode:
Sobald der Thread terminiert, wird das Wartefenster geschlossen.
procedure TWorkerThread.Execute;
begin // setzt mit Synchronize das Label im Wartefenster SetAction('Wichtige Berechnung'); Sleep(2000); end; Ich hoffe mal, das ist in etwa das, was du brauchst. :stupid: |
AW: "Bitte warten"-Formular korrekt anzeigen
Danke für die Antwort.
Der Sinn meiner Idee - ob das klapp oder nicht sei dahingestellt - war, eine einfache Klasse zu haben, die für mich den Thread und das WaitForm erstellt und auch wieder freigibt. So muss ich mich jedesmal selbst um den Thread etc. kümmern. Der Unterschied unserer Versionen scheint zu sein, dass in deiner die Berechnungen im Thread durchgeführt werden. Bei mir werden die Berechnungen im MainThread durchgeführt und existierten, bevor mir die Idee mit dem "Bitte-Warten"-Fenster kam. D.h, mein Thread soll so lange das Form anzeigen und aktualisieren, bis die Wrapper-Klasse den Status "Finished" erreicht hat. Aber da liegt glaub ich das Problem. Während der MainThread die Berechnung durchführt, ist er blockiert und kann auch nicht das Warten-Fenster neuzeichnen, richtig? Das würde auch bedeuten, dass ich alle Aktionen, die das Fenster benutzen sollen, in einen Thread verschoben werden müssen und ich so das Programm komplett umstellen darf... auch richtg? Danke |
AW: "Bitte warten"-Formular korrekt anzeigen
Hallo DJ-SPM,
das hat jetzt nichts mit deinem eigentlich Problem zu tun, nur ein Hinweis: Randomize soll in einem Programm nur 1-mal aufgerufen werden. Du rufst es x-mal in einer Schleife auf.....
Delphi-Quellcode:
Gruss,
for i:=0 to 100000 do
begin randomize(); blauweiss |
AW: "Bitte warten"-Formular korrekt anzeigen
Ja ich weiß ;)
Das war nur, weil die Schleife sowie nur den Testzwecken dient und ich, als ich es gemerkt habe, keine Lust mehr hatte, es umzuändern (da eh nur Test) ;) Aber trotzdem danke für den Hinweis |
AW: "Bitte warten"-Formular korrekt anzeigen
Zitat:
Zitat:
Als Alternative zur Auslagerung der Berechnungen in einen neuen Thread könntest du, wie rollstuhlfahrer hier früher schon erwähnt hat, in einem Thread das Warte Fenster nonVCL erstellen. So könntest du dann z.B. mit PostThreadMessage den Warte-Fenster-Thread über Updates benachrichtigen, während der Main Thread am werkeln ist. Schätze ab, was dir mehr Arbeit macht. :wink: |
AW: "Bitte warten"-Formular korrekt anzeigen
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo,
ich habe nun also in den sauren Apfel gebissen und die Aufgaben in einen Thread ausgelagert (bzw. das werde ich alles nach und nach machen). Mein Warten-Formular und der Thread dazu steht und funktioniert. Meine Wrapper-Klasse wollte ich dennoch behalten. So ergibt sich der unten aufgeführte Code. Ich habe also eine Wrapper-Klasse, die die Warten-Form anzeigt und den Thread startet. Zuvor wird der Wrapper-Klasse gesagt, welche Aktion der Thread zu erledigen hat. Der Thread startet und führt die für die Aktion hinterlegte Berechnung durch. Danach gibt sich die Klasse über den Thread wieder frei. Wer's haben mag, darf es gerne nutzen. Schaut euch bitte meinen Code an und sagt, was positiv und was negativ ist. Danke..! (Achso: Bisher gab's keine Probleme bez. VCL, AVs etc.) Anwendung der Wrapper-Klasse (Darstellen eines Warten-Bildschirms)
Delphi-Quellcode:
Und hier das, was wie im Hintergrund passiert (Auszug)
procedure TForm1.Button2Click(Sender: TObject);
var wu: TWaitUtils; begin //Erstellt ein WaitUtil-Objekt, zeigt das Fenster an wu:=TWaitUtils.Create; //Erstellt einen Thread, sagt ihm was zu tun ist und lässt den Dingen seinen lauf wu.InitWaitThread(taStoreAttachment); //Freigeben nicht nötig, geschieht automatisch (laut FastMM4 alles OK). end;
Delphi-Quellcode:
Ich häng's hier nochmal an, vielleicht mögt ihr es nutzen oder mal "Korrekturlesen"
type
TThreadActions = (taStoreAttachment, taLoadAttachment); {************** TWaitThread ***************} procedure TWaitThread.Execute; begin case (Action) of taStoreAttachment: begin StoreAttachment; end; taLoadAttachment: begin end; end; end; {************** TWaitUtils ***************} constructor TWaitUtils.Create; begin InUse:=False; WartenForm:=TfrmWarten.Create(nil); Thread:=TWaitThread.Create(True); Thread.WaitFormular:=WartenForm; Thread.FreeOnTerminate:=True; Thread.WaitUtilObject:=Self; WorkerThread:=Thread; WorkerThread.OnTerminate:=ThreadTerminate; end; procedure TWaitUtils.InitWaitThread(ta: TThreadActions); begin InUse:=True; ShowWaitForm; //Welche Aktion soll der Thread ausüben? Thread.Action:=ta; //Thread ins Rollen bringen Thread.Resume; end; procedure TWaitUtils.ThreadTerminate(Sender: TObject); begin InUse:=False; with (Sender as TWaitThread).WaitFormular do begin Close; end; //Das Warten-Formular freigeben DestroyWaitForm; //Das WaitUtilObjekt wieder freigeben Thread.WaitUtilObject.Free; end; Danke! |
Alle Zeitangaben in WEZ +1. Es ist jetzt 09:41 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