![]() |
VCL-Form aktualisieren obwohl Maschine ausgelastet ist
Liebe Wissende,
ich bin leider noch Anfänger. Mit einem VCL-Form habe ich das Problem, dass, wenn eine Prozedur gestartet wird, die etwas länger dauert, und ich vorher z.b. ein TLabel.Caption beschreibe, er mir diese TLable.Caption nicht anzeigt. Gibt es irgendwelche Befehle um das Label, das ja gesetzt wurde auch anzuzeigen? Beispiel: ich habe eine Prozedur auf einem Button, die lange ausgeführt wird.
Delphi-Quellcode:
... und hier geht es noch enldos weiter. Die Prozedur dauert ca 2 Minuten.
procedure TAuswExcelll.BuExGrClick(Sender: TObject);
var Artikel, Wznr, inter, Dateiname : String; i,j,a,ii,gefunden,letztezeile,summe, zeile : integer; begin LblAchtung.Caption:='Bitte warten!'; // Noch ein Array mit Group by Wznr, Summe aus Intervall, unsichtbar. Setlength(Tab,1000,4); for i:=0 to 999 do begin //Array Feldbreite bestimmen for j:=0 to 3 do begin Setlength(Tab[i,j], 10); end; end; for i:=0 to 999 do begin //Array leer machen for j:=0 to 3 do begin Tab[i,j]:=''; end; end; der LblAchtung.Caption:='Bitte warten!'; wird zur laufzeit auf dem Form aber garnicht angezeigt. Ich hoffe ich habe mich verständlich ausgedrückt. |
AW: VCL-Form aktualisieren obwohl Maschine ausgelastet ist
Hey!
Baue in deine Schleife
Delphi-Quellcode:
ein.
application.ProcessMessages;
Diese Prozedur zwingt das System zur Aktualisierung. Alternativ baue sie vor die Schleife ein (Ressourcen sparen) MfG, Noobmaster |
AW: VCL-Form aktualisieren obwohl Maschine ausgelastet ist
Das ProcessMessages wäre sinnvoll, wenn zwischendrin noch mehr aktualisiert werden soll, kann aber ggf. doofe Nebeneffekte haben (z.B. ganze andere große lange Verarbeitungen auslösen, wenn man deren Auslöser nicht explizit deaktiviert hat.) Die unmittelbare Lösung, die dem Problem am angemessensten wäre, ist:
Delphi-Quellcode:
procedure TAuswExcelll.BuExGrClick(Sender: TObject);
var Artikel, Wznr, inter, Dateiname : String; i,j,a,ii,gefunden,letztezeile,summe, zeile : integer; begin LblAchtung.Caption:='Bitte warten!'; LblAchtung.Repaint; // <-------------------- !!!! . . |
AW: VCL-Form aktualisieren obwohl Maschine ausgelastet ist
Und nur der Vollständigkeit halber: man könnte auch die lange dauernde Operation in einen Thread auslagern, welcher dann synchronisiert die VCL-Controls aktualisiert. Allerdings ist das nicht unbedingt anfängerfreundlich.
|
AW: VCL-Form aktualisieren obwohl Maschine ausgelastet ist
Application.ProcessMessages birgt aber diverse Gefahren, man merke etwa, daß Dein OnClick-Handler den Button nicht für den Zeitraum der Aktion disabled, so daß ein ProcessMessages etwa bewirken würde, daß der Nutzer die Berechnung ein zweites Mal starten kann, bevor die erste zuende gelaufen ist (weil er den Button-Click "processed").
Anders gesagt: die einzige sinnvolle Variante ist, rechenintensives in Threads auszulagern. LblAchtung.Refresh und Application.ProcessMessages sind ein Workaround, der klappen mag, wenn die Form kaum was kann und die einzigen Alternativ-Actions disabled werden, aber schön ist das trotzdem nicht. |
AW: VCL-Form aktualisieren obwohl Maschine ausgelastet ist
Zitat:
Man kann übrigens auch ein Refresh (der Form) regelmäßig aufrufen, bzw. die entsprechenden Controls refreshen/repainten. |
AW: VCL-Form aktualisieren obwohl Maschine ausgelastet ist
Das hatten wir bereits in #3 (*seufz*). Allerdings reagiert das Formular zwischen 2 Aufrufen auch anderweitig nicht (verschieben etc.).
|
AW: VCL-Form aktualisieren obwohl Maschine ausgelastet ist
Zitat:
- in Threads auslagen (und die VCL-Aufrufe synchronisieren) - nur das Repainten, was man benötigt (sonst reagiert aber nichts) - Application.ProcessMessages und die entsprechenden Funktionen disablen (falls nötig), wärend der Laufzeit - nur Application.ProcessMessages und mit den Gefahren leben - die Funktion in kleine Einheiten aufteilen und via Timer abarbeiten Auswahlmöglichkeiten gibt es zu Genüge. |
AW: VCL-Form aktualisieren obwohl Maschine ausgelastet ist
Aber auch wenn man mit Threads arbeitet, sollte man die Steuerelemente deaktivieren, sonst kann der Thread mehr mals gestartet werden. Nichts desto trotz halte ich Threads für die sauberere Lösung. Denn arbeitet man mit Processmessages, wird jedes mal die Verarbeitung unterbrochen, wenn Nachrichten abgearbeitet werden. Verschiebt man das Fenster zum Beispiel oder muss es häufig aktualisiert werden und stehen deshalb viele Nachrichten an, wird gar nichts gemacht, weil erst mal die ganzen anstehenden Nachrichten abgearbeitet werden.
|
AW: VCL-Form aktualisieren obwohl Maschine ausgelastet ist
Gegen mehrmaliges Aktivieren hilft ein einfaches
Delphi-Quellcode:
Wobei..
Procedure TMyForm.myButtonClick(Sender : TObject);
Begin If myButton.Tag=0 then try myButton.Tag := 1; // Und hier was extrem lahmes mit Application.ProcessMessages zwischendurch finally myButton.Tag := 0; end end;
Delphi-Quellcode:
ist irgendwie ... naheliegender :mrgreen:
myButton.Enabled := False
|
AW: VCL-Form aktualisieren obwohl Maschine ausgelastet ist
Ups daran hatte ich garnicht gedacht. Klar darf man während des Laufes nix klicken.
Wie man einen Thread auslagert ist mir völlig schleierhaft. Ich werde nach einem Tuto suchen. Ist bestimmt irgendwo beschrieben. Bu* sind Buttons... Also mein Conde sieht jetzt so aus:
Delphi-Quellcode:
und am Ende natürlich dann:begin LblAchtung.Caption:='Bitte warten!'; BuExGr.Enabled:=False; BuExport.Enabled:=False; BuExit.Enabled:=False; AuswExcelll.Refresh; Setlength(Tab,1000,4); for i:=0 to 999 do begin //Array Feldbreite bestimmen for j:=0 to 3 do begin Setlength(Tab[i,j], 10); end; end; for i:=0 to 999 do begin //Array leer machen for j:=0 to 3 do begin Tab[i,j]:=''; end; end;
Delphi-Quellcode:
... und funktioniert bestens. Ich bedanke mich bei allen.
...
Setlength(Tab,1,1); Excel := Unassigned; BuExGr.Enabled:=True; BuExport.Enabled:=True; BuExit.Enabled:=True; LblAchtung.Caption:=''; end; |
AW: VCL-Form aktualisieren obwohl Maschine ausgelastet ist
Ein Deaktivieren des Buttons ist aber nur ein Workaround für einen kleinen Teil des Problems (und auch für Threads nötig, wie Luckie schon anmerkte - wobei man da nicht nur einen, sondern mutmaßlich etliche Steuerelemente behandeln muss, was ist beispielsweise mit Lade- und Speicher-Routinen?). Damit ist ein Doppelstart der Funktion verhindert, aber sonst?
Nächstes Problem nämlich: der User schließt das Fenster. Im OnDestroy werden wichtige Variablen freigegeben, die parallel in der Funktion aber noch bearbeitet werden. Warum hat mein Programm beim Beenden denn nun diese doofe AV? Also Workaround Nummer 2: überall in der Funktion vor Zugriff auf Objekte prüfen, ob sie noch existieren, und ob das Programm gerade beendet werden soll? Da wird's noch "dreckiger". Einen Thread beendet man in OnCloseQuery, fertig (klar muss der dann auch Terminated abfragen, aber kann sich wenigstens darauf verlassen, daß alle Objekte da sind). PS: um weitere Probleme im Falle von Fehlern zu vermeiden (bzw. auch schlicht ein Exit als Ausstieg zu ermöglichen), würde ich bei obigem mit try-finally kaspeln:
Delphi-Quellcode:
BuExGr.Enabled:=False;
try // process finally BuExGr.Enabled:=True; end; |
Alle Zeitangaben in WEZ +1. Es ist jetzt 00:06 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