如何覆盖调用以在 TEdit 中显示 CapsLock 提示 window?
How to override the call to show the CapsLock hint window in a TEdit?
基本上我有这个问题:CapsLock password message in TEdit visually fails with VCL Styles。
我想做的不是解决答案或评论中显示的问题。
我想完全禁用那个丑陋的提示 window。而是显示一张图片,让用户知道大写字母已锁定。
像这样
我找到了我的问题的解决方案,它涉及到我不想使用的 hack。
事情是这样的。
- 覆盖 WndProc。
代码
type
TEdit = class (Vcl.StdCtrls.TEdit)
protected
procedure WndProc(var Message: TMessage); override;
end;
- 截取
EM_SHOWBALLOONTIP
消息,您就完成了
代码
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 键以及在 TPasswordEdit
时触发(可选) =19=] 已更改。
使用这种方法,我可以使用 OnPasswordCapsLock
事件来 show/hide 我问题中的图像,而不是强迫组件的使用者为每个状态使用两个事件处理程序(非常聪明方式和更不容易出错)。
只要 LNeedHandle := FBlockCapsBalloonTip and IsPassword;
是 True
我还有另一个添加到 TPasswordEdit
的功能,即 OnEnter
和 OnExit
在 OnPasswordCapsLock
还有,
所以我能说什么 Kobik 先生 Je vous tire 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;
基本上我有这个问题:CapsLock password message in TEdit visually fails with VCL Styles。
我想做的不是解决答案或评论中显示的问题。
我想完全禁用那个丑陋的提示 window。而是显示一张图片,让用户知道大写字母已锁定。
像这样
我找到了我的问题的解决方案,它涉及到我不想使用的 hack。
事情是这样的。
- 覆盖 WndProc。
代码
type
TEdit = class (Vcl.StdCtrls.TEdit)
protected
procedure WndProc(var Message: TMessage); override;
end;
- 截取
EM_SHOWBALLOONTIP
消息,您就完成了
代码
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
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 键以及在 TPasswordEdit
时触发(可选) =19=] 已更改。
使用这种方法,我可以使用 OnPasswordCapsLock
事件来 show/hide 我问题中的图像,而不是强迫组件的使用者为每个状态使用两个事件处理程序(非常聪明方式和更不容易出错)。
只要 LNeedHandle := FBlockCapsBalloonTip and IsPassword;
是 True
我还有另一个添加到 TPasswordEdit
的功能,即 OnEnter
和 OnExit
在 OnPasswordCapsLock
还有,
所以我能说什么 Kobik 先生 Je vous tire 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;