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/)
-   -   [gelöst] Cursortasten von Buttons fernhalten (https://www.delphipraxis.net/193886-%5Bgeloest%5D-cursortasten-von-buttons-fernhalten.html)

Schwedenbitter 19. Sep 2017 16:12


[gelöst] Cursortasten von Buttons fernhalten
 
Hallo,

ich nutze dynamisch erzeugte Buttons auf einer TScrollBox. Diese können mit der Maus frei verschoben werden (ähnlich Delphi IDE). Nun möchte ich eine Art Raster dadurch erreichen, dass der Benutzer diese Buttons ebenfalls mittels Tastatur verschieben kann und ich dann die Werte auf Vielfache von 8, 16 oder so runde.
Mit einem Button allein klappt das prima. Mit 2 oder mehr nicht, weil dann mit den Cursortasten der Focus gewechselt und meine Aktion auf eine anderes Control angewendet wird. Im www stand dazu, dass man den Buttons diese Verhalten abgewöhnen kann, indem man
Delphi-Quellcode:
Key:= 0;
setzt.

Aber ganz so einfach scheint es dann doch nicht zu sein. Denn folgender Code funktioniert eben nur bedingt:
Delphi-Quellcode:
procedure TForm1.FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
var
   aControl         : TWinControl;
   aButton         : TButton;
begin
   aControl:= ActiveControl;         // aktives Control merken
   if (aControl is TButton) then
   begin
      aButton:= (aControl as TButton);
      case Key of
         VK_LEFT   : aButton.Left:= aButton.Left - 16;
         VK_UP      : aButton.Top:= aButton.Top - 16;
         VK_RIGHT   : aButton.Left:= aButton.Left + 16;
         VK_DOWN   : aButton.Top:= aButton.Top + 16;
      end;
      Key:= 0;                        // <== Tastaturpuffer gelöscht.
      SetFocusedControl(aControl);   // <== Focus nochmal gesetzt
   end;
end;
Ich vermute also, dass VK_LEFT & Co. immer noch irgendwo im Tastaturpuffer rumlungern. Wie löse ich das Problem denn richtig?

nahpets 19. Sep 2017 16:26

AW: Cursortasten von Buttons fernhalten
 
Rate jetzt mal:

Ändert sich das Verhalten, wenn Du statt FormKeyUp FormKeyDown nutzt?

Redeemer 19. Sep 2017 23:47

AW: Cursortasten von Buttons fernhalten
 
Das ist das falsche Event. Dein Code gehört nicht in
Delphi-Quellcode:
TForm.OnKeyUp
sondern nach
Delphi-Quellcode:
TApplicationEvents.OnShortCut
(oder von mir aus
Delphi-Quellcode:
TApplication.OnShortCut
). Da dann einfach noch nach dem Änderung
Delphi-Quellcode:
Handled := True
setzen und dann ist an der Stelle Schluss mit der Verarbeitung der Taste.
Eine kleine Umstellung deiner Methode ist allerdings nötig, um deine Taste aus dem
Delphi-Quellcode:
TWMKey
-Typ zu kriegen:
- Der Parameter
Delphi-Quellcode:
Key
heißt jetzt
Delphi-Quellcode:
Msg.CharCode
. Auch hier gehen die virtuellen Key-Codes, die du verwendest.
- Für den
Delphi-Quellcode:
TShiftState
(wenn du ihn brauchst) gibt es
Delphi-Quellcode:
Forms.KeyDataToShiftState(Msg.KeyData)
.

Schwedenbitter 20. Sep 2017 07:54

AW: Cursortasten von Buttons fernhalten
 
Zitat:

Zitat von Redeemer (Beitrag 1381677)
Das ist das falsche Event. Dein Code gehört nicht in
Delphi-Quellcode:
TForm.OnKeyUp
sondern nach
Delphi-Quellcode:
TApplicationEvents.OnShortCut
(oder von mir aus
Delphi-Quellcode:
TApplication.OnShortCut
)...

Danke, das passt genau! Ich habe das jetzt so zusammengebaut:
Delphi-Quellcode:
procedure TForm1.ApplicationEvents1ShortCut(var Msg: TWMKey;
   var Handled: Boolean);
begin
   Handled:= True;
   if (ActiveControl is TButton) then
   begin
      case Msg.CharCode of
         VK_LEFT   : (ActiveControl as TButton).Left:= (ActiveControl as TButton).Left - 16;
         VK_UP      : (ActiveControl as TButton).Top:= (ActiveControl as TButton).Top - 16;
         VK_RIGHT   : (ActiveControl as TButton).Left:= (ActiveControl as TButton).Left + 16;
         VK_DOWN   : (ActiveControl as TButton).Top:= (ActiveControl as TButton).Top + 16;
      else
         Handled:= False;
      end
   end
   else Handled:= False;
end;
Ich habe es so unschön gebaut, weil ich es unübersichtlicher gefunden hätte, 4 Mal nur wegen
Delphi-Quellcode:
Handled:= True;
ein
Delphi-Quellcode:
begin ... end;
einzufügen. Es geht vermutlich auch schöner.
Und
Delphi-Quellcode:
TApplication.OnShortCut
finde ich sogar noch besser, weil ich keine zusätzliche Komponente mit reinbasteln muss. Und schließlich und letztlich habe ich mal im Code von Vcl.AppEvnts geschnüffelt. Beim weiteren Suchen bin ich dann auf die Möglichkeit gestoßen, das ganze auch komplett über die Messages abzufangen mit z.B.
Delphi-Quellcode:
procedure CMDialogKey(var Message: TCMDialogKey); message CM_DIALOGKEY;
. Nachteil ist allerdings, dass es kein Handled gibt und man aufpassen muss, die nicht ausgewerteten Tasten mit Inherited schön weiterzugeben.

nahpets 20. Sep 2017 10:13

AW: [gelöst] Cursortasten von Buttons fernhalten
 
Noch ein bisserl kürzer:
Delphi-Quellcode:

procedure TForm1.ApplicationEvents1ShortCut(var Msg: TWMKey; var Handled: Boolean);
begin
   if (ActiveControl is TButton) then
   begin
      Handled:= True;
      case Msg.CharCode of
         VK_LEFT : (ActiveControl as TButton).Left := (ActiveControl as TButton).Left - 16;
         VK_UP   : (ActiveControl as TButton).Top := (ActiveControl as TButton).Top - 16;
         VK_RIGHT : (ActiveControl as TButton).Left := (ActiveControl as TButton).Left + 16;
         VK_DOWN : (ActiveControl as TButton).Top := (ActiveControl as TButton).Top + 16;
      else
         Handled := False;
      end
   end;
end;

DeddyH 20. Sep 2017 11:01

AW: [gelöst] Cursortasten von Buttons fernhalten
 
Oder auch
Delphi-Quellcode:
procedure TForm1.ApplicationEvents1ShortCut(var Msg: TWMKey; var Handled: Boolean);
const
  STEP = 16;
var
  Button: TButton;
begin
  if (ActiveControl is TButton) then
    begin
      Button := TButton(ActiveControl);
      Handled := true;
      case Msg.CharCode of
         VK_LEFT : Button.Left := Button.Left - STEP;
         VK_UP : Button.Top := Button.Top - STEP;
         VK_RIGHT : Button.Left := Button.Left + STEP;
         VK_DOWN : Button.Top := Button.Top + STEP;
      else
         Handled := False;
      end;
    end;
end;

Schwedenbitter 20. Sep 2017 11:11

AW: [gelöst] Cursortasten von Buttons fernhalten
 
Zitat:

Zitat von nahpets (Beitrag 1381689)
Noch ein bisserl kürzer:
...

Das stimmt! Ich wusste nicht, dass von Hause aus gilt
Delphi-Quellcode:
Handled:= False;
. Ich werde gleich mal den Code anpassen. Ich habe es übrigens bei mir auch mit einer Variable besser lesbar gemacht.

Allerdings ist die Lösung doch (noch) nicht perfekt:
Wenn ich jetzt ein weiteres Fenster öffne und dort mit den Cursortasten rumhantiere, dann bewegt sich munter der jeweils auf dem Hauptform befindliche, aktive TButton. Auf dem Kindfenster passiert hingegen nichts mehr :| Das ist sehr ungünstig. Daher noch ein weiteres Codeschnipsel :lol::
Delphi-Quellcode:
procedure TForm1.ApplicationEvents1ShortCut(var Msg: TWMKey; var Handled: Boolean);
const
  STEP = 16;
var
  Button: TButton;
begin
  if (Screen.ActiveForm = self) and // Ist das gewünschte Fenster aktiv?
     (ActiveControl is TButton) then
    begin
      Button := TButton(ActiveControl);
      Handled := true;
      case Msg.CharCode of
         VK_LEFT : Button.Left := Button.Left - STEP;
         VK_UP : Button.Top := Button.Top - STEP;
         VK_RIGHT : Button.Left := Button.Left + STEP;
         VK_DOWN : Button.Top := Button.Top + STEP;
      else
         Handled := False;
      end;
    end;
end;

nahpets 20. Sep 2017 11:44

AW: [gelöst] Cursortasten von Buttons fernhalten
 
Passen wir es nochmal an (dann können wir auf die implizit gemachte Annahme über den Wert von Handled verzichten):
Delphi-Quellcode:
procedure TForm1.ApplicationEvents1ShortCut(var Msg: TWMKey; var Handled: Boolean);
const
  STEP = 16;
var
  Button: TButton;
begin
  Handled := False;
  if (Screen.ActiveForm = self) and // Ist das gewünschte Fenster aktiv?
     (ActiveControl is TButton) then
    begin
      Button := TButton(ActiveControl);
      Handled := true;
      case Msg.CharCode of
         VK_LEFT : Button.Left := Button.Left - STEP;
         VK_UP : Button.Top := Button.Top - STEP;
         VK_RIGHT : Button.Left := Button.Left + STEP;
         VK_DOWN : Button.Top := Button.Top + STEP;
      else
         Handled := False;
      end;
    end;
end;

HolgerX 20. Sep 2017 12:58

AW: [gelöst] Cursortasten von Buttons fernhalten
 
Hmm..

Oder noch einfacher, damit dies nur auf dem einen Formular läuft:

OnShortCut vom Formular verwenden, dann brauchst Du kein ApplicationEvents.


Alle Zeitangaben in WEZ +2. Es ist jetzt 22:43 Uhr.

Powered by vBulletin® Copyright ©2000 - 2021, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2021 by Daniel R. Wolf