delphi Firemonkey中的拦截窗口状态、位置等

bqujaahr  于 2023-02-22  发布在  其他
关注(0)|答案(1)|浏览(209)

我考虑到了用户友好性,所以我想截取我打开的每个表单的位置,以便在每次再次打开相同的表单时进行存储和检索。
因为我计划将其移植到Mac,所以我决定使用FireMonkey。
不幸的是,当窗体在屏幕上移动时,没有触发事件。我试图拦截移动时应该触发的消息,但因为没有发生任何事情,我认为Firemonkey窗体不像VCL窗体那样工作。
我使用这个声明:

protected
  procedure WndMethod(var Msg: TMessage); virtual;

并且该方法实现

procedure TMYForm.WndMethod(var Msg : TMessage);
var
  Handled: Boolean;
begin
  // Assume we handle message
  Handled := True;
  case Msg.Msg of
    WM_MOVE : begin
                Edit_X.Text :='x - ' + MYForm.Left.ToString;
                Edit_Y.Text :='y - ' + MYForm.Top.ToString;
              end;
    else
       Handled := False;
  end;
  if Handled then
    // We handled message - record in message result
    Msg.Result := 0
  else
    // We didn't handle message
    // pass to DefWindowProc and record result
    Msg.Result := DefWindowProc(FHWnd, Msg.Msg,
      Msg.WParam, Msg.LParam);
end;

我尝试在屏幕上移动窗体,但没有截获任何事件。我在方法实现的开头放置了一个断点,但直到关闭窗体时才发生任何事情。在本例中,截获了一条消息。
我哪里做错了?

7ivaypg9

7ivaypg91#

首先,你没有覆盖任何预先存在的虚方法,你创建了你自己的虚方法,它没有连接到任何东西,这就是为什么它从来没有被调用。
第二,与VCL不同,FireMonkey * 不会 * 将窗口消息分派给您可以覆盖的虚拟WndProc方法,或者分派给您可能在表单类上定义的任何message处理程序。(在FMX.Platform.Win单元内的私有WndProc()函数中),它们不会公开。任何未处理的消息(包括WM_MOVE)都将被丢弃。
在Windows上在FireMonkey中拦截窗口消息的唯一方法是调用Win32 SetWindowSubclass()SetWindowLongPtr(GWLP_WNDPROC) API,以直接挂钩窗体的底层Win32 HWND(有关详细信息,请参阅MSDN上的Subclassing Controls)。您可以重写窗体的虚拟CreateHandle()方法以调用API。您可以通过调用RTL'的Platform.Win.FormToHWND()函数。
有关此类子类化的示例,请参见How detect the mouse back and forward buttons in a Delphi FMX Windows form?
不用说,使用Win32 API不会移植到MacOS,所以,你必须使用MacOS暴露给钩子窗口的任何特定于平台的API。我不知道这样的API是什么样子的。而且在FMX.Platform.Mac单元中没有像FormToHWND()这样的函数。但是有一个WindowHandleToPlatform()函数,您可以将表单的Handle传递给它。在MacOS上,WindowHandleToPlatform()返回一个TMacWindowHandle对象,该对象包含Wnd: NSWindowView: NSViewHandle: TOCLocal属性,您可以将这些属性用于本机MacOS API。
也就是说,还有一个更好的替代方法--您根本不需要直接挂钩底层平台窗口,您可以使用FireMonkey's Save State特性。在窗体的OnSaveState事件中,根据需要将窗体的当前Left/Top值保存到窗体的SaveState属性中,然后在窗体的OnCreate事件中,如果先前保存了这些值,则可以从SaveState属性恢复这些值。

相关问题