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/)
-   -   User klicken unterbinden während Querry läuft (https://www.delphipraxis.net/156638-user-klicken-unterbinden-waehrend-querry-laeuft.html)

Jumpy 9. Dez 2010 11:56

User klicken unterbinden während Querry läuft
 
Hallo zusammen,

ich habe ein Form wo in einem Memofeld ein SQL-Statement geschrieben werden kann, und das dann auf Knopfdruck ausgeführt wird indem es an eine TADOQuerry übergeben wird. Die Daten werden dann in einem DBGrid angezeigt. Funktioniert alles soweit ganz gut.

Es gibt aber Selects, die ganz schön lange laufen, unter Umständen Minuten. Ich möchte verhindern, dass der User in der Zeit wild auf dem Form rumklickt.

Z.Zt. ist es so, dass der User auf irgendwelche Buttons klicken kann, aber nichts passiert, während die Querry läuft. Aber danach werden alle diese Klicks mit Verspätung ausgeführt. Das möchte ich aber so nicht. Es soll auf keinen Klick reagiert werden, der geschieht, während die Querry läuft.

Ich hab schon versucht die ActionList auf asSuspended zu setzen und später dann auf asNormal zurück aber das Hilft nicht. Vllt. hab ich es aber auch an falscher Stelle getan?

Quelle ist die TADOQuerry:
Code:
Quelle.SQL.Clear;
Quelle.SQL.Text:= Memo1.Lines.Text;
  try
    ActionList1.State:= asSuspendedEnabled;
    Quelle.Open;
    Application.ProcessMessages;
    ActionList1.State:= asNormal;
Hat wer eine Idee, warum das nicht klappt?

Danke,
Jumpy

gsh 9. Dez 2010 12:03

AW: User klicken unterbinden während Querry läuft
 
Form1.Enabled := false;
und danach wieder auf true

GHorn 9. Dez 2010 12:39

AW: User klicken unterbinden während Querry läuft
 
... und dazu dann noch den Cursor auf crSQLWait oder crHourGlass setzen und anschließend wieder zurück.
Dann sieht der Anwender gleich, dass er warten soll.

Luckie 9. Dez 2010 12:57

AW: User klicken unterbinden während Querry läuft
 
Ich würde nicht das ganze Form deakivieren, sondern nur die Schaltfläche.

Jumpy 9. Dez 2010 13:07

AW: User klicken unterbinden während Querry läuft
 
Danke erstmal. Das Problem ist halt, dass es massig andere Buttons auf dem Form gibt, und ich nicht 20 mal ButtonXY.Enabled im Code haben will. Daher mein versuch über die ActionList. Versuch jetzt mal den Vorschlag mit dem Form.Enabled.

Jumpy

Luckie 9. Dez 2010 13:13

AW: User klicken unterbinden während Querry läuft
 
Das dürfte aber dazu führen, dass die Form nicht mehr reagiert und der Benutzer denkt das Programm wäre abgestürzt.

Jumpy 9. Dez 2010 13:30

AW: User klicken unterbinden während Querry läuft
 
Nee das hat schon gepasst, da ich hinterher ja Enabled wieder auf true setze. Aber es hat nix gebracht. Wie zuvor kann man wild auf Buttons klicken, ohne das zunächst was passiert, aber wenn die Querry dann fertig geöffnet ist und ein Ergebnis zurückgebracht hat, passiert alles, was nach drücken der Buttons geschehen sollte.

Was den Eindruck des Absturzes angeht, so ist das ja genrell ein Problem, da ja wie geschildert nix passiert, während die Querry läuft und jeder Knopfdruck scheinbar ignoriert wird, so dass ein User denken könnte, das Prog. wäre abgestürzt. Aber damit muss man bei langen Abfragen halt leben. Was halt nur stört ist, das evtl. Buttonklicks während der "Todzeit" des Progs trotzdem irgendwie registriert und dann anschließend ausgeführt werden.

Weitere Ideen gerne willkommen. Vllt. ist ja wirklich der Zeitpunkt bzw. das Ereignis wichtig, bei dem alles wieder aktiviert wird.

Jumpy

DeddyH 9. Dez 2010 13:35

AW: User klicken unterbinden während Querry läuft
 
Erst disablen, dann Abfrage ausführen, dann wieder enablen. Sonst laufen die Clicks und sonstigen Aktionen in der Botschaftswarteschlange auf.

Luckie 9. Dez 2010 13:36

AW: User klicken unterbinden während Querry läuft
 
Und so lange Operationen verlagert man üblicherweise in einen Thread.

RWarnecke 9. Dez 2010 13:39

AW: User klicken unterbinden während Querry läuft
 
Du kannst auch die Buttons über eine Schleife mit FindComponents abfragen und entsprechend das Enabled auf true oder false setzen.

Edit:
Oder im OnMouseClick - Event die Maustasten abfragen, wenn die Eigenschaft Active von der Query auf True ist, die Mausklicks ins leere laufen lassen. Wenn Active gleich False ist, dann die Mausklicks ausführen.

DeddyH 9. Dez 2010 13:44

AW: User klicken unterbinden während Querry läuft
 
Zitat:

Zitat von Luckie (Beitrag 1067378)
Und so lange Operationen verlagert man üblicherweise in einen Thread.

Nur was soll der in diesem Fall nützen? Wenn der Server so lange braucht, um Daten zu liefern, dann braucht er eben so lange.

Luckie 9. Dez 2010 13:50

AW: User klicken unterbinden während Querry läuft
 
Aber dann reagiert das Fenster wem falls noch und der Benutzer kann es bei Seite schieben oder minimieren oder man kann eine Animation einblenden. Zumindest hat der Benutzer nicht mehr den Eindruck, das Programm wäre abgestürzt.

gsh 9. Dez 2010 13:52

AW: User klicken unterbinden während Querry läuft
 
Zitat:

Zitat von Jumpy (Beitrag 1067376)
Nee das hat schon gepasst, da ich hinterher ja Enabled wieder auf true setze. Aber es hat nix gebracht. Wie zuvor kann man wild auf Buttons klicken, ohne das zunächst was passiert, aber wenn die Querry dann fertig geöffnet ist und ein Ergebnis zurückgebracht hat, passiert alles, was nach drücken der Buttons geschehen sollte.

Was den Eindruck des Absturzes angeht, so ist das ja genrell ein Problem, da ja wie geschildert nix passiert, während die Querry läuft und jeder Knopfdruck scheinbar ignoriert wird, so dass ein User denken könnte, das Prog. wäre abgestürzt. Aber damit muss man bei langen Abfragen halt leben. Was halt nur stört ist, das evtl. Buttonklicks während der "Todzeit" des Progs trotzdem irgendwie registriert und dann anschließend ausgeführt werden.

Weitere Ideen gerne willkommen. Vllt. ist ja wirklich der Zeitpunkt bzw. das Ereignis wichtig, bei dem alles wieder aktiviert wird.

Jumpy

Mach mal ein Application.ProzessMessages; bevor du das Form wieder aktivierst. Schöner wäre es das ganze in einen Thread auszulagern.

Jumpy 9. Dez 2010 14:23

AW: User klicken unterbinden während Querry läuft
 
Erstmal danke für das rege Interesse und
hier mal der momentane Code, der nicht funzt wie gesagt Quelle = TADOQuerry:

Code:
procedure TSelector.acOpenExecute(Sender: TObject);
begin
  if Quelle.State in [dsedit,dsinsert] then Quelle.Post;
  Quelle.Close;
  pnltab.Caption:= 'Bitte warten';
  self.Repaint;
  Quelle.SQL.Clear;
  Quelle.SQL.Text:= Memo1.Lines.Text;
  try
    self.Enabled:=false;               //Disabled
    Application.ProcessMessages;
    Quelle.Open;
    Application.ProcessMessages;
    pnltab.Caption:= '';
  except
    on e: exception do
      begin
      pnltab.Caption:= e.message;
      Application.ProcessMessages;
      self.Enabled:=true;
      end;
    end;
  Application.ProcessMessages;
  self.Enabled:=true;                      //enabled
end;
Mit self.enabled scheints da noch komischer zu werden. Manchmal (nicht immer) wird die Anzeige der Daten im Grid nicht aktualisiert. Erst wenn man aus dem Fenster klickt, dann wieder rein, ist es auf einmal da. Luckie scheint recht zu haben, dass das disablen des ganzen Forms "gefährlich" ist.

Hab Alternativ auch mal nur einen Button disabled und den dann gedrückt während die Query lief. Nachdem mir die Daten angezeigt wurden, ging das Fenster auf, dass der Button öffnen sollte.

Was hat es mit der Botschafterwarteschlange auf sich. Kann man da was machen?

Das benutzen eines Threads überleg ich noch, allein um dem User mit einem Fortschrittsbalken Aktivität vorzugaukeln. Das sollte aber unabhängig von dem jetzigen Problem sein, dass ich erst mal gelöst haben will, nämlich das ignorieren von User-Aktionen während die Daten aus der Datenbak geholt werden.

Jumpy

DeddyH 9. Dez 2010 14:33

AW: User klicken unterbinden während Querry läuft
 
Du könntest ein Panel(alClient) auf die Form legen, da die Controls hinein und dann das Panel disablen statt des Formulars. Und zur Botschaftswarteschlange: Windows legt die Botschaften, die an Dein Fensterhandle gehen, in dieser Schlange ab. Während zeitintensiver Berechnungen wird diese aber nicht abgearbeitet (außer man ruft Application.ProcessMessages auf, was genau dies tut). So kann es dann kommen, dass Benutzereingaben erst mit einiger Verspätung Wirkung zeigen.

Luckie 9. Dez 2010 14:36

AW: User klicken unterbinden während Querry läuft
 
Zitat:

Zitat von Jumpy (Beitrag 1067392)
Hab Alternativ auch mal nur einen Button disabled und den dann gedrückt während die Query lief. Nachdem mir die Daten angezeigt wurden, ging das Fenster auf, dass der Button öffnen sollte.

Das sollte nicht sein. Deaktivierte Schaltflächen erhalten keine Klick-Nachrichten.

Jumpy 9. Dez 2010 14:44

AW: User klicken unterbinden während Querry läuft
 
Zitat:

Zitat von Luckie (Beitrag 1067395)
Das sollte nicht sein. Deaktivierte Schaltflächen erhalten keine Klick-Nachrichten.

Genau das macht mich ja auch so stutzig und läßt mich vermuten, das der Versuch mit einem Panel wie von DeddyH vorgeschlagen auch nix bringen wird.

Hab mal einfach nach dem
Quelle.Open;
showmessage('AAAAhhhhrg');
eingebaut.

Und siehe da. Das ganze rumgeklicke wird ignoriert. Ich vermute daher, dass die Klicks in der Botschafterschlange landen, dann geht aber das modale showmessage auf. Nun werden alle Klicks abgearbeitet, laufen aber ins leere, wenn sie nicht gerade die OK-Taste des Messagefensters treffen (wg. modal) und das wars dann.
Ich denk jetzt ernstahft darüber nach ein modales Mini-Form aufzumachen, dass die Klicks abfängt und es dann wieder zuzumachen, aber das kann es doch nicht sein...

s.h.a.r.k 9. Dez 2010 14:52

AW: User klicken unterbinden während Querry läuft
 
Dieses Form.Enabled auf False setzen ist nicht gerade sehr schön imho. Wenn es wirklich längere Operationen sind (>2 Sek.) dann sollte man sich wahrlich überlegen das ganze in einen Thread auszulagern, so wie Luckie gesagt hat. Ebenso sollte man sich überlegen, so wenig wie möglich zu disablen oder evtl. gleich ein modale Ladeform einzubauen. Stellt dir mal vor du bist der User und bekommst sehr wenig Feedback darüber, was deine Anwendung denn gerade macht.

Stell dir vor Windows kopiert Dateien ohne den Kopier-Dialog!? Was würdest denn davon halten? Und was würdest davon halten, wenn Windows komplett anhält (bzw. sich disabled) bis so ein Kopiervorgang abgeschlossen ist?! Mir ist schon klar, dass der Vergleich aufgrund der Multitaskfähigkeit von Windows etwas hinkt, aber ich denke es ist klar, was ich meine ;)

