2012-10-07 10 views
149

w Xcode dodając te metody do podklasy NSView można zapobiec okno z staje się aktywny po kliknięciu na nim:Jak stworzyć „Nie Activate” formularz w Firemonkey

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

W platformie Windows Stało się przez to prosty kod:

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

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

Jak mogę podklas NSView, aby zapobiec aktywacji TFX FMX po kliknięciu?

Jak utworzyć "Nie aktywować" formularz w firemonkey?

+3

Nie wiem, czy ma ona zastosowanie do Firemonkey, a także, czy też odpowiedzi na swoje pytanie poprawnie, ale możesz chcieć rzucić okiem na ten przykład: http://delphi.about.com/od/delphitips2008/qt/ex_noactivate.htm – TildalWave

+0

Dziękuję, ale jest to tylko dla systemu Windows i łatwiejsze jest moje rozwiązanie opisane powyżej przez "SetWindowLong", Pytanie dotyczy MacOS. –

+0

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

Odpowiedz

13

Jest to możliwe przy użyciu NSPanel z NSNonactivatingPanelMask flagi. NSView formularza fmx powinno stać się potomkiem NSPanel. Pisałem klasy pomocnika, który działa na platformach Windows i Mac (działa na 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. 

wykorzystanie powyższej jednostki:

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

Jeśli frmKeyboard jest głównym Formularz wtedy nie umieść powyższy kod w konstruktorze formularzy, zaleca się umieścić go w programie OnShow.

enter image description here

Uwaga: WindowHandleToPlatform nie wydaje się istnieć w XE3 tak, że linia może być zastąpiony

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

Dzięki za świetne rozwiązanie - Windowhandletoplatform nie wydaje się istnieć w XE3, więc linia może być zastąpiona przez okno: = NSWindow (NSWindowFromObjC (FmxHandleToObjC (Form.Handle))); –

+0

Dzięki, zaktualizowałem swoją odpowiedź. –

2

Można wyłączyć obsługę formularzy za pomocą myszy, aby zapobiec skupieniu. Zakładając, że Twój formularz nazywa się 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); 

Wystąpił niewielki problem polegający na tym, że nie zatrzymuje on kliknięcia prawym przyciskiem myszy. Jeśli to jest problem, będziesz musiał odpowiedzieć na zdarzenie mousedown w formularzu i zadzwonić do głównych formularzy mousedown, aby nie utracić zdarzenia myszy. Ponieważ prawy przycisk myszy będzie przechwytywał zdarzenia myszy, musisz także reagować na ruchy myszy i zdarzenia myszy - przekazując je do głównej postaci. Mimo, że przechwytuje myszą po kliknięciu prawym przyciskiem, nadal nie będzie skupiać się na formularzu.

Software Dave Peters DP

+0

Niepoprawnie, nie działa. Formularz zmienia nacisk klawiatury na kliknięcie. –

+0

Cóż, nie jest skupiony, ale co się dzieje, to, że każde kliknięcie myszy przechodzi przez formularz do tego, co znajduje się pod nim. Jeśli możesz ustawić, że formularz nieostry ma ustawioną właściwość TopMost i tylko pusta część twojego własnego głównego formularza znajduje się poniżej tego poziomu, to zadziała. Jeśli masz jakieś główne elementy sterujące formą pod oknem, to one będą skupiać się po kliknięciu myszą, ponieważ okno nieogniskowane zachowuje się tak, jakby go nie było. Podobnie, jeśli okno zostanie umieszczone nad pulpitem, pulpit zostanie kliknięty myszą, a aplikacja straci ostrość. –

+0

Zauważ, że potrzebuję zdarzeń myszy. Nie mogę ignorować zdarzeń myszy. Chcę kliknąć przycisk, a także chcę mieć animacje firemonkey, gdy wskaźnik myszy znajdzie się na formancie. Załóżmy, że chcę utworzyć wirtualną klawiaturę, pierwsza aplikacja to (na przykład) TextEdit. Po kliknięciu przycisku w formularzu fmx zostanie wygenerowane zdarzenie klawiatury i zostanie wpisana litera. –