Entwickler-Ecke

Sonstiges (Delphi) - Leertaste und OnClick von Steuerelementen mit Focus


MeierZwoo - Di 30.07.13 23:19
Titel: Leertaste und OnClick von Steuerelementen mit Focus
Hi,

ich habe zwecks Eingabebestätigung die Leertaste (ASCII 32dec) eingesetzt, weil sie schon groß ist und sie mit der linken Hand gut antatschbar ist, während die rechte auf der Maus bleibt. Um mich dann zu wundern, daß ständig irgendwelche Checkboxen schalteten, wenn cih die Leertaste für meine gewünschte Funktion betätigte - bis ich feststellte, daß die Leertaste auf ein Steuerelement mit Focus als OnClick wirkt.

Um das zu verhindern, habe ich allen aktuell vorhandenen Steuerelementen auf der aktuellen Form den Focus per

Delphi-Quelltext
1:
2:
3:
4:
5:
procedure xxxForm.OnClickyyy (Sender: TObject);
begin
  ...
  xxxForm.ActiveControl:=Nil;
end;

in jedem OnClick entzogen.

Gibt es eine einfachere, zentralere Methode, die Taste #32 nur als Tasteneingabe zur Verfügung zu haben, also das OnClick Auslösen per #32 zu unterbinden?

MfG


FinnO - Di 30.07.13 23:54

user profile iconMeierZwoo hat folgendes geschrieben Zum zitierten Posting springen:
ich habe zwecks Eingabebestätigung die Leertaste (ASCII 32dec) eingesetzt [...]


Ohne dir zu nahe treten zu wollen... Zur Eingabebestätigung gibt es eine Eingabetaste (aka Enter). Die heißt nicht zum Spaß so. Ferner: Du musst die Hand auch nicht von der Maus nehmen, wenn du mit der linken Hand die Eingabetaste drückst. Groß ist sie auch - was will man mehr?

Gruß


MeierZwoo - Mi 31.07.13 00:14

user profile iconFinnO hat folgendes geschrieben Zum zitierten Posting springen:
Zur Eingabebestätigung gibt es eine Eingabetaste (aka Enter).

Ohne dir nahe treten zu wollen: das hilft nun ungemein weiter.

Außerdem gibt es auf normalen Tastauren zwei Enter-Tasten, nicht eine.


FinnO - Mi 31.07.13 00:48

