如何在 Firemonkey 中创建“禁止激活”表单

2024-03-12

在 XCode 中,通过将这些方法添加到 NSView 子类中可以防止窗口在单击时变为活动状态:

- (BOOL)shouldDelayWindowOrderingForEvent:(NSEvent )theEvent {
    return YES;
}
- (BOOL)acceptsFirstMouse:(NSEvent )theEvent {
    return YES; 
}
- (void)mouseDown:(NSEvent )theEvent {
    [[[NSApp]] preventWindowOrdering]; 
}

在Windows平台上它是通过这个简单的代码完成的:

HWND hWnd = FindWindowW((String("FM") + fmxForm->ClassName()).c_str(), 
    fmxForm->Caption.c_str());

SetWindowLong(hWnd, GWL_EXSTYLE,
    GetWindowLong(hWnd, GWL_EXSTYLE) | WS_EX_NOACTIVATE);

如何子类化 NSView 以防止我的 FMX TForm 在单击它时变为活动状态?

我怎样才能创建“不激活“ 形式为火猴?


可以使用NSPanel with NSNonactivatingPanelMask旗帜。 fmx 表单的 NSView 应成为 NSPanel 的子级。我编写了一个适用于 Windows 和 Mac 平台的帮助程序类(适用于 XE4):

unit NoActivateForm;

interface

uses Fmx.Forms, Fmx.Types
{$IFDEF POSIX}
    , Macapi.AppKit
{$ENDIF}
    ;

type TNoActivateForm = class
private
    form: TForm;
{$IFDEF POSIX}
    panel: NSPanel;
    timer: TTimer;  // for simulating mouse hover event
{$ENDIF}
    procedure SetPosition(const x, y: Integer);
    procedure GetPosition(var x, y: Integer);
    procedure SetDimensions(const width, height: Integer);
    procedure SetLeft(const Value: Integer);
    procedure SetTop(const Value: Integer);
    procedure SetHeight(const Value: Integer);
    procedure SetWidth(const Value: Integer);
    procedure SetVisible(const Value: Boolean);
    function GetLeft: Integer;
    function GetTop: Integer;
    function GetHeight: Integer;
    function GetWidth: Integer;
    function GetVisible: Boolean;
{$IFDEF POSIX}
    procedure OnTimer(Sender: TObject);
{$ENDIF}
public
    constructor Create(AForm: TForm);
    destructor Destroy; override;
    property Left: Integer read GetLeft write SetLeft;
    property Top: Integer read GetTop write SetTop;
    property Height: Integer read GetHeight write SetHeight;
    property Width: Integer read GetWidth write SetWidth;
    property Visible: Boolean read GetVisible write SetVisible;
end;

implementation
uses
    Classes, System.Types
{$IFDEF MSWINDOWS}
    , Winapi.Windows;
{$ELSE}
    , Macapi.CocoaTypes, FMX.Platform.Mac, Macapi.CoreGraphics, Macapi.CoreFoundation;
{$ENDIF}

constructor TNoActivateForm.Create(AForm: TForm);
{$IFDEF POSIX}
var
    rect: NSRect;
    bounds: CGRect;
    window: NSWindow;
    style: integer;
    panelCount: integer;
begin
    form := AForm;
    form.Visible := false;
    bounds := CGDisplayBounds(CGMainDisplayID);
    rect := MakeNSRect(form.Left, bounds.size.height - form.Top - form.Height,
        form.ClientWidth, form.ClientHeight);
    style := NSNonactivatingPanelMask;
    style := style or NSHUDWindowMask;
    panel := TNSPanel.Wrap(
        TNSPanel.Alloc.initWithContentRect(rect, style, NSBackingStoreBuffered,
        true));
    panel.setFloatingPanel(true);
    //panel.setHasShadow(false); optional
    window := WindowHandleToPlatform(form.Handle).Wnd;

    panel.setContentView(TNSView.Wrap(window.contentView));
    TNSView.Wrap(window.contentView).retain;

    timer := TTimer.Create(form.Owner);
    timer.OnTimer := OnTimer;
    timer.Interval := 50;
end;
{$ELSE}
var hWin: HWND;
begin
    form := AForm;
    form.TopMost := true;
    hWin := FindWindow(PWideChar('FM' + form.ClassName), PWideChar(form.Caption));
    if hWin <> 0 then
        SetWindowLong(hWin, GWL_EXSTYLE,
            GetWindowLong(hWin, GWL_EXSTYLE) or WS_EX_NOACTIVATE);
end;
{$ENDIF}

destructor TNoActivateForm.Destroy;
{$IFDEF POSIX}
begin
    panel.release;
end;
{$ELSE}
begin
end;
{$ENDIF}

procedure TNoActivateForm.SetPosition(const x, y: Integer);
{$IFDEF POSIX}
var point: NSPoint;
    screen: CGRect;
