如何在 Firemonkey 建立「不启动」表格

在 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 成为活动时,点击它?

如何在 火猴中创建“ 没有,启动”表单?

7612 次浏览

你可以关闭鼠标操作窗体来防止它被聚焦。假设你的窗体叫做 myform:

uses fmx.platform.mac, macapi.appkit;
.
.
Var nswin:nswindow;
.
.
NSWin:= NSWindow(NSWindowFromObjC(FmxHandleToObjC(myform.Handle))); { get the NSWindow }
NSWin.setIgnoresMouseEvents(true);                                 { ignore mouse events }
NSWin.setAcceptsMouseMovedEvents(false);

有一个小问题,它不会停止鼠标右键单击。如果这是一个问题,您将不得不响应表单中的 mousedown 事件并调用主表单 mousedown,这样它就不会丢失鼠标事件。因为向下的鼠标会捕捉到鼠标事件,所以你也需要响应鼠标移动和鼠标向上的事件——将它们转发到你的主窗体。虽然它在右键单击时捕获了鼠标,但是它仍然不能聚焦窗体。

Dave Peters DP 软件

使用带有 NSNonactivatingPanelMask标志的 NSPanel是可能的。Fmx 表单的 NSView 应该成为 NSPanel 的子表单。我编写了一个既适用于 Windows 平台又适用于 Mac 平台的 helper 类(在 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 中。

enter image description here

注意 : XE3中似乎不存在 WindowHandleToPlatform,因此可以用

window := NSWindow(NSWindowFromObjC(FmxHandleToObjC(Form.Handle)));