Discussion:
OnClick verhindern beim Setzen von CheckBox.Checked im Code
(zu alt für eine Antwort)
Roland Reimann
2007-11-20 13:28:17 UTC
Permalink
Hallo NG,

wenn man die Eigenschaft CheckBox.Checked per Code setzt wird auch ein
OnClick Ereignis ausgelöst. Kann dies auf einfache Art und Weise
verhindert werden?
Also, OnClick nur beim Klicken und nicht beim Verändern von Checked im
Code.

Gruß
Roland
Erich Günthner
2007-11-20 13:42:12 UTC
Permalink
Post by Roland Reimann
Hallo NG,
wenn man die Eigenschaft CheckBox.Checked per Code setzt wird auch ein
OnClick Ereignis ausgelöst. Kann dies auf einfache Art und Weise
verhindert werden?
Also, OnClick nur beim Klicken und nicht beim Verändern von Checked im
Code.
Gruß
Roland
CheckBox.OnClick := NIL
CheckBox.Checked := true;
CheckBox.Onclick := CheckBoxClick; // oder wie deine Methode auch heißt

Erich
Roland Reimann
2007-11-20 13:58:09 UTC
Permalink
Antwort auf eine Nachricht von Erich Günthner <***@Yahoo.de> vom
Tue, 20 Nov 2007 14:42:12 +0100 :

Hallo Erich,
Post by Erich Günthner
Post by Roland Reimann
wenn man die Eigenschaft CheckBox.Checked per Code setzt wird auch ein
OnClick Ereignis ausgelöst. Kann dies auf einfache Art und Weise
verhindert werden?
Also, OnClick nur beim Klicken und nicht beim Verändern von Checked im
Code.
CheckBox.OnClick := NIL
CheckBox.Checked := true;
CheckBox.Onclick := CheckBoxClick; // oder wie deine Methode auch heißt
und das kann ich innerhalb der OnClick-Methode selbst setzen, also
während die OnClick läuft?
Hintergrund meiner Frage war nämlich, daß mehrere Checkboxen EINE
OnClick-Methode haben und innerhalb dieser das Checked von einigen
dieser CheckBoxen gesetzt wird. dadurch wird zur Zeit wieder OnKlick
ausgelöst und das geht dann rekursiv so lange bis der Stack voll ist.
Natürlich kann ich das mit einer boolschen Variable (z.B.
"OnClickLaeuft=True") verhindern. Aber ich dachte das geht eleganter.

Gruß
Roland
Erich Günthner
2007-11-20 14:54:59 UTC
Permalink
Hallo Roland
Post by Roland Reimann
und das kann ich innerhalb der OnClick-Methode selbst setzen, also
während die OnClick läuft?
Du Änderst ja nicht die Methoden, sonder eine Eigenschafts-Variable.
Post by Roland Reimann
Hintergrund meiner Frage war nämlich, daß mehrere Checkboxen EINE
OnClick-Methode haben und innerhalb dieser das Checked von einigen
dieser CheckBoxen gesetzt wird. dadurch wird zur Zeit wieder OnKlick
ausgelöst und das geht dann rekursiv so lange bis der Stack voll ist.
Natürlich kann ich das mit einer boolschen Variable (z.B.
"OnClickLaeuft=True") verhindern. Aber ich dachte das geht eleganter.
Setze OnClick auf NIL.

Ist ME die einzige Möglichkeit neben deiner bereits erwähnten boolschen
Variable


Bei "CheckBox.Checked := true" schaut die CheckBox nach, ob dem
Ereigniss "OnClick" was zu gewiesen ist.
Ist dies der Fall, wird das Ereigniss aufgerufen.

Mach es so, und alles wird gut!

Erich
Hans-Peter Diettrich
2007-11-21 05:47:06 UTC
Permalink
Post by Roland Reimann
Post by Roland Reimann
wenn man die Eigenschaft CheckBox.Checked per Code setzt wird auch ein
OnClick Ereignis ausgelöst. Kann dies auf einfache Art und Weise
verhindert werden?
Also, OnClick nur beim Klicken und nicht beim Verändern von Checked im
Code.
...
Post by Roland Reimann
Natürlich kann ich das mit einer boolschen Variable (z.B.
"OnClickLaeuft=True") verhindern. Aber ich dachte das geht eleganter.
Ganz elegant geht es mit einer eigenen Checkbox-Komponente, die zwischen
Klicks und Zuweisungen unterscheidet. Wäre vielleicht ein Anlaß, Dich
näher mit der Erstellung eigener Komponenten zu befassen...

