我已经编写了一个自定义控件(TCustomControl
),它显示了悬停时的标准内置提示。但是,禁用该控件时,不会显示提示。但是,TSpeedButton
确实会在禁用时显示提示,因此必须有一种方法可以在我的控制中执行相同操作。
当我的控件被禁用时,我需要做些什么才能显示提示?
答案 0 :(得分:5)
标准提示机制基于鼠标消息。从TWinControl
(包括TCustomControl
)派生的控件在禁用时不会收到鼠标消息,并且提示系统在内部忽略禁用的窗口控件。 TSpeedButton
源自TGraphicControl
而不是TWinControl
,因此不受这些限制。
答案 1 :(得分:3)
您需要启用窗口句柄才能获得开始显示提示的WM_MOUSEMOVE
。这有一些影响。
首先,要启用窗口句柄(WinAPI),您需要从窗口样式中删除WS_DISABLED
样式,或使用EnableWindow
。此修改不会同步VCL的Enabled
属性(与其他方式不同:设置Enabled
属性dóescallEnableWindow
),这就是为什么会这样做。
但启用窗口句柄可让所有鼠标消息通过,因此您必须在WM_MOUSEMOVE
上手动阻止它们并激活提示:
type
TMyControl = class(TCustomControl)
private
FDisabledHint: Boolean;
procedure CheckEnabled;
procedure SetDisabledHint(Value: Boolean);
procedure CMEnabledchanged(var Message: TMessage);
message CM_ENABLEDCHANGED;
protected
procedure CreateParams(var Params: TCreateParams); override;
procedure SetParent(AParent: TWinControl); override;
procedure WndProc(var Message: TMessage); override;
published
property DisabledHint: Boolean read FDisabledHint write SetDisabledHint;
end;
{ TMyControl }
procedure TMyControl.CheckEnabled;
begin
if DisabledHint and HasParent and (not Enabled) and
not (csDesigning in ComponentState) then
EnableWindow(Handle, True);
end;
procedure TMyControl.CMEnabledchanged(var Message: TMessage);
begin
inherited;
CheckEnabled;
end;
procedure TMyControl.CreateParams(var Params: TCreateParams);
begin
inherited CreateParams(Params);
if DisabledHint and not Enabled then
Params.Style := Params.Style and (not WS_DISABLED);
end;
procedure TMyControl.SetDisabledHint(Value: Boolean);
begin
if FDisabledHint <> Value then
begin
FDisabledHint := Value;
CheckEnabled;
end;
end;
procedure TMyControl.SetParent(AParent: TWinControl);
begin
inherited SetParent(AParent);
CheckEnabled;
end;
procedure TMyControl.WndProc(var Message: TMessage);
begin
if not Enabled and DisabledHint and (Message.Msg = WM_MOUSEMOVE) then
Application.HintMouseMessage(Self, Message);
if Enabled or (Message.Msg < WM_MOUSEFIRST) or
(Message.Msg > WM_MOUSELAST) then
inherited WndProc(Message);
end;
我检查了TabStop
属性的工作情况,此解决方案不会干扰它。但要注意我尚未想到的问题。
(此外,禁用TControl
显示提示的原因是因为它从其父级的CM_MOUSEENTER
收到WndProc
,尽管同一个父级通过{{阻止所有其他鼠标输入1}}以防止鼠标事件被触发。)
答案 2 :(得分:1)
实际上,当您禁用控件时,您甚至无法调用Winproc的Winproc。这是一个小型演示,以便更好地理解消息循环。
在表单上放置TPanel,并向表单添加Double clickEvent。然后尝试以下代码:
unit Unit39;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls;
type
TPanel = class(ExtCtrls.TPanel)
protected
procedure WndProc(var Message: TMessage); override;
end;
TForm39 = class(TForm)
Panel1: TPanel;
procedure FormDblClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form39: TForm39;
implementation
{$R *.dfm}
{ TPanel }
procedure TPanel.WndProc(var Message: TMessage);
begin
inherited;
Application.MainForm.Caption := FloatToStr(now);
end;
procedure TForm39.FormDblClick(Sender: TObject);
begin
Panel1.Enabled := not Panel1.Enabled;
end;
end.
YES!正确:丑陋的黑客攻击和违反所有设计模式但是通过这个小例子你可以看到消息循环是如何工作的,这是一种测试某些东西的简单方法。
PS:我将此作为答案,因为您无法在评论中格式化文本:D