2012-10-07 4 views
149

で「いいえ活性化する」フォームを作成するには:それは、このことによって行われ、Windowsプラットフォームではどのようにそれをクリックしたときにアクティブになるのウィンドウを防ぐことができ、あなたのNSViewのサブクラスにこれらのメソッドを追加することによって、XcodeでFireMonkeyの

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

単純なコード:

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のに "ノーアクティブ" フォームを作成することができますか?

+3

わからないと交換することができるので、XE3には存在していないようです問題は適切ですが、この例を見てみるといいかもしれません:http://delphi.about.com/od/delphitips2008/qt/ex_noactivate.htm – TildalWave

+0

ありがとうございますが、それはWindows用であり、より簡単な方法は私の解決策です上記の "SetWindowLong"で説明したように、質問はMacOSに関するものです。 –

+0

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

答えて

13

それは、NSNonactivatingPanelMaskフラグでNSPanelを使用して可能です。 fmx形式のNSViewはNSPanelの子になります。上記ユニットの

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は、あなたのメインフォームでない場合、私は、WindowsとMacの両方のプラットフォームで動作するヘルパークラス(XE4上作品を)書かれていますフォームコンストラクタに上記のコードを入れて、それをOnShowに入れることをお勧めします。

enter image description here

:WindowHandleToPlatformはそれは同様FireMonkeyのために適用された場合、またはそれはあなたに答えるならば、その行は

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

素晴らしいソリューションをありがとう - windowhandletoplatformは、XE3に存在しないように見えるので、ウィンドウは次のように置き換えられます:NSWindow(NSWindowFromObjC(FmxHandleToObjC(Form.Handle))); –

+0

ありがとう、私は私の答えを更新しました。 –

2

フォームマウスの操作をオフにして、フォーカスしないようにすることができます。あなたのフォームがmyformと呼ばれると仮定すると、右クリックを止めないという点でわずかな問題があります。それが問題であれば、フォームのmousedownイベントに応答し、マウスのイベントを失うことがないように、メインフォームmousedownを呼び出す必要があります。右マウスを押し下げるとマウスイベントがキャプチャされるので、マウスの移動やマウスアップイベントにも応答する必要があります。これをメインフォームに転送します。右クリックでマウスをキャプチャしても、フォームにはまだフォーカスが当てられません。

デイブ・ピーターズ DPソフトウェア

+0

正しくない、動作しません。フォームはクリック時にキーボードフォーカスを変更します。 –

+0

まあ、それはフォーカスを取得していないが、何が起こるかは、マウスのクリックは、その下にあるものにフォームを通過するということです。非フォーカスフォームにTopMostプロパティが設定されていて、メインフォームの空白部分のみがその下にある場合は、動作します。ウィンドウの下にメインのフォームコントロールがある場合は、フォーカスしていないウィンドウがマウスのように振る舞うようにマウスをクリックするとフォーカスが得られます。同様に、ウィンドウがデスクトップ上に置かれている場合、デスクトップはマウスのクリックを取得し、アプリケーションはフォーカスを失います。 –

+0

私はマウスイベントが必要であることに注意してください。私はマウスイベントを無視することはできません。私はボタンをクリックしたい、マウスポインタがコントロールに入るとfiremonkeyのアニメーションを持たせたい。私は仮想キーボードを作成したいと仮定し、フォアグラウンドアプリケーションは(例えば)TextEditです。 fmxフォームのボタンをクリックすると、キーボードイベントが生成され、文字が入力されます。 –

関連する問題