DoDi
Marian Aldenhövel
2007-11-21 08:04:41 UTC
Permalink
Hi,
Post by Hans-Peter Diettrich
Ganz elegant geht es mit einer eigenen Checkbox-Komponente, die zwischen
Klicks und Zuweisungen unterscheidet. Wäre vielleicht ein Anlaß, Dich
näher mit der Erstellung eigener Komponenten zu befassen...
Und/Oder sich Simons solche Checkbox als Vorbild zu besorgen.

Ciao, MM
--
Marian Aldenhövel, Rosenhain 23, 53123 Bonn
http://www.marian-aldenhoevel.de
"Success is the happy feeling you get between the time you
do something and the time you tell a woman what you did."
Marian Aldenhövel
2007-11-20 15:26:52 UTC
Permalink
Hi,
Post by Roland Reimann
wenn man die Eigenschaft CheckBox.Checked per Code setzt wird auch ein
OnClick Ereignis ausgelöst. Kann dies auf einfache Art und Weise
verhindert werden?
Ich empfehle nicht das OnClick zu verhindern, sondern die Behandlung
zu übergehen:

procedure TForm1.Checkbox4711Click(Sender:TObject);
begin
if FUpdating>0 then exit;

inc(FUpdating);
try
Checkbox1234.Checked:=False;
Checkbox564.Checked:=False;
..
finally
dec(FUpdating);
end;
end;

Ciao, MM
--
Marian Aldenhövel, Rosenhain 23, 53123 Bonn
http://www.marian-aldenhoevel.de
"Success is the happy feeling you get between the time you
do something and the time you tell a woman what you did."
chriscolm
2007-11-20 16:24:15 UTC
Permalink
Hallo,

ich habe das Problem dadurch gelöst, dass ich nicht das OnClick-
Ereignis auswerte, sondern onMouseDown.

Grüße

Christian
Marian Aldenhövel
2007-11-20 17:14:17 UTC
Permalink
Hi,
Post by chriscolm
ich habe das Problem dadurch gelöst, dass ich nicht das OnClick-
Ereignis auswerte, sondern onMouseDown.
Nicht gut, denn die Checkbox ändert ihren Status nicht bei OnMouseDown
sondern eben bei Click. Dazu gehören Down und Up.

Mauscursor auf Checkbox. Linke Maustaste runter. Festhalten. Mauscursor
runter von der Checkbox. Linke Maustaste loslassen. Der Zustand der
Checkbox ist unverändert.

Kommt Deine Logik damit zurecht oder läuft sie auseinander? Ich halte
es nicht für sinnvoll, daß sich jemand auf dieses eingebaute Verhalten
verlässt, aber wahrscheinlich ist es. Irgendjemand macht das so,
verlass' Dich drauf, und der beschwert sich dann über das Non-Standard-
Verhalten.

Ciao, MM
--
Marian Aldenhövel, Rosenhain 23, 53123 Bonn
http://www.marian-aldenhoevel.de
"Success is the happy feeling you get between the time you
do something and the time you tell a woman what you did."
Hans-Peter Diettrich
2007-11-21 06:02:59 UTC
Permalink
Post by Marian Aldenhövel
Post by chriscolm
ich habe das Problem dadurch gelöst, dass ich nicht das OnClick-
Ereignis auswerte, sondern onMouseDown.
Nicht gut, denn die Checkbox ändert ihren Status nicht bei OnMouseDown
sondern eben bei Click. Dazu gehören Down und Up.
Mauscursor auf Checkbox. Linke Maustaste runter. Festhalten. Mauscursor
runter von der Checkbox. Linke Maustaste loslassen. Der Zustand der
Checkbox ist unverändert.
Wie sieht das aus bei:
Mauscursor außerhalb, linke Maustaste runter, Maus auf Checkbox,
Maustaste loslassen?

Ich würde zumindest OnMouseUp auswerten, das käme der Logik deutlich
näher. Es ist schon seltsam, wieso viele Leute meinen, daß beim
Anklicken schon das Drücken der Maustaste etwas auslösen soll - scheint
aber irgendwie das intuitiv Naheliegendste zu sein...

