基本上我有这个问题:
CapsLock password message in TEdit visually fails with VCL Styles.
我想完全禁用那个丑陋的提示窗口.而是显示一个图像,让用户知道帽子被锁定.
像这样
解决方法
我找到了我的问题的解决方案,它涉及到我宁愿不使用的黑客攻击.
它是这样的.
>覆盖WndProc.
码
type TEdit = class (Vcl.StdCtrls.TEdit) protected procedure WndProc(var Message: TMessage); override; end;
>拦截EM_SHOWBALLOONTIPmessage,你就完成了
码
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的后代,如果使用PasswordChar<>分配某个FOnPasswordCaps事件,则允许在密码编辑控件上抑制CapsLock警告. #0
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,所以我决定在这里添加它.
根据我的理解,它允许您在TPasswordEdit接收焦点时触发的一个事件处理程序中处理TPasswordCapsLockState,失去焦点,在焦点处按下CapsLock键,并在PasswordChar更改时触发可选触发.
使用这种方法,我可以使用OnPasswordCapsLock事件在我的问题中显示/隐藏图像,而不是强迫组件的使用者为每个状态使用两个事件处理程序(顺便说一句非常聪明且不易出错).
也只要LNeedHandle:= FBlockCapsBalloonTip和IsPassword;是真的我有另一个TPasswordEdit的附加功能,它也是在OnPasswordCapsLock中处理OnEnter和OnExit,
那么我能说什么Kobik Je vous轮胎mon chapeau.
type TPasswordCapsLockState = (pcsEnter,pcsExit,pcsKey,pcsSetPasswordChar); TPasswordCapsLockEvent = procedure(Sender: TObject; Locked: Boolean; State: TPasswordCapsLockState) of object; TPasswordEdit = class(TCustomEdit) private FIsCapsLocked: boolean; FBlockCapsBalloonTip: boolean; FOnPasswordCapsLock: TPasswordCapsLockEvent; protected procedure WndProc(var Message: TMessage); override; procedure KeyUp(var Key: Word; Shift: TShiftState); override; procedure DoEnter; override; procedure DoExit; override; procedure HandlePasswordCapsLock(State: TPasswordCapsLockState); virtual; function GetIsPassword: Boolean; virtual; public property IsPassword: Boolean read GetIsPassword; published property BlockCapsBalloonTip: boolean read FBlockCapsBalloonTip write FBlockCapsBalloonTip default False; //... The usual property declaration of TEdit property OnPasswordCapsLock: TPasswordCapsLockEvent read FOnPasswordCapsLock write FOnPasswordCapsLock; end; implementation function TPasswordEdit.GetIsPassword: Boolean; begin Result := ((PasswordChar <> #0) or // Edit control can have ES_PASSWORD style with PasswordChar == #0 // if it was creaed with ES_PASSWORD style (HandleAllocated and (GetWindowLong(Handle,GWL_STYLE) and ES_PASSWORD <> 0))); end; procedure TPasswordEdit.HandlePasswordCapsLock; var LNeedHandle: Boolean; begin LNeedHandle := FBlockCapsBalloonTip and IsPassword; if LNeedHandle then begin FIsCapsLocked := Odd(GetKeyState(VK_CAPITAL)); if Assigned(FOnPasswordCapsLock) then FOnPasswordCapsLock(Self,FIsCapsLocked,State); end; end; procedure TPasswordEdit.DoEnter; begin inherited; HandlePasswordCapsLock(pcsEnter); end; procedure TPasswordEdit.DoExit; begin inherited; HandlePasswordCapsLock(pcsExit); end; procedure TPasswordEdit.KeyUp(var Key: Word; Shift: TShiftState); begin inherited; if Key = VK_CAPITAL then HandlePasswordCapsLock(pcsKey); end; procedure TPasswordEdit.WndProc(var Message: TMessage); begin if (Message.Msg = EM_SHOWBALLOONTIP) and FBlockCapsBalloonTip and IsPassword then Exit; // Optional - if password char was changed if (Message.Msg = EM_SETPASSWORDCHAR) and Self.Focused then HandlePasswordCapsLock(pcsSetPasswordChar); inherited; end;