Firemonkey'de "Etkinleştirme Yok" formu nasıl oluşturulur


147

XCode'da NSView alt sınıfınıza şu yöntemleri ekleyerek, üzerine tıklandığında pencerenin aktif hale gelmesini önleyebilirsiniz:

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

Windows platformunda Bu basit kodla yapılır:

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

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

Üzerine tıkladığımda FMX TForm'umun aktif hale gelmesini önlemek için NSView'ı nasıl alt sınıfa ayırabilirim?

Firemonkey'de " Etkinleştirme Yok " formunu nasıl oluşturabilirim ?


3
Firemonkey için de geçerli olup olmadığından veya sorunuzu doğru bir şekilde yanıtlayıp yanıtlamadığından emin değilim, ancak şu örneğe bir göz atmak isteyebilirsiniz: delphi.about.com/od/delphitips2008/qt/ex_noactivate.htm
TildalWave

Teşekkür ederim, ancak bu sadece Windows için ve daha kolay yol benim yukarıda "SetWindowLong" tarafından açıklanan çözümüm. Soru MacOS ile ilgili.
mh taqia


Devon: Bu bağlantı bana nasıl yardımcı olabilir?
mh taqia

WBAR sayesinde ikinci ödül!
mh taqia

Yanıtlar:


13

Bu kullanarak mümkündür NSPanel ile NSNonactivatingPanelMask bayrak. NSView fmx formunun NSPanel'in alt öğesi olması gerekir. Hem Windows hem de Mac platformları için çalışan bir yardımcı sınıf yazdım ( XE4 üzerinde çalışıyor ):

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.

Yukarıdaki birimin kullanımı:

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

FrmKeyboard Ana Formunuz ise, yukarıdaki kodu form yapıcıya koymayın, OnShow'a koymanız önerilir.

görüntü açıklamasını buraya girin

Not : WindowHandleToPlatform XE3'te mevcut görünmüyor, bu nedenle satır

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

1
Harika çözüm için teşekkürler - windowhandletoplatform XE3'te mevcut görünmüyor, bu nedenle satır, window ile değiştirilebilir: = NSWindow (NSWindowFromObjC (FmxHandleToObjC (Form.Handle)));
David Peters

2

Odaklanmasını önlemek için formların fare işlemesini kapatabilirsiniz. Formunuzun adının myform olduğunu varsayarsak:

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);

Sağ fare tıklamasını durdurmaması nedeniyle küçük bir sorun var. Bu bir sorunsa, formdaki fare indirme olayına yanıt vermeniz ve fare olayını kaybetmemesi için ana formları mousedown çağırmanız gerekir. Sağ fare tuşu daha sonra fare olaylarını yakalayacağından, aynı zamanda fare hareketine ve fare yukarı hareketlerine de yanıt vermeniz gerekir - bunları ana formunuza iletirsiniz. Sağ tıklamada fareyi yakalamasına rağmen, yine de forma odaklanmayacaktır.

Dave Peters DP Yazılımı


Yanlış, çalışmıyor. Form, tıklama üzerine klavye odağını değiştirir.
mh taqia

Odaklanmıyor ama olan şey şu ki, herhangi bir fare tıklaması formdan altındakine gitmesi. Odaklanmayan formun TopMost özellik kümesine sahip olmasını ve kendi ana formunuzun yalnızca boş bir kısmının altındaysa, o zaman çalışacaktır. Pencerenin altında herhangi bir ana form kontrolünüz varsa, odak dışı pencere orada yokmuş gibi davrandığından, fare tıklattığınızda odaklanırlar. Benzer şekilde, pencere masaüstünün üzerine yerleştirilirse, masaüstü fare tıklamasını alır ve uygulamanız odağı kaybeder.
David Peters

Fare olaylarına ihtiyacım olduğunu unutmayın. Fare olaylarını görmezden gelemem. Bir düğmeye tıklamak istiyorum, ayrıca fare işaretçisi bir kontrole girdiğinde firemonkey animasyonlarının olmasını istiyorum. Bir sanal klavye oluşturmak istediğimi varsayalım, ön plan uygulaması (örneğin) TextEdit. Fmx formumdaki bir butona tıkladığımda, bir klavye olayı oluşturulacak ve bir karakter yazılacak.
mh taqia
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.