Siehe auch: Microsoft Dev Center: Keyboard [http://msdn.microsoft.com/en-us/library/windows/desktop/bb545460.aspx#concepts]
Zitat:
Spacebar, Enter, and Esc keys. The spacebar activates the control with input focus, whereas the Enter key activates the default button. Pressing the Esc key cancels or closes the window.


Du begehst sozusagen ein Rebellion mit deinem Vorhaben. Daher: Warum Dinge nicht so machen, wie sie gedacht sind?


MeierZwoo - Mi 31.07.13 05:44

Die Rebellion ist wohl ehr, eine Buchstabentaste (Space) mit Steuerfunktion zu belegen wie eine Steuertaste. Zumal diese Funktion ja bei jedem Editierfeld unterdrückt werden muß.

Ich habe bis gestern nicht gewußt, daß Space solche Wirkung hat - und ich wette, die wenigsten Benutzer wissen dies, da die wenigsten wohl Windows mit der Tastatur steuern können und dieses Wissen meist bei TAB endet.

Die einzige Funktion, die ich der Leertaste zugestehen würde, ist "..any key".

FinnO, außerdem widerspricht deine zweite Aussage deiner ersten, in der Du die Entertaste vorschlägst - denn die würde ja auf einen aktivierten Button wirken, in meiner Situation einem Reset-Button. Schon aus diesem Grund habe ich die Entertaste nie in Erwägung gezogen.

Es gibt Situationen, in denen der (kaum bekannte und wohl nie benutzte) Standard eben nicht ausreicht oder störend ist. In meiner angesprochenen Bediensituation benötige ich zu einer kontiunierlichen Mausbewegung eine ständige Bestätigung von Punkten auf der Mausspur. Wobei die meist zittrige Mausbewegung auch mit feineren Tastatur-Steuerbewegungen ergänzt wird/werden kann.

Der Benutzer hat (als Rechtshänder) also die rechte Hand an der Maus, die linke Hand auf dem klassischen Cursorkreuz S-D-E-X oder sonstwo und die Leertaste bietet sich zum markieren an - keine andere Taste ist so schnell, einfach und (treff)sicher erreichbar und hat ja auch snsonsten keine andere Funktion (dachte ich bis gestern). Alles andere führt zu ungewöhnlichen Verrenkungen.

Und da es genug Programme gibt, die den Focus innerhalb der eigenen Form gänzlich unterbinden, dachte ich an eine solche Lösung - bzw. allen Steuerelementen per Eigenschaft keinen Focus zuzuweisen.


Delete - Mi 31.07.13 07:31

user profile iconMeierZwoo hat folgendes geschrieben Zum zitierten Posting springen:
Der Benutzer hat (als Rechtshänder) also die rechte Hand an der Maus, die linke Hand auf dem klassischen Cursorkreuz S-D-E-X oder sonstwo und die Leertaste bietet sich zum markieren an - keine andere Taste ist so schnell, einfach und (treff)sicher erreichbar und hat ja auch snsonsten keine andere Funktion (dachte ich bis gestern). Alles andere führt zu ungewöhnlichen Verrenkungen.

Also wenn ich meine linke Hand über den Cursortasten habe, dann bin ich damit schneller auf Enter als auf Space.


MeierZwoo - Mi 31.07.13 08:11

user profile iconPerlsau hat folgendes geschrieben Zum zitierten Posting springen:
Also wenn ich meine linke Hand über den Cursortasten habe, dann bin ich damit schneller auf Enter als auf Space.

Das klassische Cursorkreuz S-D-E-X liegt aber recht weit von Enter entfernt, nämlich genau entgegen gesetzt weit links.

Logo könnten die Cursortasten auch per Voreinstellung auf die normalen Cursortasten nach rechts verlegt werden (z.B. auch für Linkshänder), nur ändert das nichts an der Grundproblematik, daß die Entertaste auch nicht zu gebrauchen ist, da sie auch auf Focus-Steuerelemente wirkt, also dieselbe Problematik mit dem Focus besteht wie bei der Leertaste.


Mathematiker - Mi 31.07.13 08:32

Hallo,
um zur eigentlichen Frage zurückzukommen:
Eine einfache, wenn auch nicht professionelle, Idee ist es, wenn Du einem Menüpunkt die Space-Taste als Hotkey zuweist. Dieser Menüpunkt erhält gleichzeitig Deine geplante Space-Methode und wenn man ihn nicht sehen soll, erhält er noch visible=false.
Danach schaltet die Space-Taste fokusierte Objekte nicht mehr.
Wie gesagt, nicht professionell, aber wirksam.

Beste Grüße
Mathematiker


MeierZwoo - Mi 31.07.13 09:43

Mathematiker, danke, aber eine "Buchstabentaste" als HotKey zu binden, würde auch bedeuten, diese Bindung nach Ende des Programmteils wieder unbedingt aufheben zu müssen, weil #32 sonst im Restprogrammm in Schreibfeldern fehlt. Im Hinblick auf die Programmpflege zu kritisch (man darf es ja auch in fünf oder zehn Jahren nicht übersehen). Außerdem würde ein Teil eines Steuerelementes blockiert, was im Hinblick auf die Programmpflege genau so kritsisch ist.

Da ist meine eben rein lokale Lösung mit einem fetten Kommentar an der Tastenabfrage noch die praktikabelste und zukunftsträchtigste Lösung: eine Zeile pro Steuerelement-OnClick und nur lokal und nur in diesem einen Programmteil. Wenn auch wenig elegant, vorallem weil man zur Laufzeit sieht, wie der Focus entzogen wird, wenn das Steuerelement benutzt wird.


jaenicke - Mi 31.07.13 11:27

Du müsstest die Taste als Dialogtaste abfangen können indem du bei WM_GETDLGCODE sagst, dass du die Behandlung übernimmst...
http://msdn.microsoft.com/en-us/library/windows/desktop/ms645425(v=vs.85).aspx
(speziell DLGC_RADIOBUTTON usw.)


MeierZwoo - Mi 31.07.13 12:46

user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
Du müsstest die Taste als Dialogtaste abfangen können indem du bei WM_GETDLGCODE sagst, dass du die Behandlung übernimmst...

Ja, das funktioniert, habe es für ein Element angetestet.

Aber der Aufwand ist erheblich, weil es für jedes Kontrollelement implementiert werden muß - und davon habe ich in diesem Programmteil einen Button, zwei CheckBoxen und acht RadioButtons. Also belibe ich bei meiner uneleganten, brutalen Lösung, auch wenn dann kein Focus mer vorhanden ist und kein Anwender sich mit TAB durch die Elemente wühlen kann (was wohl eh niemand vorhat).

Danke für die Antworten, Thema damit erledigt :)


