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.