如何正确回复自定义控件中的焦点消息?

时间:2015-07-17 15:13:58

标签: delphi delphi-xe7

我需要创建自己的面板,该面板将派生自TCustomPanel - 这里我将在面板上进行自己的自定义绘画,例如在顶部绘制标题。

我需要的一个要求是我需要能够根据我的面板是否有焦点来绘制两种不同的颜色,我还需要一种方法来了解我的面板中的子控件是否也有焦点 - 当然,虽然不知道孩子的内容是什么。

因此,例如,如果面板(或面板内的任何子控件)具有焦点,则颜色可以是clSkyBlue。如果面板(或面板内没有任何子控件)没有焦点,则颜色可能为clWhite

以下是自定义面板的快速布局:(为了保持简单,示例中没有标题图,只是基本的颜色变化)

type
  TMyPanel = class(TCustomPanel)
  private
    //
  protected
    // procedure Paint; override;

    procedure WMMouseDown(var Message: TWMLButtonDown); message WM_LBUTTONDOWN;        
    procedure WMKillFocus(var Message: TWMKillFocus); message WM_KILLFOCUS;
    procedure WMSetFocus(var Message: TWMSetFocus); message WM_SETFOCUS;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  end;

constructor TMyPanel.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);

  Self.ParentBackground := False;
  Self.ParentColor := False;
end;

destructor TMyPanel.Destroy;
begin
  inherited Destroy;
end;

procedure TMyPanel.WMMouseDown(var Message: TWMLButtonDown);
begin
  Self.SetFocus;
end;

procedure TMyPanel.WMKillFocus(var Message: TWMKillFocus);
begin
  Self.Color := clWhite;
  Invalidate;
end;

procedure TMyPanel.WMSetFocus(var Message: TWMSetFocus);
begin
  Self.Color := clSkyBlue;
  Invalidate;
end;

我遇到的第一个问题是让小组可以集中精力,我确信会有一个我忽略的正确解决方案,但在这种情况下我通过拦截WM_LBUTTONDOWN消息使用了一个肮脏的技巧让小组专注。这当然也否定了我之前提到的其他要求,其中儿童控制也决定了小组应该是什么颜色,这取决于小组或它的儿童控制是否集中。

当我点击我的面板时会发生这种情况:

enter image description here

点击子控件时会发生这种情况:

enter image description here

正如您所看到的那样,面板变为白色,但我需要转向clSkyBlue以指示面板或其子内容具有焦点,如下所示:

enter image description here

那么,正确识别我的自定义控件或它的子控件是否具有焦点的解决方案是什么?

我曾想过迭代遍历面板内的每个子控件以确定它是否有焦点但是我不知道如何首先触发这样的事件,因为直接点击子控件肯定会忽略任何自定义面板等待拦截的消息。

2 个答案:

答案 0 :(得分:5)

所有TWinControl后代都已成为焦点,您的TCustomPanel后代也是如此。在这方面没有必要做任何额外的工作。

为您自动完成的操作(我认为您想要做的)是直观地显示组件的焦点状态。一种可行的方法是处理CM_ENTERCM_EXIT消息:

  TMyPanel = class(TCustomPanel)
  private
    procedure FocusChanged(Value: Boolean);
  protected
    procedure CMEnter(var Message: TCMEnter); message CM_ENTER;
    procedure CMExit(var Message: TCMExit); message CM_EXIT;
  end;

procedure TMyPanel.CMEnter(var Message: TCMEnter);
begin
  FocusChanged(True);
end;

procedure TMyPanel.CMExit(var Message: TCMExit);
begin
  FocusChanged(False);
end;

procedure TMyPanel.FocusChanged(Value: Boolean);
const
  Colors: array[Boolean] of TColor = (clWhite, clSkyBlue);
begin
  Color := Colors[Value];
end;

答案 1 :(得分:0)

一种简单的方法是创建自己的编辑而不是TPanel。

您的衍生修改可能会控制OnEnter();OnExit()事件,并可能控制其父颜色。

作为一个可以看到你知道如何拦截事件,这将是一个更容易的方法。