Как создать форму "нет активации" в 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 становится активным при нажатии на него?
Как я могу создать "Не Активировать" в firemonkey?
2 ответа:
можно использовать NSPanel С NSNonactivatingPanelMask флаг. NSView формы fmx должен стать дочерним элементом 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.
Примечание: WindowHandleToPlatform, кажется, не существует в XE3, так что строка может быть заменена на
window := NSWindow(NSWindowFromObjC(FmxHandleToObjC(Form.Handle)));
вы можете отключить обработку форм мышью, чтобы предотвратить ее фокусировку. Предполагая, что ваша форма называется ссылки:
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, чтобы он не потерял событие мыши. Поскольку правая мышь вниз будет захватывать события мыши, вам также нужно реагировать на перемещение мыши и события мыши вверх тоже - пересылка их в основную форму. Хотя он захватывает мышь при щелчке правой кнопкой мыши, он все равно не будет фокусировать форму.
Дейв Питерс Программное обеспечение ДП