begin
    screen := CGDisplayBounds(CGMainDisplayID);
    point.x := x;
    point.y := round(screen.size.height) - y - form.height;
    panel.setFrameOrigin(point);
end;
{$ELSE}
begin
    form.Left := x;
    form.Top := y;
end;
{$ENDIF}

procedure TNoActivateForm.GetPosition(var x, y: Integer);
{$IFDEF POSIX}
var screen: CGRect;
begin
    screen := CGDisplayBounds(CGMainDisplayID);
    x := round(panel.frame.origin.x);
    y := round(screen.size.height - panel.frame.origin.y - panel.frame.size.height);
end;
{$ELSE}
begin
    x := form.Left;
    y := form.Top;
end;
{$ENDIF}

procedure TNoActivateForm.SetDimensions(const width, height: Integer);
{$IFDEF POSIX}
var size: NSSize;
begin
    size.width := width;
    size.height := height;
    panel.setContentSize(size);
end;
{$ELSE}
begin
    form.width := width;
    form.height := height;
end;
{$ENDIF}

procedure TNoActivateForm.SetLeft(const Value: Integer);
begin
    SetPosition(Value, Top);
end;

procedure TNoActivateForm.SetTop(const Value: Integer);
begin
    SetPosition(Left, Value);
end;

procedure TNoActivateForm.SetHeight(const Value: Integer);
begin
    SetDimensions(Width, Value);
end;

procedure TNoActivateForm.SetWidth(const Value: Integer);
begin
    SetDimensions(Value, Height);
end;

procedure TNoActivateForm.SetVisible(const Value: Boolean);
begin
{$IFDEF POSIX}
    panel.setIsVisible(Value);
{$ELSE}
    form.visible := Value;
{$ENDIF}
end;

function TNoActivateForm.GetLeft: Integer;
var x, y: Integer;
begin
    GetPosition(x, y);
    result := x;
end;

function TNoActivateForm.GetTop: Integer;
var x, y: Integer;
begin
    GetPosition(x, y);
    result := y;
end;

function TNoActivateForm.GetHeight: Integer;
begin
{$IFDEF POSIX}
    result := round(panel.frame.size.height);
{$ELSE}
    result := form.Height;
{$ENDIF}
end;

function TNoActivateForm.GetWidth: Integer;
begin
{$IFDEF POSIX}
    result := round(panel.frame.size.width);
{$ELSE}
    result := form.Width;
{$ENDIF}
end;

function TNoActivateForm.GetVisible: Boolean;
begin
{$IFDEF POSIX}
    result := panel.isVisible();
{$ELSE}
    result := form.visible;
{$ENDIF}
end;

{$IFDEF POSIX}
procedure TNoActivateForm.OnTimer(Sender: TObject);
var event: CGEventRef;
    point: CGPoint;
    form_rect: TRectF;
    client_point, mouse_loc: TPointF;
    shift: TShiftState;
begin
    event := CGEventCreate(nil);
    point := CGEventGetLocation(event);
    CFRelease(event);
    mouse_loc.SetLocation(point.x, point.y);
    if Visible = true then
    begin
        form_rect := RectF(0, 0, form.Width, form.Height);
        client_point.X := mouse_loc.X - Left;
        client_point.Y := mouse_loc.y - Top;
        if PtInRect(form_rect, client_point) then
            form.MouseMove(shift, client_point.x, client_point.y)
        else
            form.MouseLeave();
    end;
end;
{$ENDIF}

end.

上述装置的用途:

TNoActivateForm *naKeyboard; // global scope    
void __fastcall TfrmKeyboard::TfrmKeyboard(TObject *Sender)
{
    naKeyboard = new TNoActivateForm(frmKeyboard); // frmKeyboard is a normal fmx form
    naKeyboard->Visible = true;
}

如果frmKeyboard是您的主窗体,那么不要将上述代码放在窗体构造函数中,建议将其放在OnShow中。

Note:WindowHandleToPlatform在XE3中似乎不存在,因此可以用以下内容替换该行

window := NSWindow(NSWindowFromObjC(FmxHandleToObjC(Form.Handle)));
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在 Firemonkey 中创建“禁止激活”表单 的相关文章