jaenicke - Mi 31.07.13 13:36

Du musst doch eigentlich nur die WndProc deines Formulars überschreiben hätte ich gedacht?


MeierZwoo - Mi 31.07.13 14:10

user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
Du musst doch eigentlich nur die WndProc deines Formulars überschreiben hätte ich gedacht?

Auf einzelne, aktuelle Steuerelemente bezogen, habe ich es ja noch einigermaßen testweise grob hinbekommen, wenn auch nicht ganz begriffen.

WndProc der Form zu ändern ist mir, so wie ich es bisher nachgelesen, habe etwas zu hoch. Und jeder Fehler, jede Unsauberkeit wirkt sich dann auf das gesamte Programm aus nicht nur auf den lokalen kleinen Programmteil- mit endlosen Fehlersuchen.

Allerdings hast Du in der Weise recht, daß meine Eingangsfrage darauf abzielte, es "zentral" zu regeln.

Ich hätte vor 20 Jahren mit OOP anfangen sollen, als alle noch übten - nun erst ist nach 40 Jahren Zwangssteuerung etwas zu spät, das alles in den Kopf zu bekommen *g

Danke :)


Martok - Mi 31.07.13 18:36

user profile iconMathematiker hat folgendes geschrieben Zum zitierten Posting springen:
Eine einfache, wenn auch nicht professionelle, Idee ist es, wenn Du einem Menüpunkt die Space-Taste als Hotkey zuweist. Dieser Menüpunkt erhält gleichzeitig Deine geplante Space-Methode und wenn man ihn nicht sehen soll, erhält er noch visible=false.
Menü ist nicht ganz so einfach, mit einer Action geht das wesentlich besser. Die mischen sich nämlich wirklich überall ein (was manchmal auch nervt, hier aber wunderbar passt) und man wird sie einfach wieder los ;-)

user profile iconMeierZwoo hat folgendes geschrieben Zum zitierten Posting springen:
Mathematiker, danke, aber eine "Buchstabentaste" als HotKey zu binden, würde auch bedeuten, diese Bindung nach Ende des Programmteils wieder unbedingt aufheben zu müssen, weil #32 sonst im Restprogrammm in Schreibfeldern fehlt.
Eine Zeile, worst case. Sowas sollte man eh dokumentieren.

Für Messplätze ("jetzt mal bitte einen Wert einlesen") mach ich das meistens so, wie im Anhang.


Gerd Kayser - Mi 31.07.13 19:37

user profile iconMeierZwoo hat folgendes geschrieben Zum zitierten Posting springen:
Aber der Aufwand ist erheblich, weil es für jedes Kontrollelement implementiert werden muß - und davon habe ich in diesem Programmteil einen Button, zwei CheckBoxen und acht RadioButtons.

Ersetze doch einfach den Button, die Checkboxen und RadioButtons durch SpeedButtons. Die können nicht den Focus erhalten.


MeierZwoo - Mi 31.07.13 22:18

Martok, danke für die Mühe, es hat auch funktioniert. Nur dann ist das aufgetreten, was ich befürchtet habe:
Beim Start (Form.Created) den ShortCut eingerichtet und disabled,
beim Start des Programmteiles enabled,
am Ende des Programmteiles wieder disabled ...
danach lies es sich nicht wieder enablen

Das liegt bestimmt an mir und der Komplexität des Programmes und der mittlerweile teils chaotischen Struktur.

Da gefällt mir Gerds Vorschlag wesentlich besser, weil der vom Chaos unabhängig ist auch wenn er anfänglich mehr Arbeit macht zumal ich noch nie einen SpeedButton benutzt habe und die Abhängigkeiten untereinander bzw. Unabhängigkeiten noch nicht kenne. Aber diese Lösung hat auch den Vorteil, daß sie häppchenweise implementiert werden kann.

Danke :)


Gerd Kayser - Mi 31.07.13 22:52

user profile iconMeierZwoo hat folgendes geschrieben Zum zitierten Posting springen:
zumal ich noch nie einen SpeedButton benutzt habe und die Abhängigkeiten untereinander bzw. Unabhängigkeiten noch nicht kenne.