DoDi
NineBerry Schwarz
2007-11-20 17:31:08 UTC
Permalink
Hallo
Post by chriscolm
ich habe das Problem dadurch gelöst, dass ich nicht das OnClick-
Ereignis auswerte, sondern onMouseDown.
Man kann eine Checkbox auch per Tastatur ansteuern und umschalten.

Neun.
chriscolm
2007-11-20 19:08:17 UTC
Permalink
Post by NineBerry Schwarz
Hallo
Post by chriscolm
ich habe das Problem dadurch gelöst, dass ich nicht das OnClick-
Ereignis auswerte, sondern onMouseDown.
Man kann eine Checkbox auch per Tastatur ansteuern und umschalten.
Neun.
Ok, mit der TAstatur habe ich nicht bedacht, ehrlich gesagt, aber auch
noch nie angewendet.
Ich habe ein Formular, mit dem ich den Zusatnd eines Objektes ändern
kann. Dazu gibt es eine Prozedur, die das Formular aktualisiert. Hier
frage ich den Zusatnd des Objektes ab und setzte dementsprechend das
Häkchen oder nicht. Beim Klick auf die Checkbox ändere ich den Zusatnd
des Objektes und rufe anschließend die Prozedur zum aktualisieren des
Formulars auf. Das hat sich für mich so bewährt.

Grüße

Christian
Erich Günthner
2007-11-21 06:47:14 UTC
Permalink
Hallo Marian
Post by Marian Aldenhövel
Ich empfehle nicht das OnClick zu verhindern, sondern die Behandlung
procedure TForm1.Checkbox4711Click(Sender:TObject);
begin
if FUpdating>0 then exit;
inc(FUpdating);
try
Checkbox1234.Checked:=False;
Checkbox564.Checked:=False;
..
finally
dec(FUpdating);
end;
end;
Gibt es einen Grund das du OnClick hier nicht verwenden würdest?
Würde mich mal interessieren.

Erich
Marian Aldenhövel
2007-11-21 08:15:56 UTC
Permalink
Hi.
Post by Erich Günthner
Gibt es einen Grund das du OnClick hier nicht verwenden würdest?
Würde mich mal interessieren.
Du meinst, warum ich es nicht ausNILe?

1) Weil ich es nicht mag, daß die Verdrahtung sich zur Laufzeit
dauernd ändert.

Klassisch wird das ja zur Designzeit zusammengestöpselt. Und das soll
dann auch so bleiben wie man es im OI gesehen hat. Nicht sehr stark
das Argument.

2) Weil Du mindestens den alten Handler speichern musst.

Denn wenn sich die Verdrahtung ändern kann, dann ändert sie sich potentiell
ständig. Und Du musst dann schon wieder den aktuellen Handler wieder
anhängen und nicht irgendeinen der vielleicht irgendwann mal der richtige
war.

Also brauchst Du eine lokale Variable vom Eventtyp. Schreibarbeit, fängt
damit an daß man den richtigen Typnamen braucht, TNotifyEvent habe ich noch
im Kopf, aber viel mehr nicht. Die lokale Variable brauchst Du in jeder
Methode, die potentiell was rekursiv auslösen kann. Mein Integer ist ein
Feld des Formulars.

Du musst das dann auch für jedes Steuerelement machen, das diesen
Handler auslösen könnte. Also nicht eine Checkbox sondern siebenundneunzig.

Nimm den typischen Optionendialog. Da werden aus einer Konfig-Klasse ein
Stapel Steuerelemente gefüllt. Dann wird bei Änderungen etwas an anderen
Steuerelementen gefummelt. Andere Listen angezeigt, Ein- Ausgeblendet,
Validiert. Beim Füllen willst Du das nicht, oder nur genau einmal nachdem
alles gefüllt ist.

Wenn Du das steuern willst, brauchst Du für jedes der Steuerelemente, die
ein OnChange-Äquivalent haben, eine eigene lokale Variable für "alter
Handler". Da ist ein FUpdating viel einfacher. Vergleichbar
BeginUpdate/EndUpdate.

