Discussion:
Checkbox: Status in OnKeyUp ermitteln
(zu alt für eine Antwort)
Holger Schieferdecker
2021-02-23 15:48:32 UTC
Permalink
Hallo,

in einem kleinen Programm (D4) habe ich mehrere Checkboxen, von denen
nur eine oder keine gleichzeitig angehakt sein soll. Dazu habe ich im
OnMouseUp (gleiche Routine für alle Checkboxen) folgendes stehen:

procedure TForm1.CheckBoxFunctionMouseUp(Sender: TObject;
Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
if Sender is TCheckBox then begin
if TCheckBox(Sender).Checked then begin
ClearFunctionCheckboxes(Sender);
end;
StringGrid1.Repaint;
end;
end;

ClearFunctionCheckboxes(Sender) setzt bei allen Checked:=false, nur bei
der des Sender nicht.

procedure TForm1.ClearFunctionCheckboxes(aCBtoTrue:TObject=NIL);
begin
CheckboxReplace.Checked:=false;
CheckBoxDelete.Checked:=false;
CheckBoxInsert.Checked:=false;
CheckBoxEnumerate.Checked:=false;
CheckBoxCorrectNumbering.Checked:=false;
CheckBoxDeleteSep.Checked:=false;
if aCBtoTrue is TCheckBox then begin
(aCBtoTrue as TCheckBox).Checked:=true;
end;
end;

Das klappt auch soweit. Nun ist mir aufgefallen, daß man ja auch mit der
Leertaste das Häkchen einer mittels TAB angesteuerten Checkbox setzen
oder löschen kann. Also habe ich etwas ähnliches mit OnKeyUp gemacht:

procedure TForm1.CheckBoxFunctionKeyUp(Sender: TObject; var Key: Word;
Shift: TShiftState);
begin
if (Sender is TCheckBox) and (Key=VK_SPACE) then begin
// showmessage('Hallo');
if TCheckBox(Sender).Checked then begin
ClearFunctionCheckboxes(Sender);
end;
StringGrid1.Repaint;
end;
end;

Damit klappt es aber nur, wenn ich den Kommentar bei showmessage
entferne. Ohne showmessage sehe ich im Debugger, daß
TCheckBox(Sender).Checked=false ist, obwohl anschließend das Häkchen
gesetzt wird. Was könnte showmessage da noch machen, daß in dem Fall
bereits true gefunden wird? Ist das eine Timing-Geschichte?
Application.ProcessMessages bringt übrigens nichts.

Da das nur ein kleines Programm für den Eigenbedarf ist, ist das kein
echtes Problem, aber mich interessiert, woher der Unterschied kommt. Wie
könnte ich dem auf die Spur kommen? Oder wie könnte ich das anders lösen?

Ja, natürlich könnte ich das ganze auf eine Radiogroup umbauen, dann
bräuchte ich eben ein zusätzliches Item für den Fall, daß keine Funktion
gewünscht ist.

Holger
Jens Kallup
2021-02-24 13:05:03 UTC
Permalink
Hallo Holger,

versuche mal, ob Du die Ojekte in eine
TGroupBox unterbringen kannst.

Jens
Holger Schieferdecker
2021-02-26 08:00:46 UTC
Permalink
Hallo Jens,
Post by Jens Kallup
Hallo Holger,
versuche mal, ob Du die Ojekte in eine
TGroupBox unterbringen kannst.
Du meinst damit die Checkboxen? Das habe ich versucht, ändert aber nichts.

Mir scheint, im OnKeyUp einer Checkbox ist es nicht möglich, den neuen
Zustand schon abzufragen, das .Checked wird wohl erst danach gesetzt.
Ich habe es auch mal mit Lazarus versucht, dort ist das Verhalten
ebenso. Mich wundert eben, daß es mit OnMouseUp klappt. Noch mehr
wundert mich, daß ein eingestreutes showmessage das Verhalten ändert.

Ich muß vielleicht mal den Quelltext einer Checkbox genauer anschauen,
auch wenn ich auf den ersten Blick nichts gesehen habe, wo da auf die
Leertaste reagiert wird.

Holger
Heiko Rost
2021-02-26 09:17:02 UTC
Permalink
Post by Holger Schieferdecker
Mir scheint, im OnKeyUp einer Checkbox ist es nicht möglich, den neuen
Zustand schon abzufragen, das .Checked wird wohl erst danach gesetzt.
Ich habe hier nur D7 zum Testen, und dort gibt es das OnClick-Ereignis.
Damit dürfte das unten angehängte Testprogramm genau das von Dir
gewünschte Verhalten zeigen. Im Unterschied zu Deiner Lösung reagiert es
auf jede Änderung, z. B. auch bei einem zugewiesenen Tastenkürzel.
Deshalb auch das aktiv-Flag, weil das .Checked:=false innerhalb des
OnClick-Ereignisses wieder ain OnClick auslösen kann.

Gruß Heiko

-------------------- hier abschneiden --------------------------------

unit KlickUnit;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls,
Forms, Dialogs, StdCtrls;

type
TForm1 = class(TForm)
CheckBox1: TCheckBox;
CheckBox2: TCheckBox;
CheckBox3: TCheckBox;
CheckBox4: TCheckBox;
procedure FormCreate(Sender: TObject);
procedure CheckBoxClick(Sender: TObject);
private
{ Private-Deklarationen }
public
{ Public-Deklarationen }
end;

var
Form1: TForm1;
Aktiv : Boolean;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);