Die wichtigste Eigenschaft bei den SpeedButtons dürfte im Hinblick auf den Ersatz für die Checkboxen bzw. RadioButtons der GroupIndex sein. Damit kannst Du die SpeedButtons gruppieren und somit bestimmen, ob z. B. mehrere SpeedButtons gleichzeitig gedrückt sein dürfen.
Erstelle einfach mal ein kleines Testobjekt mit einigen SpeedButtons und spiele mal mit dem GroupIndex herum.
Ich persönlich verwende am liebsten die TLMDSpeedButtons von http://www.lmdinnovative.com/. Damit kann man noch einige Dinge mehr machen. Schau Dir mal das Programm hier an http://www.entwickler-ecke.de/viewtopic.php?t=111318&highlight=etiketten. Dort verwende ich diese TLMDSpeedButtons.


MeierZwoo - Do 01.08.13 12:00

Zu Martoks Hotkey-Version möchte ich abschließend nur noch sagen, daß diese Methode bestimmt korrekt funktioniert, wenn man nicht wie ich (aus Versehen) eine quasi Kreuzreferenz zwischen enablen und disablen einbaut.

Zu Gerds SpeedButton-Vorschlag (hier) abschließend: Ich werde mir die SpeedButton in Ruhe ansehen, eben hat der sachliche Teil Vorrang und eine weitere Diskussion in diesem Thread würde das Prinzip "Eine Frage, ein Thread" sprengen.


MeierZwoo - Fr 09.08.13 16:44

@Gerd Kayser
Das mit den SpeedButtons als Ersatz für RadioButtons und CHeckBoxen klappt nicht. Ich kann den ersetzten SpeedButtons und RadioButtons einfach nicht das "Eindrücken" abgewöhnen, weder mit den SpeedButtons aus Delphi selber noch bei den TLMDSpeedButtons.

Ich habe keine Eigenschaft gefunden, die diese "Eindrücken" beim Anklicken unterbindet :(


Gerd Kayser - Fr 09.08.13 17:03

user profile iconMeierZwoo hat folgendes geschrieben Zum zitierten Posting springen:
Ich habe keine Eigenschaft gefunden, die diese "Eindrücken" beim Anklicken unterbindet :(

Meinst Du mit "Eindrücken" das Einrasten bei den SpeedButtons?
Schau Dir mal GroupIndex und AllowAllUp bei den SpeedButtons an. Ansonsten schicke mir mal per private Mail die Exe und eine genaue Beschreibung des Fehlverhaltens zu.


MeierZwoo - Fr 09.08.13 17:45

AllowAllUp
wirkt nur auf die Gruppenbildung und auch nur bei GroupIndex>0.

Der GroupIndex hat damit auch nichts zu tun.

Die Eigenschaft Flat soll das "eindrücken" verhindern oder ermöglichen, tut es aber nicht.

Mit "Eindrücken" meine ich das optische Bewegen beim Anklicken wie bei einem normalen Button, der sich beim Anklicken scheinbar versenkt, danache wieder erhaben wird.

Dies ist bei Buttions ja ok, bei CheckBoxen und RadioButtons aber falsch, denn dort ändert sich nur der Inhalt (Mit Haken oder ohne Haken bzw. mit Punkt oder ohne Punkt) aber nicht die scheinbare optische Höhe gegenüber der Basisfläche.

user defined image


MeierZwoo - Fr 09.08.13 18:01

Ich dachte, die Eigenscgaften, die dies regeln, seine bekannt nur ICH finde die nicht. Für ein Beispiel muß ich erst ein Demo-Projekt anlegen ...


jaenicke - Fr 09.08.13 19:13

Das sieht aus wie die Fokusmarkierung, wenn ich mich an die graue Vorzeit ohne Themes richtig erinnere. Da musst du im OnClick den Fokus woandershin setzen.


MeierZwoo - Fr 09.08.13 19:58

user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
Das sieht aus wie die Fokusmarkierung

SpeedButtons haben/erhalten keinen Focus. Das ist ja der Grund, weshalb sie mir in diesem speziellen Abwendungsfall vorgeschlagen wurden uns ich sie auch benutzen möchte.


jaenicke - Fr 09.08.13 20:05

Ich meinte die Checkboxen, an die du geschrieben hast "Soll aber nicht". ;-)


Gerd Kayser - Fr 09.08.13 20:12

Wenn die nachgebildeten Checkboxen diesen Klickeffekt haben, dann verwende halt Panels. Ein Beispiel, wie das aussehen könnte, findest Du im Anhang.


MeierZwoo - Fr 09.08.13 21:02

user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
Ich meinte die Checkboxen, an die du geschrieben hast "Soll aber nicht". ;-)

Diese CheckBoxen sind keine CheckBoxen, sondern EIN SpeedButton mit der Grafik einer CheckBox und den drei Stadien vorm Klicken [ ], beim Klicken [x] und nach dem Klicken[x] um zu zeigen, wie es sich beim Klick eindrückt.