Ciao, MM
--
Marian Aldenhövel, Rosenhain 23, 53123 Bonn
http://www.marian-aldenhoevel.de
"Success is the happy feeling you get between the time you
do something and the time you tell a woman what you did."
Erich Günthner
2007-11-21 09:17:00 UTC
Permalink
Post by Marian Aldenhövel
Du meinst, warum ich es nicht ausNILe?
1) Weil ich es nicht mag, daß die Verdrahtung sich zur Laufzeit
dauernd ändert.
Klassisch wird das ja zur Designzeit zusammengestöpselt. Und das soll
dann auch so bleiben wie man es im OI gesehen hat. Nicht sehr stark
das Argument.
Allerdings, ist es auch gängig bewußt zur Laufzeit Ereignisse umzubiegen
(siehe 2)
Post by Marian Aldenhövel
2) Weil Du mindestens den alten Handler speichern musst.
Denn wenn sich die Verdrahtung ändern kann, dann ändert sie sich potentiell
ständig. Und Du musst dann schon wieder den aktuellen Handler wieder
anhängen und nicht irgendeinen der vielleicht irgendwann mal der richtige
war.
Das wäre ein Argument. Wenn allerdings nur ein Handler verwendet wird,
ist dies durchaus so machbar.

Man könnte auch den Tag-Wert nehmen.
Post by Marian Aldenhövel
Also brauchst Du eine lokale Variable vom Eventtyp. Schreibarbeit, fängt
damit an daß man den richtigen Typnamen braucht, TNotifyEvent habe ich noch
im Kopf, aber viel mehr nicht. Die lokale Variable brauchst Du in jeder
Methode, die potentiell was rekursiv auslösen kann. Mein Integer ist ein
Feld des Formulars.
Wobei bei Verwendung einer lokalen Variable und meheren Checkboxen hier
keine Unterscheidung möglich ist, welche checkBox gerade nicht reagieren
soll.
Post by Marian Aldenhövel
Nimm den typischen Optionendialog. Da werden aus einer Konfig-Klasse ein
Stapel Steuerelemente gefüllt. Dann wird bei Änderungen etwas an anderen
Steuerelementen gefummelt. Andere Listen angezeigt, Ein- Ausgeblendet,
Validiert. Beim Füllen willst Du das nicht, oder nur genau einmal nachdem
alles gefüllt ist.
Klar, das bei einem Init das Verwenden einer lokale Variable von Vorteil
ist.
Post by Marian Aldenhövel
Wenn Du das steuern willst, brauchst Du für jedes der Steuerelemente, die
ein OnChange-Äquivalent haben, eine eigene lokale Variable für "alter
Handler". Da ist ein FUpdating viel einfacher. Vergleichbar
BeginUpdate/EndUpdate.
Nur kannst du hier nur ein globales "nicht Updating" setzen.
Es gibt auch Situation die während eines Programmablaufes eintreten, und
durch die nur bestimmte Objekte manuipuliert werden.
Andere sollte sich aber wie bisher verhalten.

In der Tat habe ich Beginupdate und Endupdate auch schon vermisst.
Ich habe mir dann selber mal aus der Checkbox was abgeleitet.
Es hat sich, bei meinen Anforderungen, jedoch nicht viel geändert.

Code mit tCheckBox

Procedure Tform.CheckBox1Click(sender : TObject);
begin
CheckBox1.Onclick := NIL;
CheckBox1.checked := true;
CheckBox1.Onclick := CheckBox1Click;
end;

Code mit erweiterter tCheckBox

Procedure Tform.CheckBox1Click(sender : TObject);
begin
CheckBox1.DisableCheckToClick; // Oder so ähnlich
CheckBox1.checked := true;
CheckBox1.EnableCheckToClick; // Oder so ähnlich
end;


Deinen Vorschlag halte ich für genauso sinnvoll, wie das direkte
deaktivieren des Handlers.

Erich
Rene Kadner
2007-11-23 10:09:20 UTC
Permalink
Post by Marian Aldenhövel
Ich empfehle nicht das OnClick zu verhindern, sondern die Behandlung
procedure TForm1.Checkbox4711Click(Sender:TObject);
begin
if FUpdating>0 then exit;
....
Dem kann ich nur zustimmen. Ich mache es sogar nur mit einer Boolschen
Variable fInitForm. Sie wird gesetzt, wenn vom Code Anzeigeobjekte gesetzt
werden. In den jeweiligen OnClick / OnChange Methoden steht dann als erstes
wie bei Dir

if fInitForm the Exit;

