2012-10-07 15 views
149

in Xcode con l'aggiunta di questi metodi per sottoclasse NSView può impedire la finestra di diventare attiva quando si fa clic su di esso:Come creare la forma "No Attiva" in FireMonkey

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

In piattaforma Windows E 'fatto da questo codice semplice:

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

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

Come posso sottoclasse NSView per evitare che la mia FMX TForm diventare attivo quando si fa clic su di esso?

Come posso creare "No Attiva" forma in FireMonkey?

+3

Non sono sicuro se si applica a FireMonkey così, o se esso risponde alla tua domanda correttamente, ma potresti dare un'occhiata a questo esempio: http://delphi.about.com/od/delphitips2008/qt/ex_noactivate.htm – TildalWave

+0

Grazie, ma è solo per Windows e il modo più semplice è la mia soluzione descritto sopra da "SetWindowLong", La domanda riguarda MacOS. –

+0

Link: http://stackoverflow.com/questions/9048346/how-embed-a-firemonkey-form-inside-a-control – Devon117

risposta

13

E 'possibile utilizzare NSPanel con NSNonactivatingPanelMask bandiera. NSView del modulo fmx dovrebbe diventare figlio di NSPanel. Ho scritto una classe di supporto che funziona per le piattaforme Windows e Mac (Opere su 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. 

L'utilizzo di unità di cui sopra:

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

Se frmKeyboard è la tua forma principale, quindi non metti sopra il codice nel costruttore del modulo, Si consiglia di inserirlo in OnShow.

enter image description here

Nota: WindowHandleToPlatform non sembra esistere in XE3 modo che la linea può essere sostituito con

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

Grazie per l'ottima soluzione - windowhandletoplatform non sembra esistere in XE3 in modo che la riga possa essere sostituita con window: = NSWindow (NSWindowFromObjC (FmxHandleToObjC (Form.Handle))); –

+0

Grazie, ho aggiornato la mia risposta. –

2

È possibile disattivare la gestione del mouse dei moduli per impedirne la messa a fuoco. Assumendo che il modulo è chiamato 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); 

C'è un piccolo problema nel senso che non si ferma un click destro del mouse. Se questo è un problema, dovrai rispondere all'evento "mouse" nel modulo e chiamare i moduli principali in modo che non perda l'evento del mouse. Poiché il mouse destro in basso acquisirà gli eventi del mouse, dovrai anche rispondere agli eventi di spostamento del mouse e del mouse, inoltrandoli alla tua forma principale. Anche se cattura il mouse con il tasto destro, non focalizzerà comunque il modulo.

Software Dave Peters DP

+0

errato, non funziona. Il modulo cambia il focus della tastiera al clic. –

+0

Beh, non si sta concentrando, ma quello che succede è che qualsiasi clic del mouse passa attraverso il modulo per qualsiasi cosa ci sia sotto. Se è possibile disporre che il modulo non attivo abbia la proprietà TopMost impostata e solo una parte vuota del proprio modulo principale sia mai al di sotto di esso, funzionerà. Se si dispone di controlli di moduli principali sotto la finestra, questi otterranno lo stato attivo quando si fa clic con il mouse mentre la finestra non a fuoco si comporta come se non fosse presente. Allo stesso modo se la finestra viene posizionata sul desktop, il desktop ottiene il clic del mouse e l'applicazione perde lo stato attivo. –

+0

Nota che ho bisogno degli eventi del mouse. Non posso ignorare gli eventi del mouse. Voglio fare clic su un pulsante, inoltre voglio avere animazioni firemonkey quando il puntatore del mouse entra in un controllo. Supponiamo che voglio creare una tastiera virtuale, l'applicazione in primo piano è (per esempio) TextEdit. Quando clicco su un pulsante sul mio modulo fmx, verrà generato un evento tastiera e verrà digitato un carattere. –