Gerd hatte ja gesagt, ich können CheckBoxen und RadioButtons per SpeedButtons in deren Lock ersetzen, um mein Focus-Problem los zu werden, da SpeedButtons keinen Focus erhalten.

user profile iconGerd Kayser hat folgendes geschrieben Zum zitierten Posting springen:
Wenn die nachgebildeten Checkboxen diesen Klickeffekt haben, dann verwende halt Panels.

Dann verliere ich grade bei den gruppierten RadioButtons ja alle Gruppeneigenschaften und muß diese gegenseitigen Abhängigkeiten nachflicken. Ich dachte, Du wüßtest wie man RadioButtons und CheckBoxen aus SpeedButtons nachbildet, ohne daß die sich beim Klicken versenken, weil der Vorschlag ja von dir kam.

Da ist meine augenblickliche Lösung, mit einer Zeile pro OnKlick den Focus zu killen, immer noch die simpelste Lösung. Und da die CheckBoxen eh duch Buttons, in diesem Fall SpeedButtons ersetzt werden sollen, die sich ja reindrücken sollen ist das Focus-Problem damit erstmal aus der Welt.

Danke für die Antworten :)


Gerd Kayser - Fr 09.08.13 23:43

user profile iconMeierZwoo hat folgendes geschrieben Zum zitierten Posting springen:
Dann verliere ich grade bei den gruppierten RadioButtons ja alle Gruppeneigenschaften und muß diese gegenseitigen Abhängigkeiten nachflicken.

SpeedButtons beim Klicken versinken nun einmal kurz. Wenn Dich dieser kleine Schönheitsfehler stört, mach's halt zum Beispiel mit Panels. Im nachfolgenden Beispielprogramm verwende ich den Zeichensatz Webdings 2, um ein Kreuzchen anzuzeigen. Die Tag-Eigenschaft wird verwendet, um eine Gruppe zu bilden. Innerhalb der Gruppe sind die Panels aufsteigend nummeriert.
Beispiel Gruppe 1: 1. Panel hat den Tag-Wert 10, das nächste 11 usw.
Bei der Gruppe 2 analog 20, 21, 22.
Die Zehnerstelle gibt also die Gruppe an. Dadurch, dass jedes Panel einen eigenen und einmaligen Tag-Wert hat, kann man beim Programmstart jedes Panel gezielt ansprechen und den Status "gesetzt" oder "nicht gesetzt" aus einer Ini-Datei auslesen und im Programm entsprechend den Status der Panels setzen bzw. beim Programmende auslesen (hier im Programmbeispiel nicht implementiert).
Das Hin- und Herschalten bei den einzelnen Panels sieht so aus:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
procedure TForm1.PanelGroupClick(Sender: TObject);
var
  Schleife : integer;
  Merken   : string;
  Gruppe   : integer;
begin
  with Sender as TPanel do
    begin
      Merken := TPanel(Sender).Caption;
      Gruppe := TPanel(Sender).Tag div 10;
    end;

  for Schleife := 0 to ComponentCount - 1 do
    if (Components[Schleife] is TPanel) and
      (TPanel(Components[Schleife]).Tag div 10 = Gruppe) then
      begin
        TPanel(Components[Schleife]).Caption := '';
      end;

  TPanel(Sender).Caption := Merken;
  if TPanel(Sender).Caption = 'Ñ' then
    TPanel(Sender).Caption := ''
  else
    TPanel(Sender).Caption := 'Ñ';
end;


Anhand des Tag-Wertes könntest Du mit einer Case-Anweisung auf die Änderungen reagieren und entsprechende Eigenschaftswerte in Deinem Programm setzen. Wie Du siehst hält sich der Aufwand sehr in Grenzen.


MeierZwoo - Sa 10.08.13 19:31

Gerd, danke, sehr schön. Nur werde ich in diesem Projekt in Hinblick auf die Pflege bei meinem Stil bleiben und merke mir deine Anregungen für später.

Ich habe nun die CheckBoxen durch "selbstgemachte" Buttons ersetzt, bei denen kein Focus vorhanden ist und die Abhängigkeiten von mir selbst gesetzt werden können und nicht durch zig (fremde) sich immer wieder ausschließende bzw. beeinflussende Eigenschaften.

Die beiden Gruppen RadioButtons belasse ich erstmal so mit brutalem killen des Focus.

Ich danke allen für ihre Mühe und Antworten - ich kann nun mit meiner Lösung erstmal leben und mich mit den sachlichen, mathematischen Problemen weiter beschäftigen :)