begin
Aktiv := false;
end;

procedure TForm1.CheckBoxClick(Sender: TObject);
begin
if not aktiv then begin
aktiv:=true;
if sender is tCheckBox then begin
if (sender as tCheckBox).Checked then begin
if sender is tCheckBox then begin
checkbox1.Checked:=false;
checkbox2.Checked:=false;
checkbox3.Checked:=false;
checkbox4.Checked:=false;
(sender as tCheckBox).Checked:=true;
end;
end;
end;
aktiv:=false;
end;
end;

end.
--
Der Mensch ist gut, nur die Nerven sind schlecht.
Mose Ya'aqob Ben-Gavriêl
Holger Schieferdecker
2021-03-02 08:12:24 UTC
Permalink
Hallo Heiko,

entschuldige die Mail neulich, hatte den falschen Antworten-Button erwischt.
Post by Heiko Rost
Post by Holger Schieferdecker
Mir scheint, im OnKeyUp einer Checkbox ist es nicht möglich, den neuen
Zustand schon abzufragen, das .Checked wird wohl erst danach gesetzt.
Ich habe hier nur D7 zum Testen, und dort gibt es das OnClick-Ereignis.
Damit dürfte das unten angehängte Testprogramm genau das von Dir
gewünschte Verhalten zeigen. Im Unterschied zu Deiner Lösung reagiert es
auf jede Änderung, z. B. auch bei einem zugewiesenen Tastenkürzel.
Deshalb auch das aktiv-Flag, weil das .Checked:=false innerhalb des
OnClick-Ereignisses wieder ain OnClick auslösen kann.
Inzwischen habe Deinen Vorschlag mit dem Flag implementiert, das klappt
wie gewünscht. Natürlich wäre es eleganter, nur bei den Checkboxen das
.Checked zu ändern, wo es notwendig ist. Die passenden Abfragen machen
halt den Code etwas länglicher, aber evtl. ändere ich das noch.

Als ich geschrieben hatte, OnClick würde bei mir 3 Mal ausgelöst, hatte
ich das so beobachtet, kann es jetzt aber nicht mehr reproduzieren.

Vielen Dank also für den Tip,
Holger
Christian Schmitt
2021-03-08 14:54:51 UTC
Permalink
Holger Schieferdecker schrieb am Dienstag, 2. März 2021 um 09:17:23 UTC+1:
[...]
Natürlich wäre es eleganter, nur bei den Checkboxen das
Post by Holger Schieferdecker
.Checked zu ändern, wo es notwendig ist. Die passenden Abfragen machen
halt den Code etwas länglicher, aber evtl. ändere ich das noch.
[...]

kürzerer Code wäre z.B. (grade kein Delhpi zur Hand, meine Ausdemkopfsyntax kann etwas vom original abweichen :-) ):

for I := 0 to form1.componentcount -1 do
if Form1.components[i] is TCheckbox then
TCheckbox(Form1.components[i]).checked := false;
(Sender as TCheckbox).checked := true;

Wahlweise, falls es auch noch Checkboxen gibt, die nicht resettet werden, kann man das Property Tag nutzen. Bei den zu resettenden einfach das Tag:=1 setzen und eine If-Abfrage mehr einbauen.