Der Startup großer Anwendungen wird bei mir z.B. immer in einen Thread ausgelagert. Dort werden alle Objekte erzeugt, Daten aus der DB geladen etc. Von diesem Thread aus werden Nachrichten an einen Ladescreen (Stichwort: Splashscreen) geschicht und so bekommt der User Feedback über den aktuellen Fortschritt.

DeddyH 9. Dez 2010 14:53

AW: User klicken unterbinden während Querry läuft
 
Hast Du das Disablen auch vor das Öffnen der Query gesetzt?

Jumpy 9. Dez 2010 15:06

AW: User klicken unterbinden während Querry läuft
 
Zitat:

Zitat von DeddyH (Beitrag 1067408)
Hast Du das Disablen auch vor das Öffnen der Query gesetzt?

Ja. Aber ich hab es innerhalb des try-Blocks gesetzt. Als letzten Versuch hab ich es mal davor gesetzt und auf einmal klappt es. Keine Ahnung warum das einen Unterschied macht.
Wenn einer 'ne Idee hat wieso, her damit, denn ich lerne gerne neues.
Hab jetzt auch wieder die Version genommen, wo nur die ActionList suspended wird.

Code:
procedure TSelector.acOpenExecute(Sender: TObject);
begin
  if Quelle.State in [dsedit,dsinsert] then Quelle.Post;
  Quelle.Close;
  ActionList1.State:= asSuspendedEnabled; //hier ist es jetzt
  pnltab.Caption:= 'Bitte warten';
  self.Repaint;
  Quelle.SQL.Clear;
  Quelle.SQL.Text:= Memo1.Lines.Text;
  try
    //hier war es vorher
    Quelle.Open;
    pnltab.Caption:= '';
  except
    on e: exception do pnltab.Caption:= e.message;
  end;
  Application.ProcessMessages;
  ActionList1.State:= asNormal; //hier wieder alles möglich
