如何覆盖调用以在TEdit中显示CapsLock提示窗口?

时间:2017-12-11 14:20:42

标签: delphi delphi-10-seattle

基本上我有这个问题:CapsLock password message in TEdit visually fails with VCL Styles

我想做的不是解决问题,如答案或评论中所示。

我想完全禁用那个丑陋的提示窗口。而是显示一个图像,让用户知道上限被锁定。

像这样

enter image description here

1 个答案:

答案 0 :(得分:7)

我找到了问题的解决方案,它涉及到我宁愿不使用的黑客攻击。

就是这样。

  1. 覆盖WndProc。
  2. type
      TEdit = class (Vcl.StdCtrls.TEdit)
      protected
        procedure WndProc(var Message: TMessage); override;
      end;
    
    1. 拦截EM_SHOWBALLOONTIP消息,您已完成
    2. procedure TEdit.WndProc(var Message: TMessage);
      begin
       if Message.Msg = EM_SHOWBALLOONTIP then
         showmessage('Do your thing.')
       else
        inherited;
      end;
      

      有关详细信息,请查看MSDN文档:

      How do I suppress the CapsLock warning on password edit controls?

      这是TEdit的后代,如果某个FOnPasswordCaps事件分配了PasswordChar <> #0

      ,则可以禁止密码编辑控件上的CapsLock警告
      unit NCREditUnit;
      
      interface
      
      uses
        Vcl.StdCtrls,
        vcl.Controls,
        Winapi.Messages,
        System.Classes;
      
      type
        TNCREdit = class(TEdit)
        private
          FOnPasswordCapsLocked: TNotifyEvent;
          FIsCapsLocked: boolean;
          FOnPasswordCapsFreed: TNotifyEvent;
          FBlockCapsBalloonTip: boolean;
          FValuePasswordChrOnCaps: boolean;
          procedure SetOnPasswordCapsEvents;
          procedure SetOnPasswordCapsFreed(const aValue: TNotifyEvent);
          procedure SetOnPasswordCapsLocked(const aValue: TNotifyEvent);
        protected
          procedure WndProc(var Message: TMessage); override;
          procedure KeyUp(var Key: Word; Shift: TShiftState); override;
          procedure DoEnter; override;
          procedure DoExit; override;
        published
          property BlockCapsBalloonTip: boolean read FBlockCapsBalloonTip write FBlockCapsBalloonTip default False;
          property ValuePasswordChrOnCaps: boolean read FValuePasswordChrOnCaps write FValuePasswordChrOnCaps default True;
      
      //... The usual property declaration of TEdit
      
          property OnPasswordCapsLocked: TNotifyEvent read FOnPasswordCapsLocked write SetOnPasswordCapsLocked;
          property OnPasswordCapsFreed: TNotifyEvent read FOnPasswordCapsFreed write SetOnPasswordCapsFreed;
        end;
      
      
      implementation
      
      uses
        Winapi.CommCtrl,
        Winapi.Windows;
      
      { TNCREdit }
      
      procedure TNCREdit.DoEnter;
      begin
        inherited;
        if FBlockCapsBalloonTip then
          begin
            FIsCapsLocked := Odd(GetKeyState(VK_CAPITAL));
            SetOnPasswordCapsEvents;
          end;
      end;
      
      procedure TNCREdit.DoExit;
      begin
        if FBlockCapsBalloonTip and (FIsCapsLocked) then
          begin
            FIsCapsLocked := False;
            SetOnPasswordCapsEvents;
          end;
        inherited;
      end;
      
      procedure TNCREdit.KeyUp(var Key: Word; Shift: TShiftState);
      begin
        if Key = VK_CAPITAL then
          FIsCapsLocked := not FIsCapsLocked;
        SetOnPasswordCapsEvents;
        inherited;
      end;
      
      procedure TNCREdit.SetOnPasswordCapsEvents;
      begin
        if FIsCapsLocked then
          begin
            if Assigned(FOnPasswordCapsLocked) and
               ((self.PasswordChar <> #0) or ( not FValuePasswordChrOnCaps)) then
            begin
            FOnPasswordCapsLocked(Self);
            end;
          end
        else
          begin
            if Assigned(FOnPasswordCapsLocked) and
               ((self.PasswordChar <> #0) or ( not FValuePasswordChrOnCaps)) then
            begin
            FOnPasswordCapsFreed(Self);
            end;
          end;
      end;
      
      procedure TNCREdit.SetOnPasswordCapsFreed(const aValue: TNotifyEvent);
      begin
        FOnPasswordCapsFreed := aValue;
        FBlockCapsBalloonTip := True;
      end;
      
      procedure TNCREdit.SetOnPasswordCapsLocked(const aValue: TNotifyEvent);
      begin
        FOnPasswordCapsLocked := aValue;
        FBlockCapsBalloonTip := True;
      end;
      
      procedure TNCREdit.WndProc(var Message: TMessage);
      begin
        if (Message.Msg = EM_SHOWBALLOONTIP) and FBlockCapsBalloonTip then Exit; 
        inherited;
      end;
      
      end.
      

      Kobik先生制作了一段非常优雅的代码,我认为不应该信任PasteBin,所以我决定在这里添加它。

      根据我的理解,它允许您在TPasswordCapsLockState获得焦点时失效的一个事件处理程序中处理TPasswordEdit,失去焦点,在焦点处按下CapsLock键并在{{1时触发可选触发改变了。

      使用这种方法,我可以使用PasswordChar事件来显示/隐藏我的问题中的图像,而不是强迫组件的使用者为每个状态使用两个事件处理程序(顺便说一句,非常聪明,错误少)易发生)。

      只要OnPasswordCapsLockLNeedHandle := FBlockCapsBalloonTip and IsPassword;我还有True的另一个附加功能,即TPasswordEditOnEnterOnExit的处理同样,

      那么我怎能说Kobik先生 Je vous tire mon chapeau。

      OnPasswordCapsLock