Gruß
Holger Schieferdecker
2021-03-10 11:41:58 UTC
Permalink
Post by Holger Schieferdecker
[...]
Natürlich wäre es eleganter, nur bei den Checkboxen das
Post by Holger Schieferdecker
.Checked zu ändern, wo es notwendig ist. Die passenden Abfragen machen
halt den Code etwas länglicher, aber evtl. ändere ich das noch.
[...]
Danke für den Hinweis, einfach alles durchzugehen, ist natürlich auch
eine Möglichkeit.
Post by Holger Schieferdecker
for I := 0 to form1.componentcount -1 do
if Form1.components[i] is TCheckbox then
TCheckbox(Form1.components[i]).checked := false;
(Sender as TCheckbox).checked := true;
Sieht richtig aus, abgesehen davon, daß ich self statt Form1 verwenden
würde. Das iteriert eben über alle Komponenten, die da sind. Aber die
Abfrage, ob es eine Checkbox ist, geht ja schnell.
Post by Holger Schieferdecker
Wahlweise, falls es auch noch Checkboxen gibt, die nicht resettet werden, kann man das Property Tag nutzen. Bei den zu resettenden einfach das Tag:=1 setzen und eine If-Abfrage mehr einbauen.
Ob man das property Tag verwenden könnte, hatte ich auch schon überlegt.
Damit könnte man dann mehrere Gruppen von Checkboxen verwalten.

Momentan reicht mir jedoch die Lösung mit dem Flag.

Holger

Sieghard Schicktanz
2021-02-24 18:44:25 UTC
Permalink
Hallo Holger,
Post by Holger Schieferdecker
in einem kleinen Programm (D4) habe ich mehrere Checkboxen, von denen
nur eine oder keine gleichzeitig angehakt sein soll. Dazu habe ich im
...
Post by Holger Schieferdecker
Ja, natürlich könnte ich das ganze auf eine Radiogroup umbauen, dann
bräuchte ich eben ein zusätzliches Item für den Fall, daß keine Funktion
gewünscht ist.
Gibt's da nicht auch eine Option à la "all_up" oder so ähnlich? Irgendwo in
der Umgebung ist mir sowas schonmal untergekommen, und das sollte doch
wenigstens dieses "Problem" mit der "Radiogroup" lösen?
--
--
(Weitergabe von Adressdaten, Telefonnummern u.ä. ohne Zustimmung
nicht gestattet, ebenso Zusendung von Werbung oder ähnlichem)
-----------------------------------------------------------
Mit freundlichen Grüßen, S. Schicktanz
-----------------------------------------------------------
Holger Schieferdecker
2021-02-26 08:07:47 UTC
Permalink
Post by Jens Kallup
Hallo Holger,
Post by Holger Schieferdecker
in einem kleinen Programm (D4) habe ich mehrere Checkboxen, von denen
nur eine oder keine gleichzeitig angehakt sein soll. Dazu habe ich im
....
Post by Holger Schieferdecker
Ja, natürlich könnte ich das ganze auf eine Radiogroup umbauen, dann
bräuchte ich eben ein zusätzliches Item für den Fall, daß keine Funktion
gewünscht ist.
Gibt's da nicht auch eine Option à la "all_up" oder so ähnlich? Irgendwo in
der Umgebung ist mir sowas schonmal untergekommen, und das sollte doch
wenigstens dieses "Problem" mit der "Radiogroup" lösen?
Man kann ItemIndex:=-1 setzen, dann ist kein Radiobutton aktiv. Aber
soweit ich das sehe geht das nur aus dem Code heraus, nicht per
Mausklick oder Tastendruck. Wäre auch ein unübliches Verhalten für eine
Radiogroup.

Ich müßte sowieso statt einer Radiogroup eine Groupbox oder ein Panel
nehmen, da ich die Radiobuttons manuell positionieren will. Da gibt es
dann wiederum kein ItemIndex, ergo käme sowieso ein zusätzlicher
Radiobutton mit 'None' oder so hinzu.

Holger
Jens Kallup
2021-02-26 13:14:12 UTC
Permalink
Post by Holger Schieferdecker
Ich müßte sowieso statt einer Radiogroup eine Groupbox oder ein Panel
nehmen, da ich die Radiobuttons manuell positionieren will. Da gibt es
dann wiederum kein ItemIndex, ergo käme sowieso ein zusätzlicher
Radiobutton mit 'None' oder so hinzu.
also mein Favorit und Vorschlag wäre, das Du einen dynamischen Array
erstellst, der eine Sub-Klasse für jede TCheckBox enthält.
Dann kannst Du per Index drauf zugreifen und hast die freie Wahl, was
die Zuordnung von Funktionen/Properties, etc.. anbelangt.

In etwa so:

type
TMyCheckBox = class(TCheckBox)
procedure MyOnClick(...);
end;

var
MyCheckers: Array of TMyCheckBox;

SetLength(MyCheckArray, 100);

dann:
for i := 0 to 20 do begin ... end;
Post by Holger Schieferdecker
Holger
Jens
Loading...