Denn das Problem tritt ja nicht nur beim OnClick auf, sondern eben auch,
wenn man interaktiv per OnChange andere Felder/Daten anpassen will (bei mir
z.B.: Übergang in den Bearbeitungsmodus -> Aktivieren SpeicherAction).

Gruß
René
Marian Aldenhövel
2007-11-23 16:31:29 UTC
Permalink
Hi,
Post by Rene Kadner
Dem kann ich nur zustimmen. Ich mache es sogar nur mit einer Boolschen
Variable fInitForm.
Das ist nur leider nicht schachtelbar. Wenn Du also

fInitForm:=True;
try
..
finally
fInitForm:=False;
end;

in mehreren Methoden machst, und eine dieser Methoden eine andere aufruft,
dann kann das, naja, unerwünschte, Ergebnisse liefern.

Ciao, MM
--
Marian Aldenhövel, Rosenhain 23, 53123 Bonn
http://www.marian-aldenhoevel.de
"Success is the happy feeling you get between the time you
do something and the time you tell a woman what you did."
Dirk Schauries
2007-11-21 09:43:55 UTC
Permalink
Hi,
Post by chriscolm
Hallo,
ich habe ein Macbook von Apple, welches nur eine linke Maustaste hat.
Unter MacOSX kann man nun einen Rechtsklick simulieren, indem man die
linke Maustaste 2sek gedrückt hält.
Sowas würde ich auch gerne für Delphi programmieren. Nun fehlt mir das
Stichwort, wie man sowas lösen kann. Und nach dem wollte ich mal fragen.
Es wäre sehr nett, wenn mir einer sagen könnte, wie sowas _prinzipiell_
gehen könnte.
Danke und Tschau - Robert
ich habe das seinerzeit wie folgt gelöst und bin bestens zufrieden:

procedure SVNE(C : TWinControl; ValueString : String; ValueBool : Boolean;
ValueInteger : Integer; ValueDouble : Double); overload;
procedure SVNE(C : TWinControl; ValueString : String); overload;
procedure SVNE(C : TWinControl; ValueBool : Boolean); overload;
procedure SVNE(C : TWinControl; ValueInteger : Integer); overload;
procedure SVNE(C : TWinControl; ValueDouble : Double); overload;

//...

procedure SVNE(C : TWinControl; ValueString : String; ValueBool : Boolean;
ValueInteger : Integer; ValueDouble : Double);
var
OnChange : TNotifyEvent;
OnClick : TNotifyEvent;
begin
if c is TEdit then
begin
OnChange := TEdit(c).OnChange;
TEdit(c).OnChange := nil;
TEdit(c).Text := ValueString;
TEdit(c).OnChange := OnChange;
end else
if c is TMemo then
begin
OnChange := TMemo(c).OnChange;
TMemo(c).OnChange := nil;
TMemo(c).Text := ValueString;
TMemo(c).OnChange := OnChange;
end else
if c is TRichEdit then
begin
OnChange := TRichEdit(c).OnChange;
TRichEdit(c).OnChange := nil;
TRichEdit(c).Text := ValueString;
TRichEdit(c).OnChange := OnChange;
end else
if c is TCheckBox then
begin
OnChange := TCheckBox(c).OnClick;
TCheckBox(c).OnClick := nil;
TCheckBox(c).Checked := ValueBool;
TCheckBox(c).OnClick := OnChange;
end else
if c is TDateTimePicker then
begin
OnChange := TDateTimePicker(c).OnChange;
TDateTimePicker(c).OnChange := nil;
TDateTimePicker(c).Date := Trunc(ValueDouble);
TDateTimePicker(c).OnChange := OnChange;
end else
if c is TRadioButton then
begin
OnChange := TRadioButton(c).OnClick;
TRadioButton(c).OnClick := nil;
TRadioButton(c).Checked := ValueBool;
TRadioButton(c).OnClick := OnChange;
end else
if c is TRadioGroup then
begin
OnChange := TRadioGroup(c).OnClick;
TRadioGroup(c).OnClick := nil;
TRadioGroup(c).ItemIndex := ValueInteger;
TRadioGroup(c).OnClick := OnChange;
end else
//usw.
sm('SVNE ist unbekannt!');

//***************

Aufruf:

SVNE(MeineCheckBox,true);
oder
SVNE(MeinEdit,'Event wird nicht ausgelöst');

Gruß,
Dirk Schauries
Loading...