如何显示禁用控件的提示?

时间:2013-05-14 08:39:46

标签: delphi

我有一个复选框,可在运行时启用/禁用。我只想显示启用/禁用的不同工具提示。我正在考虑重写OnMouseEnter事件并在那里处理它,但只有在启用控件时才会调用OnMouseEnter。我怎么可能实现这种行为?任何帮助,将不胜感激。

我尝试处理表单的OnMouseMove并执行类似的操作

procedure Tdlg.pnlTopMouseMove(Sender: TObject;Shift: TShiftState; X, Y: Integer);
var
  point: TPoint;
  checkBoxCursorPos: TPoint;
begin
  inherited;
  point.X := X;
  point.Y := Y;
  checkBoxCursorPos := chkBx.ScreenToClient(point);
  if (PtInRect(chkBx.ClientRect, checkBoxCursorPos)) then
  begin
    if(chkBx.Enabled) then
      chkBx.Hint := 'Enabled'
    else
      chkBx.Hint := 'Disabled' ;

    Application.ShowHint := True;
  end;

end;

但条件PtinRect不满意。我做错了什么?

3 个答案:

答案 0 :(得分:6)

有一个简单的解决方案:在复选框上放置一个空TLabel,并将其Hint设置为禁用复选框状态的值。标签必须关闭AutoSize,您可以通过将BoundsRect属性设置为CheckBox的属性来强制执行位置和大小。

启用CheckBox时,会使用Checkbox的提示,而禁用CheckBox时会使用Label的提示。

更新:刚看到Bummi在评论中提到了类似的想法。

答案 1 :(得分:2)

官方答复:you can’t

解决方法:您可以尝试使用表单的 MouseMove事件(假设当然不会被禁用),如果鼠标光标位于相关控件上,则显示相应的提示

答案 2 :(得分:0)

这里是一个可以显示禁用控件提示的单元。

我这样使用它:

TATHintControl.Create(self).HintStyleController := GlobalHintStyleController;

GlobalHintStyleController是一个DevExpress样式控制器。 然后是单位

unit ATHintControl;

