如何在Firemonkey中创build“不激活”窗体

在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变得活跃?

如何在firemonkey中创build“ 不激活 ”窗体?

有可能使用带NSNonactivatingPanelMask标志的NSPanel 。 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是你的主窗体,那么不要把上面的代码放在窗体构造函数中,build议把它放在OnShow中。

在这里输入图像说明

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

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

您可以closures窗体鼠标处理,以防止焦点。 假设你的表单被称为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,以便它不会丢失鼠标事件。 由于鼠标右键将捕获鼠标事件,因此您还需要响应鼠标移动和鼠标移动事件 – 将它们转发到主窗体。 虽然它捕捉鼠标右键单击,它仍然不会集中表单。

戴夫·彼得斯DP软件