Cách tạo hình thức Không kích hoạt biểu mẫu trên mạng trong Firemonkey


147

Trong XCode bằng cách thêm các phương thức này vào lớp con NSView của bạn có thể ngăn cửa sổ hoạt động khi nhấp vào nó:

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

Trong nền tảng Windows Nó được thực hiện bằng mã đơn giản này:

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

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

Làm cách nào tôi có thể phân lớp NSView để ngăn chặn FMX TForm của tôi hoạt động khi nhấp vào nó?

Làm cách nào tôi có thể tạo biểu mẫu " Không kích hoạt " trong Firemonkey ?


3
Không chắc chắn nếu nó cũng áp dụng cho Firemonkey, hoặc nếu nó trả lời đúng câu hỏi của bạn, nhưng bạn có thể muốn xem ví dụ này: delphi.about.com/od/delphitips2008/qt/ex_noactivate.htmlm
TildalWave

Cảm ơn, nhưng nó chỉ dành cho Windows và cách dễ dàng hơn là giải pháp của tôi được mô tả ở trên bởi "SetWindowLong", Câu hỏi là về MacOS.
mh taqia


Devon: Làm thế nào liên kết này có thể giúp tôi?
mh taqia

Cảm ơn WBAR, đây là tiền thưởng thứ hai!
mh taqia

Câu trả lời:


13

Có thể sử dụng NSPanel với cờ NSNonactivatingPanelMask . NSView của dạng fmx sẽ trở thành con của NSPanel. Tôi đã viết một lớp trợ giúp hoạt động cho cả nền tảng Windows và Mac ( Hoạt động trên 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.

Cách sử dụng của đơn vị trên:

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

Nếu frmPal là Biểu mẫu chính của bạn thì không nên đặt mã ở trên vào hàm tạo biểu mẫu, bạn nên đặt nó trong OnShow.

nhập mô tả hình ảnh ở đây

Lưu ý : WindowHandleToPl Platform dường như không tồn tại trong XE3 để dòng đó có thể được thay thế bằng

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

1
Cảm ơn giải pháp tuyệt vời - windowhandletopl platform dường như không tồn tại trong XE3 để dòng đó có thể được thay thế bằng window: = NSWindow (NSWindowFromObjC (FmxHandleToObjC (Form.Handle)));
David Peters

2

Bạn có thể tắt các hình thức xử lý chuột để ngăn chặn nó được tập trung. Giả sử hình thức của bạn được gọi là 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);

Có một vấn đề nhỏ là nó không dừng nhấp chuột phải. Nếu đó là một vấn đề, bạn sẽ phải trả lời sự kiện mousedown trong biểu mẫu và gọi các hình thức chính là mousedown để nó không bị mất sự kiện chuột. Vì chuột phải xuống sau đó sẽ ghi lại các sự kiện chuột, do đó bạn cũng cần phải phản ứng với việc di chuyển chuột và di chuột lên các sự kiện - chuyển tiếp chúng đến biểu mẫu chính của bạn. Mặc dù nó bắt chuột khi nhấp chuột phải, nhưng nó vẫn sẽ không tập trung vào biểu mẫu.

Phần mềm DP của Dave Peters


Không chính xác, không hoạt động. Các hình thức thay đổi tập trung bàn phím vào nhấp chuột.
mh taqia

Vâng, nó không tập trung nhưng điều xảy ra là bất kỳ nhấp chuột nào cũng đi qua biểu mẫu cho đến bất cứ điều gì bên dưới nó. Nếu bạn có thể sắp xếp rằng biểu mẫu không tập trung có tập thuộc tính TopMost và chỉ một phần trống của biểu mẫu chính của bạn nằm bên dưới nó, thì nó sẽ hoạt động. Nếu bạn có bất kỳ điều khiển biểu mẫu chính nào bên dưới cửa sổ thì chúng sẽ lấy nét khi bạn nhấp chuột khi cửa sổ không lấy nét hoạt động như không có ở đó. Tương tự nếu cửa sổ được đặt trên màn hình nền thì máy tính để bàn sẽ nhấp chuột và ứng dụng của bạn mất tiêu điểm.
David Peters

Lưu ý rằng tôi cần các sự kiện chuột. Tôi không thể bỏ qua các sự kiện chuột. Tôi muốn nhấp vào một nút, tôi cũng muốn có hình động Firemonkey khi con trỏ chuột vào điều khiển. Giả sử rằng tôi muốn tạo một bàn phím ảo, ứng dụng nền trước là (ví dụ) TextEdit. Khi tôi nhấp vào nút trên biểu mẫu fmx của mình, một sự kiện bàn phím sẽ được tạo và một ký tự sẽ được nhập.
mh taqia
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.