随机推荐

  • 如何使用 geom_boxplot(stat = "identity") 模拟带有异常值的 geom_boxplot()

    我想预先计算数据的变量摘要 使用plyr并通过一个quantile函数 然后用geom boxplot stat identity 这非常有效 除了它 a 不将异常值绘制为点以及 b 将 胡须 扩展到所绘制数据的最大值和最小值 Exampl
  • Git 分支命名规则[重复]

    这个问题在这里已经有答案了 当我在 Git 中命名分支时 我总是倾向于以字母开头 mybranch89例如 Git 分支的命名有什么规则吗 例如 我应该始终以字母开头 还是只能使用数字分支名称 例如876 规则是相当复杂 http git
  • 在 TextView 中显示图像

    我希望在 TextView 中显示图像 我的图像保存在 res raw 目录中 我尝试使用 HTML ImageGetter 但找不到相同的完整参考 import android app Activity import android gr
  • 追踪事务为何升级为 DTC

    有什么方法可以准确确定 System Transaction TrasactionScope 升级为 DTC 的原因吗 我们的一个组件遇到了麻烦 该组件似乎升级了交易 而所有其他组件 看起来看似相似 却没有升级 是否提供了有关升级原因以及如
  • 如何在Python中查找字符串中的一个数字?

    我有一个名为 FILE 1 txt 或 FILE 340 txt 的文件 我希望能够从文件名中获取数字 我发现我可以使用 numbers re findall r d s filename 获取包含数字的列表 并使用numbers 0 将数
  • 什么时候应该使用 XS?

    我正在写一篇关于 XS 的演讲 我需要知道社区何时认为适合采用 XS 我可以想到至少三个使用 XS 的理由 您有一个想要在 Perl 5 中访问的 C 库 您有一段代码 它确实会减慢您的程序速度 如果用 C 编写 速度会更快 您需要访问仅在
  • 想在Mysql中为两个不同的数据库编写触发器

    有没有办法在Mysql中的两个不同的数据库上创建触发器 我的要求是这样的 database test1 gt table tmp1 database test2 gt table tmp2 现在我必须在 test1 上使用触发器插入操作发生
  • 错误:没有匹配的函数来调用“Point::Point()”

    因此 我创建了 Point 类 并希望将其用作 Circle 类中构造函数的参数 但出现错误 没有显示类 Point 的默认构造函数 我不知道如何修复它 代码如下所示 class Point private int x y public P
  • 使用android的sip进行Android音频通话

    我为客户开发了一个使用 sip 进行互联网呼叫的应用程序 为此 他向我提供了两个有效的 sip 用户 ID 和密码 我正在使用 SIP API 进行 SIP 实施 客户说呼叫无法进行 当他使用自己的帐户登录时 他没有收到任何有关未接来电的通
  • 动态渲染vue模板

    我有 vue 模板数据作为字符串 例如 String s div myData div 现在我想在我已经定义的 vue 组件中进行渲染
  • Laravel 如何测试控制器中的复选框是否被选中

    我试图获取复选框是否已选中 在我看来
  • ASP.NET MVC 项目中的 Web 表单?

    我需要向 ASP NET MVC 项目添加一个 管理 区域 并且我需要它来使用 ASP NET Web 窗体 而不是 MVC ASP NET Web 窗体可以在 ASP NET MVC 应用程序中使用吗 我在 MVC 项目中有类似的东西 因
  • vtable存放在内存的什么位置?

    vtable存放在内存的什么位置 取决于编译器 在 VC 中 vtable 指针存储在对象分配的开始处 位于任何成员数据之前 前提是您的类至少有一个虚拟成员函数 如果您的类从具有虚函数表的其他类进行多重继承 则还可能有多个虚函数表指针 vt
  • 如何使用 JavaScript 从 Web 服务返回的二进制字符串构建 PDF 文件

    我正在尝试从二进制流中构建一个 PDF 文件 该文件是我收到的 Ajax 请求的响应 Via XmlHttpRequest我收到以下数据 PDF 1 4 hole data representing the file EOF 到目前为止我尝
  • jqgrid - 调整大小和覆盖

    HTML
  • Canvas 对象未显示,但位置在 Java Applet 中正确更新

    我的基本弹跳球小程序应该有一个球根据中的值移动loc变量 但什么也没有显示 打印输出loc表明移动它和弹离边界背后的数字 数学确实按其应有的方式工作 但没有任何显示 查看在线示例 我不明白为什么我的绘图 绘画代码没有按预期工作 这就是我所拥
  • 为轮播创建循环时出现问题 - 回到第一个元素

    我在轮播中创建循环时遇到问题 因此在单击事件 rightButton 上到达最后一张卡后它将返回到第一张卡 到目前为止 轮播在到达最后一张卡时停止 const carousel document querySelector data tar
  • Android 单元测试:在测试活动之前清除首选项

    我想确保在我之前清除首选项Activity在我的单元测试中开始 问题是要清除首选项 您需要调用getActivity 之后 Activity启动 它会读取首选项 Override protected void setUp throws Ex
  • 在 Immutable.js 中从 Map 内的 List 中删除元素的最佳方法

    我在用Facebook 的 Immutable js http facebook github io immutable js 加速我的 React 应用程序以利用PureRender混合 https facebook github io
  • 如何在 Firemonkey 中创建“禁止激活”表单

    在 XCode 中 通过将这些方法添加到 NSView 子类中可以防止窗口在单击时变为活动状态 BOOL shouldDelayWindowOrderingForEvent NSEvent theEvent return YES BOOL