My problems is about setting componentproperties as runtime.
I have made 2 test components to show my problem, TMyEdit and TMyGroupBox.
TMyEdit.Enable will (in this test) set its background to red.
MyGroupBox.Enable will iterate all components in it and set the Enable property on them.
Here are snips from my code:
TMyEdit = class(TEdit)
private
Function GetEnabled: Boolean;
Procedure SetEnabled(ABoolean: Boolean);
protected
public
published
Property Enabled: Boolean Read GetEnabled Write SetEnabled;
end;
Function TMyEdit.GetEnabled: Boolean;
begin
Result := Inherited Enabled;
end;
Procedure TMyEdit.SetEnabled(ABoolean: Boolean);
begin
if ABoolean <> Enabled then
begin
if ABoolean then
Color := clWindow
else
Color := clRed;
Inherited Enabled := ABoolean;
end;
end;
TMyGroupBox = class(TGroupBox)
private
Function GetEnabled: Boolean;
Procedure SetEnabled(ABoolean: Boolean);
protected
public
published
Property Enabled: Boolean Read GetEnabled Write SetEnabled;
end;
Function TMyGroupBox.GetEnabled: Boolean;
begin
Result := Inherited Enabled;
end;
Procedure TMyGroupBox.SetEnabled(ABoolean: Boolean);
Var
i: Integer;
begin
if ABoolean <> Enabled then
begin
for i := 0 to ControlCount-1 do
Controls[i].Enabled := ABoolean;
Inherited Enabled := ABoolean;
end;
end;
What I do is that I put a MyGroupBox on a form and drops a MyEdit in it. Now, if I at runtime change the Enabled value of MyEdit, the background will change accordingly.
If I change Enabled for MyGroupBox, it will not call (Set)Enabled for MyEdit but instead it calls it on TEdit (the parent component).
Now, if I change the For loop to read
for i := 0 to ControlCount-1 do
if (Controls[i] is TMyListBox) then
(Controls[i] As TMyListBox).Enabled := ABoolean
else
Controls[i].Enabled := ABoolean;
it will work. But I don't want MyGroupBox to know all possible components that I will drop in it.
procedure TMyEdit.CMEnabledChanged(var Message: TMessage);
begin
if Enabled then Color := clWindow else Color := clRed;
end;
procedure TMyGroupBox.CMEnabledChanged(var Message: TMessage);
var I: Integer;
begin
for I := 0 to ControlCount-1 do
Controls[I].Enabled := Enabled;
end;
The problem is that GetEnabled and SetEnabled in TControl is not virtual.
If it were virtual you simple override it and all.
Suppose exists two class
type
TClass1 = class
public
procedure Print;
end;
TClass2 = class(TClass1)
public
procedure Print;
end;
procedure TClass1.Print;
begin
// print 'Class 111'
end;
procedure TClass2.Print;
begin
// print 'Class 222'
end;
and procedure ..
procedure Test(C: TClass1);
begin
C.Print;
end;
and you have two variables
var C1: TClass1;
C2: TClass2;
C1 := TClass1.Create; // Type of C1 is Class1
C2 := TClass2.Create; // Type of C2 is Class2
if you call Test(C1) you see 'Class 111'
if you call Test(C2) you as well as see 'Class 111' becouse Print is not virtual
if Print was virtual you see in first case 'Class 111' and 'Class 222' in second case
It is reason.
So, Delphi does not allow you override property Enabled but
notify you about its changing.
If it was another property and Get/Set not virtual and no notify message
I am afraid it is impossible
So, If you write components yourself make Get/Set protected and virtual.