Autor Beitrag
Narses
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Administrator
Beiträge: 10181
Erhaltene Danke: 1254

W10ent
TP3 .. D7pro .. D10.2CE
BeitragVerfasst: Fr 17.04.09 13:45 
Moin!

Problem: Der Zustand einer TCheckBox soll durch Code geändert werden, ohne dabei ein OnClick-Ereignis auszulösen!

Für dieses Problem gibt es einige Lösungsansätze. Zunächst etwas zum Hintergrund, dann sollen zwei Ansätze konkret vorgestellt werden. Grundsätzlich ist es nicht falsch, dass beim Schreiben auf TCheckBox.Checked das Ereignis OnClick ausgelöst wird. So kann auch durch Tastaturereignisse (z.B. Ändern per Leertaste) auf Wertänderungen reagiert bzw. eine Benutzereingabe durch Code simuliert werden.

Es sind allerdings zwei grundsätzliche verschiedene Anwendungsfälle zu unterscheiden:
  • Benutzerinteraktion
    Hier ist das Verhalten der TCheckBox völlig OK, bei Änderung der Eigenschaft .Checked ist das OnClick-Ereignis gewünscht.

  • Vorgabe eines Wertes, z.B. beim Laden von Daten
    In diesem Fall möchte man eigentlich nur den Status der Checkbox per Code vorgeben, es findet zu diesem Zeitpunkt keine Benutzerinteraktion statt. Hier stört das Ereignis nun, da man üblicherweise im OnClick-Ereignis Code stehen hat, der die Änderung wieder in den Datenbestand überführen soll.
Der "einfache" Lösungsansatz sieht eine (klassen-)globale Variable vor (z.B. Boolean), in der man sich merkt, ob die Komponente(n) OnClick-Ereignisse auslösen sollen. Nachteil: globale Variable erforderlich, sowas ist immer unschön. :nixweiss: Vorteil: klappt immer ohne großen Aufwand.

Ich möchte aber noch eine weitere Lösung vorschlagen: die Komponente erweitern! ;) Beim Schreiben auf die Eigenschaft TCheckBox.State wird nur dann ein OnClick-Ereignis ausgelöst, wenn der Wert cbChecked zugewiesen wird, also schon fast das gewünschte Verhalten. Wir müssen jetzt nur noch dafür sorgen, dass beim Schreiben auf .State gar kein Ereignis mehr ausgelöst wird, dann haben wir den gewünschten Effekt und trotzdem bei Benutzerinteraktion das Ereignis. :idea:

Vorgehensweise (für D7(pro)):
  • Im Menü "Komponente" -> "Neue Komponente..." auswählen
  • Vorfahrtyp "TCheckBox [StdCtrls]" auswählen
  • Klassenname von "TCheckBox1" z.B. in "TClickFreeStateCheckBox" ändern
  • Palettenseite "Standard" auswählen
  • OK anklicken
  • Package-Auswahl kann einfach übernommen werden (wird dann im DefaultUser-Package abgelegt; ist OK, wenn man nicht so genau weiß, wozu das da ist)
  • Code anpassen, siehe unten
  • Compilieren, fertig.
Hier die Änderungen:
ausblenden volle Höhe 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:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
unit ClickFreeStateCheckBox;

interface

uses
  SysUtils, Classes, Controls, StdCtrls;

type
  TClickFreeStateCheckBox = class(TCheckBox)
  protected
    function GetMyState: TCheckBoxState;
    procedure SetMyState(const Value: TCheckBoxState);
  published
    property State: TCheckBoxState read GetMyState write SetMyState;
  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('Standard', [TClickFreeStateCheckBox]);
end;

// -----------------------------------------------------------------------------
// TClickFreeStateCheckBox

function TClickFreeStateCheckBox.GetMyState: TCheckBoxState;
begin
  Result := inherited State;
end;

procedure TClickFreeStateCheckBox.SetMyState(const Value: TCheckBoxState);
begin
  ClicksDisabled := TRUE; // leider ist diese Eigenschaft protected deklariert... :-(
  inherited State := Value;
  ClicksDisabled := FALSE;
end;

// -----------------------------------------------------------------------------

end.
Jetzt hat man eine "neue" Checkbox, die beim Schreiben auf .State keine OnClick-Ereignisse mehr auslöst. :)

cu
Narses

_________________
There are 10 types of people - those who understand binary and those who don´t.
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: Fr 17.04.09 13:50 
Warum nicht einfach die besagte Eigenschaft in der Klasse gleich mit public setzen?

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
Narses Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Administrator
Beiträge: 10181
Erhaltene Danke: 1254

W10ent
TP3 .. D7pro .. D10.2CE
BeitragVerfasst: Fr 17.04.09 18:08 
Moin!

user profile iconBenBE hat folgendes geschrieben Zum zitierten Posting springen:
Warum nicht einfach die besagte Eigenschaft in der Klasse gleich mit public setzen?
Tja, könnte man tun. :nixweiss: (ich halte ja keinen davon ab ;))

Ich denke allerdings, dass das Grundkonzept der Eigenschaft .Checked gar nicht erst änderbar sein sollte. Das würde die verfügbar gemachte Eigenschaft aber erlauben. :? Mein Kritikpunkt ist ja das Verhalten von .State, (nur) hier ist meiner Meinung nach ein logischer Bruch drin, warum sonst löst nur cbChecked ein OnClick aus? Ich weiß nicht, was sich die Delphi-Entwickler dabei gedacht haben, aber ich halte das Verhalten von TCheckBox in Bezug auf .State-Beschreiben für unbrauchbar. Fazit: so wenig wie möglich vom Standard abweichen.

cu
Narses

_________________
There are 10 types of people - those who understand binary and those who don´t.