Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   VCL Elemente in geblocktem Ereignishandler disablen (https://www.delphipraxis.net/169910-vcl-elemente-geblocktem-ereignishandler-disablen.html)

Viktorii 21. Aug 2012 07:47

VCL Elemente in geblocktem Ereignishandler disablen
 
Moin.

Wie im Titel schon geschrieben möchte ich VCL Elemente (vier Buttons) in einer Ereignishandler eines Buttons disablen.

Dieser Ereignishandler ist für eine gewisse Zeit geblockt und während dieser Zeit sollen die Buttons disabled sein. Da beim Blocken ja keine Window Messages verarbeitet werden können, habe ich es mit repaint, refresh und processmessages probiert. Alles ohne Erfolg:

Delphi-Quellcode:
procedure TForm2.Button2Click(Sender: TObject);
begin
  button1.Enabled := false;
  button1.Refresh;
  button1.Repaint;
  button2.Enabled := false;
  button2.Refresh;
  button2.Repaint;
  button3.Enabled := false;
  button3.Refresh;
  button3.Repaint;
  button4.Enabled := false;
  button4.Refresh;
  button4.Repaint;

  Form2.Refresh;
  Form2.Repaint;

  Application.ProcessMessages;

  sleep(5000);

  button1.Enabled := true;
  button2.Enabled := true;
  button3.Enabled := true;
  button4.Enabled := true;
end;
Es wird nur der geklickte Button disabled. Alle anderen Buttons werde erst nach den fünf Sekunden disabled und sofort wieder enabled.

Wie muss ich es richtig machen?

s.h.a.r.k 21. Aug 2012 07:51

AW: VCL Elemente in geblocktem Ereignishandler disablen
 
Vielleicht solltest du nicht Sleep verwenden, sondern z.B. einen Timer. Der blockiert den MainThread nicht und du hättest das, was du willst.

Furtbichler 21. Aug 2012 07:58

AW: VCL Elemente in geblocktem Ereignishandler disablen
 
Man kann mit der VCL nicht so umgehen, als ob jeder Aufruf einer Methode einen unmittelbaren Effekt hätte. Insbesondere die Methoden/Eigenschaften zur Veränderung des Aussehens (Enable, Visible, Caption etc.) sollten eher nach dem Motto: "Bitte ausführen, wenn die Anwendung mal wieder Zeit hat" gehandhabt werden.

So ein Formular wartet ja eigentlich immer, das der Anwender irgendwo raufklickt oder sonstwas anstellt. Und nur in der Zeit werden die o.g. Anforderungen an Layoutänderungen abgearbeitet.

Man kann z.T. mit 'Update', 'Repaint' usw. das Neuzeichnen forcen, aber so richtig schick ist das nicht, da das Formular dann zwar u.U. statisch neu gezeichnet wird, aber nur einmalig.

Du willst bei einem Buttonklick eine Aktion starten und solange diese Aktion läuft, soll der Button nicht klickbar sein? Aber das Fenster soll man ja noch verschieben dürfen, oder?

Verwende einen Thread. Im OnClick des Start-Buttons startest Du dem Thread und disablest den Button. Dem Thread sagst Du, das er bei Beendigung (OnTerminate) den Button wieder enablen soll.

Dann musst Du nur im OnClose-Ereignis des Formulars eine ggfs. aktive Instanz des Threads terminieren.

Viktorii 21. Aug 2012 08:10

AW: VCL Elemente in geblocktem Ereignishandler disablen
 
Das ganze ist für kleines Tool eine Quick and Dirty Lösung. Das sleep ist hier nur ein Platzhalter. Eigentlich wird eine Funktion aufgerufen die für eine gewisse Zeit blockiert...

Habe für das Tool eigentlich keine Lust mit mehreren Threads zu hantieren. Mit ist klar, dass das Fenster für die Zeit nicht verschiebbar bzw. für Benutzereingaben nicht empfänglich ist. Es soll durch das disablen nur eine optisches Feedback gegeben werden, dass das Tool beschäftigt ist.

Zitat:

Zitat von Furtbichler (Beitrag 1178985)
Man kann mit der VCL nicht so umgehen, als ob jeder Aufruf einer Methode einen unmittelbaren Effekt hätte. Insbesondere die Methoden/Eigenschaften zur Veränderung des Aussehens (Enable, Visible, Caption etc.) sollten eher nach dem Motto: "Bitte ausführen, wenn die Anwendung mal wieder Zeit hat" gehandhabt werden.

Ich dachte genau dafür ist processmessage da. Man sagt: "Nimm dir jetzt Zeit um alles abzuarbeiten was angefordert ist und mache erst dann weiter" (in diesem Fall das disablen). Also lässt die VCL solch eine Lösung nicht zu?

Furtbichler 21. Aug 2012 08:35

AW: VCL Elemente in geblocktem Ereignishandler disablen
 
Also bei mir funktioniert es, allerdings ohne das ganze Repaint/Refresh-Gedöns.

Im Zweifelsfall rufst Du in deiner Schleife immer mal wieder Application.Processmessages auf.

shmia 21. Aug 2012 09:56

AW: VCL Elemente in geblocktem Ereignishandler disablen
 
SO sollte das aussehen:
Delphi-Quellcode:
procedure TForm2.EnableButtons(en:Boolean);
begin
  button1.Enabled := en;
  button2.Enabled := en;
  button3.Enabled := en;
  button4.Enabled := en;
end;

procedure TForm2.MachDieArbeit;
var
  i : Integer;
begin
  for i:= 1 to ANZAHL_HAARE_IM_WASCHBECKEN do
  begin
    // der "Trick" ist, immer mal wieder Application.ProcessMessages aufzurufen
    // um die GUI upzudaten und auf Messages zu reagieren
    // Macht man dies aber zu oft, dann verlängert sich die Gesamtzeit
    // mit der Modulo-Abfrage kann man die Anzahl der Aufrufe entsprechend reduzieren
    // es kommt halt immer auf den konkreten Fall an
    if (i mod 10) = 0 then
      Application.ProcessMessages;
   
    Sleep(20); // Platzhalter für blockierenden Code
  end;
end;

procedure TForm2.Button2Click(Sender: TObject);
begin
  EnableButtons(False);
  try
    MachDieArbeit;
  finally
    EnableButtons(True);
  end;
end;


Alle Zeitangaben in WEZ +1. Es ist jetzt 06:55 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