![]() |
AW: Form ansprechen während einer Bearbeitung
Zitat:
Du hast ein schönes großes Fenster, wo man also ne Menge eingeben kann. Dann klickt man auf einen Button "Start" und es soll ein neues Fenster mit einer Processbar und einem Abbruchbutton darauf erscheinen. Das schöne große Fenster soll disablen (sowie der Rest des Programms auch, falls noch andere schöne Fenster da sind) und nur die das zuletzt geöffnete Fenster mit der Progressbar soll eine Aufgabe übernehmen, die etwas Zeit beansprucht. Die Progressbar soll den Fortschritt anzeigen und der Abbruchbutton soll jederzeit die Unterbrechung der Aufgabe ermöglichen. Am Ende der Aufgabe (oder nach Unterbrechung) soll sich das FEnster wieder schließen und die anderen schönen großen Fenster sollen wieder enablen. Ist das soweit richtig? Dann starte das ProgressbarFenster einfach modal (ShowModal), damit ist alles andere grau. Und das Progressbarfenster startet den Thread mit der Aufgabe. Es gäbe auch noch die Funktion DisableTaskWindows, aber eigentlich übernimmt showmodal schon alles. |
AW: Form ansprechen während einer Bearbeitung
Zitat:
Zitat:
|
AW: Form ansprechen während einer Bearbeitung
Hier wäre mal ein Vorschlag
Form1 ist via Formdesigner einer normalen VCL-Anwendung erstellt ProgressForm ist direkt gecodet (aber nur als Beispiel; kann man auch über den Designer erstellen und zu den "verfügbaren Formularen" in den Projektoptionen schieben).
Delphi-Quellcode:
unit Unit1;
interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ComCtrls; const CM_Progress=WM_User+1; type TForm1 = class(TForm) Button1: TButton; Edit1: TEdit; Memo1: TMemo; procedure Button1Click(Sender: TObject); private { Private-Deklarationen } public { Public-Deklarationen } end; TProgressThread=class(TThread) protected procedure execute; override; private FParameter:String; FProgressWindowHandle:hwnd; FResult:String; FStatusReady: boolean; procedure SetParameter(const Value: String); procedure SetProgressWindowHandle(const Value: hwnd); public property ProgressWindowHandle:hwnd read FProgressWindowHandle write SetProgressWindowHandle; property Parameter:String read FParameter write SetParameter; property StatusReady:boolean read FStatusReady; property Result:String read FResult; end; TProgressform=class(TCustomForm) constructor CreateNew(AOwner: TComponent;dummy:Integer); override; private FProgressbar:TProgressbar; FAbbruchButton:TButton; FProgressThread:TProgressThread; FLabel:TLabel; FResult: String; FParameter: String; procedure AbbruchButtonClick(Sender:TObject); procedure CMProgress(var msg:TMessage);message CM_Progress; procedure SetParameter(const Value: String); procedure StarteThread(Parameter: String); procedure ProgressThreadTerminate(Sender:TObject); protected procedure DoShow; override; public property Parameter:String read FParameter write SetParameter; property Result:String read FResult; end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.Button1Click(Sender: TObject); var Progressform:TProgressform; begin //Form dynamisch erstellen Progressform:=TProgressform.CreateNew(nil,0); try //Eingansgparameter setzen ProgressForm.Parameter:=Edit1.Text; //Fenster Modal öffnen und Rückgabewert prüfen case Progressform.ShowModal of mrOK: Memo1.Lines.Add('Fertsch: '+ProgressForm.Result); mrCancel: Memo1.Lines.Add('Abbruch: '+ ProgressForm.Result); end; finally //finito Progressform.Free; end; end; { TProgressform } procedure TProgressform.AbbruchButtonClick(Sender: TObject); begin //einfach nur Abbruch des Threads erzwingen //um auch einen konsistenten Zustand aller Werte des Threads zu haben FProgressThread.Terminate; end; procedure TProgressform.CMProgress(var msg: TMessage); begin //zum Aktualisieren der //Wenn Postmessage an dieses Fenster gesendet wird... (siehe TProgressthread.execute) FProgressbar.StepBy(msg.LParam); //lparam ist der letzte Wert in Postmessage FLabel.Caption:= inttostr(FProgressbar.Position)+' von '+inttostr(FProgressbar.Max); //lparam und wParam dürfen frei verwendet werden end; constructor TProgressform.CreateNew(AOwner: TComponent;dummy:Integer); begin //hier wird ein fesnter ohne formulardesigner erstellt //kann man aber auch mit designer machen (der Code aus Methode DoShow muss dan zum Ereignis onShow) inherited; //lustige Elemente zusammenbasteln Caption:='please hold the line...'; Width:=400; Height:=150; FProgressbar:=TProgressbar.Create(self); FProgressbar.Parent:=self; FProgressbar.Height:=20; FProgressbar.Width:=300; FProgressbar.Left:=50; FProgressbar.Top:=20; FProgressbar.Visible:=true; FPRogressbar.Min:=0; FPRogressbar.Max:=100; FProgressbar.Position:=0; FAbbruchButton:=TButton.Create(self); FAbbruchButton.Caption:='A&bbruch'; FAbbruchbutton.Parent:=self; FAbbruchbutton.Height:=40; FAbbruchButton.Width:=100; FAbbruchButton.Left:=150; FAbbruchButton.Top:=60; FAbbruchButton.Show; FAbbruchButton.OnClick:=AbbruchButtonClick; FLabel:=TLabel.Create(self); FLabel.Parent:=self; FLabel.Visible:=true; FLabel.Caption:='ich muss mal kurz rechnen'; FLabel.Left:=50; FLabel.Top:=5; end; procedure TProgressform.DoShow; //oder als Ereignis in onShow begin inherited; BringToFront; if FParameter<>'' then StarteThread(FParameter) //wenn Fenster angezeigt wird, soll der Thread gestartet werden else raise Exception.Create('keine Parameter'); //aber nur bei gültigen Eingabewerten ;-) end; procedure TProgressform.ProgressThreadTerminate(Sender: TObject); begin //wenn der Thread beendet wird, landen wir hier FResult:=(Sender as TProgressThread).Result; if (Sender as TProgressThread).StatusReady then modalResult:=mrOk else modalResult:=mrCancel; //das setzen von modalresult bewirkt, dass dieses Fenster automatisch geschlossen wird // wir landen hinter dem Aufruf von ShowModal end; procedure TProgressform.SetParameter(const Value: String); begin FParameter := Value; FProgressbar.Max:= length(FParameter); end; procedure TProgressform.StarteThread(Parameter: String); begin FProgressThread:=TProgressThread.Create(true); //Parameter übergeben FProgressThread.Parameter:=FParameter; //Windowhandle übergeben, damit wir Messages des Threads über den Fortschritt bekommen können FProgressThread.ProgressWindowHandle:=self.WindowHandle; FProgressThread.OnTerminate:=ProgressThreadTerminate; FProgressThread.FreeOnTerminate:=true; FProgressThread.Resume; end; { TProgressThread } procedure TProgressThread.execute; var i,p:Integer; begin FStatusready:=false; p:=1; //Hauptschleife while (not terminated)and(p<=length(FParameter)) do begin //erstmal Message senden, dass wir die nächste Aufgabe abarbeiten Postmessage(FProgressWindowHandle,CM_Progress,0,1); //Aufgabe erledigen FResult:=FResult+inttohex(ord(FParameter[p]),2)+' '; inc(p); //simulieren, dass die Aufgabe ca. 1sek braucht for i:=1 to 10 do begin sleep(100); if terminated then break; end; end; FStatusReady:= p>length(FParameter); end; procedure TProgressThread.SetParameter(const Value: String); begin FParameter := Value; end; procedure TProgressThread.SetProgressWindowHandle(const Value: hwnd); begin FProgressWindowHandle := Value; end; end. |
AW: Form ansprechen während einer Bearbeitung
Danke, das muuß ich mir erst einmal angucken. Irgendwie alles komplizierter als ich dachte...
|
AW: Form ansprechen während einer Bearbeitung
Nein, er hat es nur komplizierter gemacht als nötig, weil er, warum auch immer, das Formular zur Laufzeit erstellt, was absolut unnötig ist.
|
AW: Form ansprechen während einer Bearbeitung
Zitat:
Der einzige Unterschied ist die Methode CreateNew, die man sich sonst zusammenklickern anstatt tippen müsste. |
AW: Form ansprechen während einer Bearbeitung
Ganz ruhig.
Mit "kompliziert" habe ich mich auf das ganze Thema bezogen. Eigentlich dachte ich, ich mache ein kleines Fenster auf mit einem Progressbar und einem Button und das wäre es schon fast, aber... |
AW: Form ansprechen während einer Bearbeitung
Auf das Problem ist wohl jeder schon gestoßen.
|
AW: Form ansprechen während einer Bearbeitung
In den Cindy-Komponenten habe ich ein ProgressPanel gefunden und das wie Folgt adaptiert.
Die Threadlösung ist derzeit etwas zu groß für mich. Bei dieser Lösung frieren aber auch alle Fenster ein. Das Progressfenster zeigt aber die Bars an und der Button kann den Prozess canceln.
Delphi-Quellcode:
Die Berechnungsschleife:
type
TfrmProgress = class(TForm) pb2: TProgressBar; pb1: TProgressBar; btn1: TButton; procedure btn1Click(Sender: TObject); procedure FormShow(Sender: TObject); private public IsCanceled: Boolean; function ProcessMessages(var Msg: TMsg): Boolean; overload; procedure ProcessMessages; overload; end; var frmProgress: TfrmProgress; implementation {$R *.dfm} procedure TfrmProgress.ProcessMessages; var Msg: TMsg; Cont: Boolean; begin cont := ProcessMessages(Msg); while Cont do cont := ProcessMessages(Msg); end; procedure TfrmProgress.btn1Click(Sender: TObject); begin IsCanceled := True; end; procedure TfrmProgress.FormShow(Sender: TObject); begin pb1.Position := 0; IsCanceled := False; end; function TfrmProgress.ProcessMessages(var Msg: TMsg): Boolean; var aHandle: HWND; begin RESULT := false; if IsCanceled then EXIT; aHandle := 0; // aHandle := FPanel.Handle doesn' t work if you click outiside the panel before clicking panel's cancel button ... if PeekMessage(Msg, aHandle, 0, 0, PM_REMOVE) then begin Result := True; if Msg.hwnd = btn1.Handle then begin Windows.TranslateMessage(Msg); Windows.DispatchMessage(Msg); end else if Msg.message = WM_PAINT then // !!! Only WM_PAINT message are not removed from queue !!! begin // In order to go outside while Cont do, we need to dispatch the message // Windows.TranslateMessage(Msg); Windows.DispatchMessage(Msg); end; end; end;
Delphi-Quellcode:
frmProgress.Show;
for i:= 0 to 1000 begin Berechnung; frmProgress.ProcessMessages; if frmProgress.IsCanceled then break; end; frmProgress.Close; |
AW: Form ansprechen während einer Bearbeitung
Wenn es funktioniert ist es ok. Aber bedenke, dass du hier auch ein separate Messageschleife benutzt. Es ist zwar nicht die von TApplication(.ProcessMessages), sondern deine eigene (damit du Messages filtern kannst). Aber bei größeren Programmen bekommst du mit derartigen Konstrukten nur Probleme.
Lies Dir mal folgenden Beitrag von einem sehr geschätzten Informatiker durch (es geht um Delay, welches auch Application.ProcessMessages benutzt): ![]() Ich will Dir damit sagen: Früher oder später kommst du um Threads nicht herum. Kein ordentliches Programm kommt ohne Threads aus. Das ist nicht so kompliziert. Du solltest es dir an dem recht einfachen Beispiel einer Progressbar einmal ansehen. mfg sirius |
Alle Zeitangaben in WEZ +1. Es ist jetzt 06:23 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