{
The purpose of this component is to show hints for disabled controls (VCL doesn't)
It uses timestamp comparison instead of Timers to save resources 
}
interface

uses
  // VCL
  Classes,
  Controls,
  Forms,
  AppEvnts,
  Messages,
  Windows,

  // DevEx
  cxHint;

type
  TGetHintForControlEvent = function(AControl: TControl): string of object;
  THandleControlEvent = function(AControl: TControl): boolean of object;

  TATHintControl = class(TComponent)
  private
    fHintTimeStamp: TDateTime;
    fHintHideTimeStamp: TDateTime;
    fHintControl: TControl;
    fHintVisible: boolean;
    FHintStyleController: TcxHintStyleController;
    FHintShowDelay: Integer;
    FHintHideDelay: Integer;
    fGetHintForControlEvent: TGetHintForControlEvent;
    fHandleControlEvent: THandleControlEvent;
    fApplicationEvents: TApplicationEvents;
    procedure IdleHandler(Sender: TObject; var Done: Boolean);
    procedure ShortcutHandler(var Msg: TWMKey; var Handled: Boolean);
    procedure SetHintStyleController(const Value: TcxHintStyleController);
    procedure HideHint;
    function GetCursorPos(out APoint: TPoint): Boolean;
    function HandleHint: boolean;
  protected
    function GetHintForControl(AControl: TControl): string; virtual;
    function HandleControl(AControl: TControl): boolean; virtual;
  public
    procedure AfterConstruction; override;
  published
    property HintStyleController: TcxHintStyleController read FHintStyleController write SetHintStyleController;
    property OnGetHintForControl: TGetHintForControlEvent read fGetHintForControlEvent write fGetHintForControlEvent;
    property OnHandleControl: THandleControlEvent read fHandleControlEvent write fHandleControlEvent;
  end;

implementation

uses
  Types,
  SysUtils,
  DateUtils;

const
  cHintShowDelay: Integer = 500; // msec
  cHintHideDelay: Integer = 3 * 1000; // 3 sec

{ TATHintControl }

procedure TATHintControl.AfterConstruction;
begin
  inherited;
  fApplicationEvents := TApplicationEvents.Create(self);
  fApplicationEvents.OnIdle := IdleHandler;
  fApplicationEvents.OnShortCut := ShortcutHandler;
  fHintShowDelay := cHintShowDelay;
  fHintHideDelay := cHintHideDelay;
end;

function TATHintControl.GetCursorPos(out APoint: TPoint): Boolean;
begin
{$WARN SYMBOL_PLATFORM OFF}
  result := Windows.GetCursorPos(APoint);
{$WARN SYMBOL_PLATFORM ON}
end;

function TATHintControl.GetHintForControl(AControl: TControl): string;
begin
  if Assigned(OnGetHintForControl) then
    result := OnGetHintForControl(AControl)
  else
    result := AControl.Hint;
end;

procedure TATHintControl.HideHint;
begin
  HintStyleController.HideHint;
  fHintTimeStamp := 0;
  fHintVisible := false;
  fHintHideTimeStamp := 0;
end;

procedure TATHintControl.IdleHandler(Sender: TObject; var Done: Boolean);
begin
  if Assigned(HintStyleController) then
    Done := HandleHint;
end;

procedure TATHintControl.SetHintStyleController(
  const Value: TcxHintStyleController);
begin
  FHintStyleController := Value;
end;

procedure TATHintControl.ShortcutHandler(var Msg: TWMKey; var Handled: Boolean);
begin
  fHintControl := nil; // clear the HintControl so that keypress causes it to be shown again w/o having to move the mouse
end;

function TATHintControl.HandleControl(AControl: TControl): boolean;
begin
  if Assigned(OnHandleControl) then
    result := OnHandleControl(AControl)
  else
    result := not AControl.Enabled;
end;

function TATHintControl.HandleHint: boolean;
var
  vNow: TDateTime;
  vScreenPos: TPoint;
  vClientPos: TPoint;
  vControl: TControl;
  vHintString: string;
  vForm: TForm;
  vWinControl: TWinControl;
begin
  result := (fHintTimeStamp = 0);
  vForm := Screen.ActiveForm;
  if not Assigned(vForm) then
    exit;
  if not boolean(GetCursorPos(vScreenPos)) then
    exit;
  vNow := Now;

  vControl := nil;
  vWinControl := vForm as TWinControl;
  while Assigned(vWinControl) do
  try
    vClientPos := vWinControl.ScreenToClient(vScreenPos);  
    vControl := vWinControl.ControlAtPos(vClientPos, true, true, true);
    if not Assigned(vControl) then    
    begin
      vControl := vWinControl;
      break;
    end
    else
    if vControl is TWinControl then
      vWinControl := vControl as TWinControl
    else
      vWinControl := nil;    
  except
    exit; // in some cases ControlAtPos can fail with EOleError: Could not obtain OLE control window handle.
  end;

  if (fHintControl <> vControl) then
  begin
    if fHintVisible then
      HideHint;
    if Assigned(vControl) and HandleControl(vControl) then
    begin
      fHintControl := vControl;
      fHintTimeStamp := vNow; // starts timer for hint to show
    end
    else
    begin
      fHintTimeStamp := 0;
      fHintControl := nil;
    end;
  end
  else
  begin
    if fHintVisible and (vNow > fHintHideTimeStamp) then
    begin
      HideHint;
    end
    else   // we check HandleControl again here to make sure we still want to show the hint
    if not fHintVisible and Assigned(vControl) and HandleControl(vControl) and (fHintTimeStamp > 0) and (vNow > IncMillisecond(fHintTimeStamp, fHintShowDelay)) then
    begin
      vHintString := GetHintForControl(vControl);
      if vHintString = '' then
        exit;

      HintStyleController.ShowHint(vScreenPos.X + 0, vScreenPos.Y + 18, '', vHintString);
      fHintTimeStamp := vNow;
      fHintControl := vControl;
      fHintVisible := true;
      // base hide delay + dynamic part based on length of the hint string, 500 msec per 30 characters
      fHintHideTimeStamp := vNow + IncMillisecond(0, fHintHideDelay) + ((Length(vHintString) div 20) * EncodeTime(0,0,0,500));
    end
  end;
  result := (fHintTimeStamp = 0);
end;

end.