Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Delphi Hä? Warum ist das Ändern von Checked ein Click? (https://www.delphipraxis.net/213272-hae-warum-ist-das-aendern-von-checked-ein-click.html)

Alallart 29. Jun 2023 14:46

Hä? Warum ist das Ändern von Checked ein Click?
 
Ich will statt mit drei RadioButtons eine Auswahl mit zwei CheckBoxen lösen. Gedacht ist das so: beide Checkboxen können abgewählt sein, dann kann einer von beiden ausgewählt sein. Wird einer einer von den beiden ausgewählt, muss natürlich der andere abgewählt werden. Theoretisch sollte das damit möglich sein:
Delphi-Quellcode:
procedure TForm1.CheckBox1Click(Sender: TObject);
begin
  CheckBox2.Checked := False;
end;

procedure TForm1.CheckBox2Click(Sender: TObject);
begin
  CheckBox1.Checked := False;
end;
Jetzt passiert aber etwas was ich nicht verstehe. Klicke ich auf CheckBox1, um es auszuwählen, wird in der Prozedur CheckBox2.Checked auf False gestellt. Das führt aber dazu, dass die Prozedur CheckBox2Click aufgerufen wird, und CheckBox1.Checked auf False stellt. Warum das denn?

Warum führt der Checked Code dazu, dass es als Click wahrgenommen wird?

Führe ich den Code durch eine Button Prozedur, passiert das nicht.

himitsu 29. Jun 2023 14:58

AW: Hä? Warum ist das Ändern von Checked ein Click?
 
Weil jemand vor über 20 Jahren dachte es wäre cool so.
Und nun bleibt es so, weil is halt so. :angle:




Einige haben sich über eine Ableitung, oder einen ClassHelper, da was gebaut. :zwinker:

Delphi-Quellcode:
//property CheckedNoClick: Boolean read GetCheckedNoClick write SetCheckedNoClick stored False;

procedure TMyCheckBox.SetCheckedNoClick(Value: Boolean);
var
  _Click, _Change: TNotifyEvent;
begin
  _Click := OnClick;
  _Change := Properties.OnChange;
  try
    OnClick            := nil;
    Properties.OnChange := nil;
    Checked            := Value;
  finally
    OnClick            := _Click;
    Properties.OnChange := _Change;
  end;
end;
OnChange ist für DevExpress (beim Delphi reicht OnClick)



[EDIT] Ich wusste doch da gab's nochwas, aber sah es vorhin natürlich nicht.
Delphi-Referenz durchsuchenClicksDisabled

PS: Hier im Forum suchenTCheckBox OnClick Checked

Uwe Raabe 29. Jun 2023 15:00

AW: Hä? Warum ist das Ändern von Checked ein Click?
 
Das ist nun mal das Standardverhalten.

Lösung 1 (quick-and-dirty): Du setzt das (allerdings protected) Property ClicksDisabled temporär auf True.
Lösung 2 (sauber aber aufwändig): Du verwendest zwei Actions, die einen gemeinsamen Status manipulieren bzw. überwachen.

Sherlock 29. Jun 2023 15:07

AW: Hä? Warum ist das Ändern von Checked ein Click?
 
So isses. Und das ist gemäß Doku sogar so gewollt
Zitat:

Hinweis: Wenn Sie den Wert der Eigenschaft Checked programmseitig ändern, wird das Ereignis OnClick des Kontrollkästchen-Steuerelements ausgelöst. Ändern Sie den Wert der Eigenschaft Checked nicht in der Ereignisbehandlungsroutine des Ereignisses OnClick, weil dies zu einem Deadlock führt.
Hat mich damals auch mal ein paar Tage näher an die Rente gebracht.

Sherlock

bcvs 29. Jun 2023 15:08

AW: Hä? Warum ist das Ändern von Checked ein Click?
 
Das OnClick einer Checkbox wird immer ausgelöst, wenn sich der Checked-Staus ändert, sei es durch Anklicken oder aus dem Programm heraus. Sollte vielleicht besser OnChecked heißen.

Ich mache es immer so. Ohne Actions oder ClassHelper oder Ableitungen
Delphi-Quellcode:
procedure TForm1.CheckBox1Click(Sender: TObject);
begin
  if not DoCheckBox1Click then
    exit;

  DoCheckBox2Click:=false;
  CheckBox2.Checked := False;
  DoCheckBox2Click:=true;
end;

procedure TForm1.CheckBox2Click(Sender: TObject);
begin
  if not DoCheckBox2Click then
    exit;

  DoCheckBox1Click:=false;
  CheckBox1.Checked := False;
  DoCheckBox1Click:=true;
end;
DoCheckBox1Click und DoCheckBox2Click natürlich irgenwo vorher sinnvoll auf true setzen.

Jasocul 29. Jun 2023 15:09

AW: Hä? Warum ist das Ändern von Checked ein Click?
 
Noch ein Q&D:
Du müsstest im Click-Event den Sender prüfen können. Kommt der von der falschen CheckBox führst du den Code nicht aus.
Falls es mit dem Sender nicht geht, müsste das ActiveControl vermutlich auch als Test möglich sein.
Nächste Möglichkeit:
Wenn die CheckBox1 geklickt wird, den Eventzeiger von CheckBox2 auf nil setzen, dann die CheckBox2 umsetzen. Anschließend wieder das Event zuweisen.

Das aktuelle Verhalten hat Vor- und Nachteile. Ich würde daher nicht grundsätzlich behaupten, dass es falsch ist.

Uwe Raabe 29. Jun 2023 15:14

AW: Hä? Warum ist das Ändern von Checked ein Click?
 
Genau dafür gibt es ja eben das ClicksDisabled. Das wird auch von den Actions so verwendet, wie dieser Code aus TButtonControl.ActionChange zeigt:
Delphi-Quellcode:
        // prevent generating Action.OnExecute when the control gets checked
        OldClicksDisabled := ClicksDisabled;
        ClicksDisabled := True;

        Self.Checked := Checked;

        ClicksDisabled := OldClicksDisabled;

dummzeuch 29. Jun 2023 16:11

AW: Hä? Warum ist das Ändern von Checked ein Click?
 
Zitat:

Zitat von Sherlock (Beitrag 1523951)
So isses. Und das ist gemäß Doku sogar so gewollt
Zitat:

Hinweis: Wenn Sie den Wert der Eigenschaft Checked programmseitig ändern, wird das Ereignis OnClick des Kontrollkästchen-Steuerelements ausgelöst. Ändern Sie den Wert der Eigenschaft Checked nicht in der Ereignisbehandlungsroutine des Ereignisses OnClick, weil dies zu einem Deadlock führt.

Naja "gewollt" ist übertrieben, eigentlich kann das keiner wirklich wollen - zumindest fällt mir kein Fall ein, wo das einen Vorteil hätte -, aber immerhin ist es dokumentiert.

himitsu 29. Jun 2023 16:22

AW: Hä? Warum ist das Ändern von Checked ein Click?
 
Es fing ja schon damit an, dass auch die nutzerseitige Änderung im OnClick ankommt, und es kein OnChange gab/gibt. (DevExpress hat bei seiner TcxCheckBox zusätzlich ein OnChange)
und da das "Click" somit eigenlich "Change" bedeutet, ist es "richtig", dass es beim Change auch klickt :angle2:

klaus schaaff 2. Jul 2023 11:29

AW: Hä? Warum ist das Ändern von Checked ein Click?
 
Hallo Delphi-PRAXiS,

vielleicht etwas OldSchool, aber das sollte auch noch funktionieren.

Delphi-Quellcode:

var
  DontChange: Boolean = False;

procedure TForm1.CheckBox1Click(Sender: TObject);
begin
  if DontChange = True then Exit;
  DontChange := True;
  try
    CheckBox2.Checked := False;
  finally
    DontChange := False;
  end;
end;

procedure TForm1.CheckBox2Click(Sender: TObject);
begin
  if DontChange = True then Exit;
  DontChange := True;
  try
    CheckBox1.Checked := False;
  finally
    DontChange := False;
  end;
end;
Besonders bei älteren Delphi-Versionen.


Liebe Grüße
Klaus Schaaff

Uwe Raabe 2. Jul 2023 11:38

AW: Hä? Warum ist das Ändern von Checked ein Click?
 
Zitat:

Zitat von klaus schaaff (Beitrag 1524066)
Besonders bei älteren Delphi-Versionen.

Damit meinst du älter als Delphi 5?

himitsu 2. Jul 2023 11:40

AW: Hä? Warum ist das Ändern von Checked ein Click?
 
Delphi-Quellcode:
if ... = True then
gehört sowieso in garkeine Delphiversion rein.

klaus schaaff 2. Jul 2023 21:14

AW: Hä? Warum ist das Ändern von Checked ein Click?
 
Hallo,

@Uwe Rabe:
Zitat:

Damit meinst du älter als Delphi 5?
Alles was <= Delphi 7 ist.

@himitsu
Zitat:

if ... = True then gehört sowieso in garkeine Delphiversion rein.
Ja, ich habe hier schon öfter Diskurse dazu hier gelesen. Die Beispiele dazu habe ich nachkompiliert und konnte bei <= Delphi 7 keine Fehler nach produzieren. Einzig die unterschiedlichen Boolean-Größen, da muss man aufpassen. Aber was du schreibst, sollte in neueren Delphi-Versionen der Sicherheit wegen beachtet werden, sicher.

Liebe Grüße
Klaus Schaaff

himitsu 2. Jul 2023 21:22

AW: Hä? Warum ist das Ändern von Checked ein Click?
 
Minimierte Beispiele, sind eben nicht immer naturgeträu.
z.B. BOOL aus WinAPIs ist 32 Bit / 4 Byte groß und wird dann auf das 1 Byte (Boolean) umgebrochen, was aber eben im Delphi auch nicht ganz genau dem ByteBool entspricht.
Unter Windows ist die Konstante "True" z.B. -1, aber im Pascal bzw. Delphi ist es +1.

Boolean ist nunmal eben nicht 1 Bit, was wirklich ausschließlich 0 und 1 kennen würde.

Außerdem kann ein Boolean eben aus anderen Werten gekastet generiert sein
in C-Sprachen und z.B. Javascript geht auch ein
Delphi-Quellcode:
if (i)
, wobei I = Integer ... alles <> 0 ist nunmal "True".

Delphi-Quellcode:
var B: Boolean;

//B := Boolean(0); // immer False (aber geht auch nicht anders)
B := Boolean(2); // eigentlich "True", aber eben nicht genau das "eine" True

if B = True then
  ShowMessage('True')
else if B = False then
  ShowMessage('False')
else
  ShowMessage('auch True');

if B then
  ShowMessage('True')
else if not B then
  ShowMessage('False')
else
  ShowMessage('nie');

Uwe Raabe 2. Jul 2023 21:24

AW: Hä? Warum ist das Ändern von Checked ein Click?
 
Zitat:

Zitat von klaus schaaff (Beitrag 1524092)
Alles was <= Delphi 7 ist.

Ich meinte nur, weil es das ClicksDisabled auch schon in Delphi 5 gab. Ältere Versionen habe ich aktuell nicht mehr greifbar. Daher kann ich nicht sagen, in welcher Version das eingeführt wurde.

himitsu 2. Jul 2023 22:04

AW: Hä? Warum ist das Ändern von Checked ein Click?
 
Nja, bissl blöd lief wohl, dass es normal "unsichtbar" ist und es somit auch kaum jemand sah.

Gerade bei der CheckBox spräche ja nichts dagegen, dass endlich mal published zu machen.

https://quality.embarcadero.com/brow...ClicksDisabled
Uwe :stupid:

jaenicke 3. Jul 2023 06:22

AW: Hä? Warum ist das Ändern von Checked ein Click?
 
Ich fände es auch gut, wenn es eine passende globale Einstellung gäbe. Allerdings könnte die natürlich auch zu Irritationen führen.

Zitat:

Zitat von Uwe Raabe (Beitrag 1524095)
Ich meinte nur, weil es das ClicksDisabled auch schon in Delphi 5 gab. Ältere Versionen habe ich aktuell nicht mehr greifbar. Daher kann ich nicht sagen, in welcher Version das eingeführt wurde.

Das gibt es seit Delphi 4.

Zitat:

Zitat von klaus schaaff (Beitrag 1524092)
Ja, ich habe hier schon öfter Diskurse dazu hier gelesen. Die Beispiele dazu habe ich nachkompiliert und konnte bei <= Delphi 7 keine Fehler nach produzieren.

Weil es nicht zum Thema gehört nur kurz:
Sagst du denn dann auch im echten Leben: Wenn "das Wetter ist schön" wahr ist, gehe ich zum Fußballspielen.
Wenn nicht, was macht es dann für einen Sinn, das im Quelltext so verklausuliert zu schreiben, unabhängig von den möglichen Fehlern?

Beispiel getestet mit Delphi 1 (mit zusätzlich BoolToStr, das es dort noch nicht gibt) bis 7:
Delphi-Quellcode:
function Example(const AValue: string): Boolean;
begin
  Result := Boolean(CompareStr(AValue, 'Test'));
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  ShowMessage('Echter Wert: ' + BoolToStr(Example('TestNix'), True)
    + sLineBreak + 'Manuelle Auswertung: ' + BoolToStr(Example('TestNix') = True, True));
end;

himitsu 3. Jul 2023 09:06

AW: Hä? Warum ist das Ändern von Checked ein Click?
 
Zitat:

Zitat von jaenicke (Beitrag 1524106)
Ich fände es auch gut, wenn es eine passende globale Einstellung gäbe. Allerdings könnte die natürlich auch zu Irritationen führen.

Es muß ja nicht gleich global sein.
Ein sichtbares, bzw. wirklich nutzbares Property an den CheckBoxen wäre schon nett. :-D

Aber joar, vielleicht eine Einstellung in den IDE-Settings und Projekt-Settings, wo man das Default festlegen kann, für neue CheckBoxen.

klaus schaaff 3. Jul 2023 14:11

AW: Hä? Warum ist das Ändern von Checked ein Click?
 
Hallo,

@Uwe Raabe
@jaenicke

ich habe StdCtrls.pas in allen Versionen von Delphi 5 bis Delphi 10 duchsuchen lassen nach 'ClicksDisabled' und 'FClicksDisabled'. Keine der Versionen von TCustomCheckBox enthält diese property. Eine Frage bleibt offen, die ich nicht exakt beantworten kann. Hatten Updates dieser Delphi Versionen vielleicht doch TCustomCheckBox property ClicksDisabled eingebunden?
Ich finde es schade, dass es kein offizielles Tool gibt, um diese Fragen korrekt zu bentworten.

Dagegen haben TButtonControl und TRadioButton ClicksDisabled.

Ein Kuriosum gibt es dennoch:

Delphi-Quellcode:
procedure TCustomCheckBox.SetState(Value: TCheckBoxState);
begin
  if FState <> Value then
  begin
    FState := Value;
    if HandleAllocated then
      SendMessage(Handle, BM_SETCHECK, Integer(FState), 0);
    if not ClicksDisabled then Click; // <- Hier
  end;
end;
Das ist die einzige Stelle.

In Delphi wurden schon immer Quelltext-Dateien *.pas mit leicht verändertem Code ausgeliefert, als die complierten *.dcu. Das scheint ein solcher Fall zu sein.

Alle Versuche mit Casts TButtonControl(CheckBox1).ClicksDisabled führten zu nichts, auch Debug dcu's dazu zuschalten brachten keinen Erfolg. Vielleicht hat jemand eine Idee, wie man doch zu CheckBox1.ClicksDisabled kommt.


Liebe Grüße
Klaus Schaaff

jaenicke 3. Jul 2023 14:32

AW: Hä? Warum ist das Ändern von Checked ein Click?
 
Zitat:

Zitat von klaus schaaff (Beitrag 1524146)
Dagegen haben TButtonControl und TRadioButton ClicksDisabled.

Und TCustomCheckBox ist von TButtonControl abgeleitet...

Wie schon geschrieben, die TCheckBox funktioniert mit ClicksDisabled seit Delphi 4 so.

freejay 3. Jul 2023 14:40

AW: Hä? Warum ist das Ändern von Checked ein Click?
 
Also wenn ich im Code versuche, bei einer TCheckBox eine Property oder Methode mit "click" zu finden bekomme ich nur "OnClick" , kein "ClicksDisabled"...

jaenicke 3. Jul 2023 15:07

AW: Hä? Warum ist das Ändern von Checked ein Click?
 
Zitat:

Zitat von freejay (Beitrag 1524148)
Also wenn ich im Code versuche, bei einer TCheckBox eine Property oder Methode mit "click" zu finden bekomme ich nur "OnClick" , kein "ClicksDisabled"...

Wie Use schon schrieb... die Property steht unter protected, ist also nur in der Klasse selbst und der Unit, in der sie deklariert ist, erreichbar.
Zitat:

Zitat von Uwe Raabe (Beitrag 1523947)
Lösung 1 (quick-and-dirty): Du setzt das (allerdings protected) Property ClicksDisabled temporär auf True.

Delphi-Quellcode:
type
  TMyCheckBox = class(TCheckBox)
  end;

...

TMyCheckBox(CheckBox1).ClicksDisabled := True;

Delphi.Narium 3. Jul 2023 15:16

AW: Hä? Warum ist das Ändern von Checked ein Click?
 
Zitat:

Zitat von freejay (Beitrag 1524148)
Also wenn ich im Code versuche, bei einer TCheckBox eine Property oder Methode mit "click" zu finden bekomme ich nur "OnClick" , kein "ClicksDisabled"...

Ist beim VorVorfahren von TCheckBox als Protected deklariert.
Delphi-Quellcode:
...
  TButtonControl = class(TWinControl)
  private
    FClicksDisabled: Boolean;
...
  protected
...
    property ClicksDisabled: Boolean read FClicksDisabled write FClicksDisabled;

...
  TCustomCheckBox = class(TButtonControl)
...
  TCheckBox = class(TCustomCheckBox)
...
Eigenschaft in 'nem Nachfahren veröffentlichen?
Delphi-Quellcode:
type
  TMyCheckBox = class(TCheckBox)
  published
    property ClicksDisabled: Boolean;
  end;

himitsu 3. Jul 2023 15:26

AW: Hä? Warum ist das Ändern von Checked ein Click?
 
Click ist nur Protected, also aus "deinem" Code auch nicht zugänglich.
Bei TButton dagegen wurde es nach Puplic verschoben, somit kann dort direkt aufgerufen werden.

freejay 3. Jul 2023 15:44

AW: Hä? Warum ist das Ändern von Checked ein Click?
 
Delphi-Quellcode:
type
  TMyCheckBox = class(TCheckBox)
  end;

...

TMyCheckBox(CheckBox1).ClicksDisabled := True;
Ich glaube so ein Konstrukt hab ich in meinem Vierteljahrhundert Delphi erst einmal benutzt/benutzen müssen. Das ist mir einfach nicht mehr eingefallen...

3 x Danke!

himitsu 3. Jul 2023 16:24

AW: Hä? Warum ist das Ändern von Checked ein Click?
 
Viele nennen sowas
Delphi-Quellcode:
type THackedCheckBox = class(TCheckBox);
,
aber Einige haben sich angewöhnt es netter zu benennen
Delphi-Quellcode:
type TCheckBoxAccess = class(TCheckBox);
.
(das END ist optional, wenn ansonsten nichts verändert wird)

Es ginge auch ohne es Umzubennen
Delphi-Quellcode:
type TCheckBox = class(StdCtrls.TCheckBox); // bzw. (Vcl.StdCtrls.TCheckBox)

Oberhalb das Form kann man damit auch lokal Komponenten "umbauen", welche so dann auch direkt auf der Form laden. (zur Laufzeit, nicht im FormDesigner)



PS, siehe #16 ... da brav für voten, damit sowas hier bald nicht mehr nötig ist.

jaenicke 3. Jul 2023 16:31

AW: Hä? Warum ist das Ändern von Checked ein Click?
 
Ja, es geht auch ohne anders genannten Typ. Das mache ich allerdings ungern, denn wenn man den Code dann kopiert, wundert man sich, dass er anderswo nicht funktioniert. Oder man postet ihn hier im Forum, ohne dran zu denken... :lol:

freejay 4. Jul 2023 10:28

AW: Hä? Warum ist das Ändern von Checked ein Click?
 
Zitat:

Zitat von himitsu (Beitrag 1524155)
...PS, siehe #16 ... da brav für voten, damit sowas hier bald nicht mehr nötig ist.

Done.

Redeemer 5. Jul 2023 09:16

AW: Hä? Warum ist das Ändern von Checked ein Click?
 
Liste der Anhänge anzeigen (Anzahl: 2)
Sehr gut ist auch TComboBox. Das hat die Ereignisse OnSelect und OnClick. Beide sind komplett identisch. So gibt es kein Ereignis fürs Klicken in die ComboBox, dafür aber eins fürs Drücken der Pfeiltasten: OnClick.
Ebenfalls gut: TListView.Items.Add verhält sich komplett anders, je nach dem Wert von Checkboxes. Ist Checkboxes False, passiert schlicht nichts. Ist Checkboxes True, werden gleich drei Ereignisse ausgelöst.
Oder du klickst links auf das StateImage eines ListViews. Du erhältst einmal MouseDown und zweimal MouseUp, weil du das erste MouseUp bereits vorm Loslassen kriegst.

Ich habe euch mal meine gesammelten Worst-Ofs der Delphi-Logik angehängt.

himitsu 5. Jul 2023 09:41

AW: Hä? Warum ist das Ändern von Checked ein Click?
 
@Redeemer
Das abschließende #13#10 beim TStrings.Text ist eigentlich ein sLineBreak, bzw. ganz genau das Delphi-Referenz durchsuchenTStrings.LineBreak.
Merkst du, wenn nicht für Windows kompiliert wird und die Unixoiden bloß ein #10 haben.

Und dafür gibt es auch schon eine Lösung: Delphi-Referenz durchsuchenTStrings.TrailingLineBreak
[add] https://docwiki.embarcadero.com/Libr...ilingLineBreak


Alle Zeitangaben in WEZ +1. Es ist jetzt 20:05 Uhr.

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