I noticed that if I have a main container/parent (MainPanel), adding a child panel to it (ChildPanel), will perform CM_CONTROLLISTCHANGE on MainPanel (in TWinControl.InsertControl()) which is fine.
But if I insert a child control (ChildButton) to ChildPanel, a CM_CONTROLLISTCHANGE will be fired again for the main MainPanel!
Why is that? I was expecting the CM_CONTROLLISTCHANGE to fire only for ChildPanel when inserting ChildButton into ChildPanel.
MCVE
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ExtCtrls, StdCtrls;
type
TMainPanel = class(ExtCtrls.TCustomPanel)
private
procedure CMControlListChange(var Message: TCMControlListChange); message CM_CONTROLLISTCHANGE;
end;
TForm1 = class(TForm)
Button1: TButton;
Memo1: TMemo;
procedure Button1Click(Sender: TObject);
private
public
MainPanel: TMainPanel;
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TMainPanel.CMControlListChange(var Message: TCMControlListChange);
begin
if Message.Inserting then
begin
Form1.Memo1.Lines.Add('TMainPanel.CMControlListChange: Inserting ' + Message.Control.ClassName);
// Parent is always nil
if Message.Control.Parent = nil then Form1.Memo1.Lines.Add('*** Parent=nil');
end;
inherited;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
ChildPanel: TPanel;
ChildButton: TButton;
begin
FreeAndNil(MainPanel);
MainPanel := TMainPanel.Create(Self);
MainPanel.SetBounds(0, 0, 200, 200);
MainPanel.Parent := Self;
ChildPanel := TPanel.Create(Self);
ChildPanel.Parent := MainPanel;
ChildButton := TButton.Create(Self);
ChildButton.Parent := ChildPanel; // Why do I get CM_CONTROLLISTCHANGE in "MainPanel"?
end;
end.
DFM
object Form1: TForm1
Left = 192
Top = 114
Width = 685
Height = 275
Caption = 'Form1'
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'MS Shell Dlg 2'
Font.Style = []
OldCreateOrder = False
PixelsPerInch = 96
TextHeight = 13
object Button1: TButton
Left = 592
Top = 8
Width = 75
Height = 25
Caption = 'Button1'
TabOrder = 0
OnClick = Button1Click
end
object Memo1: TMemo
Left = 456
Top = 40
Width = 209
Height = 193
TabOrder = 1
end
end
P.S: I don't know if it matters, but I'm on Delphi 5.
CM_CONTROLLISTCHANGEis a custom notification VCL message AFAIK (Not sure if it acts same as native Window messages). I was unable to find how it is "propagate up through the chain of parents" in the sources. So I still can't tell what's going on and how. My main issue is that I can't tell who is theParentof the inserted control in theCMControlListChangemessage handler (but that might be another question). - zigCM_CONTROLLISTCHANGEup the parent chain. but not for any message. for exampleCM_CONTROLCHANGEis sent only to the immediate parent not up in the chain. - zig