end;
Damit ist mein Problem gelöst, das der User keine Buttons mehr klicken kann. Gleichzeitig ist aber das Form noch enabled was mir auch lieber ist (und z.B. Verschiebbar). Ich werd jetzt morgen noch einen Thread dafür aufsetzen, damit ich dem User Fortschritt vorgaukeln kann und bin happpy.

Danke für die viele Hilfe bei meinem ertsen Post und Problem hier. Wird bestimmt nicht das letzte bleiben, da ich gerade erst mit Delphi angefangen hab,
Jumpy.

mz23 19. Dez 2010 08:57

AW: User klicken unterbinden während Querry läuft
 
Hallo Jumpy,

Zitat:

Zitat von Jumpy (Beitrag 1067363)
Danke erstmal. Das Problem ist halt, dass es massig andere Buttons auf dem Form gibt, und ich nicht 20 mal ButtonXY.Enabled im Code haben will. Daher mein versuch über die ActionList. Versuch jetzt mal den Vorschlag mit dem Form.Enabled.

Jumpy

Du kannst eine for-Schleife über alle Objekte machen,
die TButtons (bzw. TCheckBoxes oder TRadioButtons oder
TEdits) sind und diese dann Enabled:=False setzen.

So hast Du nur eine Schleife, die du auch nicht bearbeiten
mußt, wenn Buttons wegfallen bzw. hinzukommen sollten:))

Das crHourGlas und crDefault setzen ist ein guter Tipp
von einem anderen Antworter hier. Allerdings genügt ein
nur setzen nicht ohne ein UpDate bzw. Refresh und danach ein
kurzes Sleep() einzufügen.

Alles klar,
MfG Manfred Zenns

PS: Ich gebe hier nur "meine" Erfahrungen mit Delphi wieder.

Oops:
Ist mir noch was eingefallen.
Bevor du die Action startest, setze ein Form-großes TPanel
(über alle Objekte) mit Text, was nun läuft.

Erhalten dann die Objekte in deinem Form Änderungen,
und sind diese abgeschlossen (!?!) entferne das Panel
über Visible wieder.

Alle Klicks in der Zwischenzeit hat dann das Panel
abgefangen.

Aber ich gebe dir recht, es muß eine elegantere Lösung
geben.

Sir Rufo 19. Dez 2010 09:57

AW: User klicken unterbinden während Querry läuft
 
So müsste es eigentlich funktionieren:
Delphi-Quellcode:
ActionList1.Enabled := False;
Application.ProcessMessages; // evtl. Unnötig
try
  // jetzt das ganze Geraffel ausführen
finally
  Application.ProcessMessages;
  ActionList1.Enabled := True;
end;


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