【发布时间】:2017-07-25 13:59:54
【问题描述】:
我注意到,如果我有一个主容器/父级 (MainPanel),向它添加一个子面板 (ChildPanel),将在 MainPanel (TWinControl.InsertControl()) 上执行 CM_CONTROLLISTCHANGE,这很好.
但是,如果我将子控件 (ChildButton) 插入到 ChildPanel,则会为主 MainPanel 再次触发 CM_CONTROLLISTCHANGE!
这是为什么呢?将ChildButton 插入ChildPanel 时,我希望CM_CONTROLLISTCHANGE 只为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:我不知道这是否重要,但我在 Delphi 5 上。
【问题讨论】:
-
所有未处理的 windows 消息都通过父链向上传播。如果孩子不处理消息,父母就有机会这样做,依此类推。
-
@Dsm 你确定吗?这是怎么发生的?一些VCL代码?或者是 Windows 功能。我必须承认我对你所写的说法持怀疑态度。
-
@Dsm,
CM_CONTROLLISTCHANGE是自定义 notification VCL 消息 AFAIK(不确定它是否与本机 Window 消息相同)。我无法在来源中找到如何它是“通过父链向上传播”。所以我仍然不知道发生了什么以及如何。我的主要问题是我无法分辨CMControlListChange消息处理程序中插入控件的Parent是谁(但这可能是另一个问题)。 -
@Dsm 很难看出怎么会这样。例如,考虑一个班级私人消息。因为它们是类私有的,所以它们只能被发送到该类的窗口。如果它们被发送到不同类别的窗口,则该消息 ID 可能是不同类别私人消息的 ID。所以我只能得出结论,你在第一条评论中所说的显然是错误的。我建议谨慎的做法是删除所有这些 cmets,以免给读者造成混淆。
-
@Dsm, “所有未处理的 Windows 消息都通过父链向上传播” - 错误。 VCL 专门将
CM_CONTROLLISTCHANGE向上传播到父链。但不是为了任何消息。例如,CM_CONTROLCHANGE仅发送给不在链上的直接父级。