Firemonkey에서 "No Activate"양식을 만드는 방법


147

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

FMX TForm을 클릭 할 때 활성화되지 않도록 NSView를 서브 클래 싱하려면 어떻게해야합니까?

firemonkey 에서 " No Activate "양식을 어떻게 만들 수 있습니까?


3
Firemonkey에도 적용되는지 또는 질문에 올바르게 대답했는지 확실하지 않지만 다음 예를 살펴보십시오. delphi.about.com/od/delphitips2008/qt/ex_noactivate.htm
— TildalWave

고맙지 만 Windows 전용이며 위의 솔루션이 "SetWindowLong"으로 설명되는 더 쉬운 방법입니다. 문제는 MacOS에 관한 것입니다.
— mh taqia


데본 :이 링크가 어떻게 도움이 될까요?
— mh taqia

WBAR 덕분에 두 번째 현상금입니다!
— mh taqia

답변:


13

NSNonactivatingPanelMask 플래그 와 함께 NSPanel 을 사용할 수 있습니다 . fmx 형식의 NSView는 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)));

1
훌륭한 솔루션에 감사드립니다-windowhandletoplatform이 XE3에 존재하지 않아서 line을 window로 바꿀 수 있습니다. = NSWindow (NSWindowFromObjC (FmxHandleToObjC (Form.Handle)));
— David Peters

2

마우스 핸들링 양식을 해제하여 초점이 맞지 않도록 할 수 있습니다. 양식을 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);

마우스 오른쪽 버튼 클릭을 멈추지 않는 약간의 문제가 있습니다. 그것이 문제라면, 폼에서 mousedown 이벤트에 응답하고 메인 폼 mousedown을 호출하여 마우스 이벤트를 잃지 않도록해야합니다. 오른쪽 마우스 아래로 마우스 이벤트를 캡처하므로 마우스 이동 및 마우스 위로 이벤트에도 응답하여이를 기본 양식으로 전달해야합니다. 마우스 오른쪽 버튼을 클릭하면 마우스를 캡처하지만 여전히 양식에 초점을 맞추지 않습니다.

Dave Peters DP 소프트웨어


잘못되어 작동하지 않습니다. 클릭시 폼이 키보드 포커스를 변경합니다.
— mh taqia

초점이 맞지는 않지만 마우스 클릭은 그 아래에있는 모든 형태로 마우스를 클릭하는 것입니다. 포커스가없는 양식에 TopMost 속성이 설정되어 있고 기본 양식의 빈 부분 만 그 아래에 있으면 정렬 할 수 있습니다. 창 아래에 기본 양식 컨트롤이 있으면 마우스를 클릭 할 때 포커스가없는 창이없는 것처럼 동작하므로 포커스를 얻습니다. 마찬가지로 창을 바탕 화면 위에 놓으면 바탕 화면에 마우스 클릭이 발생하고 응용 프로그램의 포커스가 사라집니다.
— David Peters

마우스 이벤트가 필요합니다. 마우스 이벤트를 무시할 수 없습니다. 버튼을 클릭하고 마우스 포인터가 컨트롤에 들어갈 때 firemonkey 애니메이션을 원합니다. 가상 키보드를 만들고 싶다고 가정하면 전경 응용 프로그램은 (예 : TextEdit)입니다. fmx 양식에서 버튼을 클릭하면 키보드 이벤트가 생성되고 문자가 입력됩니다.
— mh taqia
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.