gpt4 book ai didi

Delphi - 当用户单击模式对话框外部时如何生成事件?

转载 作者:行者123 更新时间:2023-12-03 14:41:54 26 4
gpt4 key购买 nike

当用户在模式对话框外部单击时是否可以触发事件?

好的,当您通过发出“bonk”声音或闪烁应用程序的任务栏按钮来执行此操作时,Windows 会提供自己的线索,但我想为声音不可用和/的情况提供某种额外的线索或者用户不知道任务栏闪烁的原因。另外,如果模态对话框隐藏在主窗体后面,我想尝试使用此方法将其置于前面。

最佳答案

首先回答问题:

当鼠标移动到对话框之外或显示时已经在对话框之外时,您可以捕获鼠标。然后您可以捕捉 WM_CAPTURECHANGED 来触发 OnMouseClickOutside 事件:

type
TDialog = class(TForm)
private
FMouseInDialog: Boolean;
FOnMouseClickOutside: TNotifyEvent;
procedure WMCaptureChanged(var Message: TMessage);
message WM_CAPTURECHANGED;
procedure CMMouseLeave(var Message: TMessage); message CM_MOUSELEAVE;
procedure CMMouseEnter(var Message: TMessage); message CM_MOUSEENTER;
protected
procedure DoShow; override;
public
property OnMouseClickOutside: TNotifyEvent read FOnMouseClickOutside
write FOnMouseClickOutside;
end;

...

procedure TDialog.CMMouseLeave(var Message: TMessage);
begin
// CM_MOUSELEAVE is also send to the dialog when the mouse enters a control that
// is within the dialog:
if not PtInRect(BoundsRect, Mouse.CursorPos) then
begin
// Now the mouse is really outside the dialog. Start capturing it:
MouseCapture := True;
FMouseInDialog := False;
end;
inherited;
end;

procedure TDialog.CMMouseEnter(var Message: TMessage);
begin
FMouseInDialog := True;
// Only release capture when it had, otherwise it might affect another control:
if MouseCapture then
MouseCapture := False;
inherited;
end;

procedure TDialog.DoShow;
begin
inherited DoShow;
// When mouse is outside the dialog when it should become visible, CM_MOUSELEAVE
// isn't send because the mouse hasn't been inside yet. So also capture mouse
// when the dialog is shown:
MouseCapture := True;
end;

procedure TDialog.WMCaptureChanged(var Message: TMessage);
begin
// When the dialog loses mouse capture and the mouse is outside the dialog, fire:
if (not FMouseInDialog) and Assigned(FOnMouseClickOutside) then
FOnMouseClickOutside(Self);
inherited;
end;

这有效。对于可见对话框和模糊对话框。但正如大卫感激地评论的那样,这对依赖鼠标捕获的控制产生了影响。据我所知,大多数控件(例如备忘录或菜单栏)都可以正常运行。但以组合框为例:当下拉组合框时,列表框会捕获鼠标。当它失去鼠标时,列表就会被打包。因此,当用户将鼠标移到对话框之外时(请注意,下拉列表可能位于对话框之外),组合框将表现出非默认行为。

其次,进一步解决实际问题:

此外,该问题特别指出了在隐藏对话框的情况下需要此事件。好吧,上面的鼠标离开和进入代码取决于对话框是否可见,所以让我们忘记所有这些,摆脱缺点并将代码减少为:

type
TDialog = class(TForm)
private
FOnMouseClickOutside: TNotifyEvent;
procedure WMCaptureChanged(var Message: TMessage);
message WM_CAPTURECHANGED;
protected
procedure DoShow; override;
public
property OnMouseClickOutside: TNotifyEvent read FOnMouseClickOutside
write FOnMouseClickOutside;
end;

...

procedure TDialog.DoShow;
begin
inherited DoShow;
MouseCapture := True;
end;

procedure TDialog.WMCaptureChanged(var Message: TMessage);
begin
if Assigned(FOnMouseClickOutside) then
FOnMouseClickOutside(Self);
inherited;
end;

现在,如果事件触发该怎么办?该对话框仍然处于隐藏状态,并且对 BringToFront 的调用不起作用。 (相信我,我已经测试过它,尽管重现隐藏对话框非常令人讨厌)。您应该做的是使用 SetWindowPos 将对话框置于所有其他窗口之上:

procedure TAnyForm.MouseClickOutsideDialog(Sender: TObject);
begin
if Sender is TDialog then
SetWindowPos(TWinControl(Sender).Handle, HWND_TOPMOST, 0, 0, 0, 0,
SWP_NOMOVE or SWP_NOSIZE or SWP_NOACTIVATE or SWP_NOOWNERZORDER);
end;

但是由于对话框应始终显示在所有其他对话框之上,因此您宁愿完全消除该事件并将代码修改为:

type
TDialog = class(TForm)
private
procedure CMShowingChanged(var Message: TMessage);
message CM_SHOWINGCHANGED;
end;

...

procedure TDialog.CMShowingChanged(var Message: TMessage);
begin
if Showing then
SetWindowPos(Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE or SWP_NOSIZE
or SWP_NOACTIVATE or SWP_NOOWNERZORDER);
inherited;
end;

结论:

现在,这仍然不适用于消息或系统对话框(尽管您可以使用 these nice dialogs ),并且我必须同意 David 的观点,找出模式对话框变得模糊的原因。如果您有带有 FormStyle = fsStayOnTop 的表单(或任何带有 HWND_TOPMOST 作为 Z 顺序的窗口),那么您应该使用以下适当的应用程序方法来临时补偿这些窗口:

procedure TAnyForm.Button1Click(Sender: TObject);
var
Dialog: TDialog;
begin
Application.NormalizeAllTopMosts;
Dialog := TDialog.Create(Application);
try
Dialog.ShowModal;
finally
Dialog.Free;
Application.RestoreTopMosts;
end;
end;

在所有其他情况下,模式对话框的消失表明您正在执行 VCL 可能无法处理的异常操作。

关于Delphi - 当用户单击模式对话框外部时如何生成事件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9856956/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com