我考虑到了用户友好性,所以我想截取我打开的每个表单的位置,以便在每次再次打开相同的表单时进行存储和检索。
因为我计划将其移植到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;
我尝试在屏幕上移动窗体,但没有截获任何事件。我在方法实现的开头放置了一个断点,但直到关闭窗体时才发生任何事情。在本例中,截获了一条消息。
我哪里做错了?
1条答案
按热度按时间7ivaypg91#
首先,你没有覆盖任何预先存在的虚方法,你创建了你自己的虚方法,它没有连接到任何东西,这就是为什么它从来没有被调用。
第二,与VCL不同,FireMonkey * 不会 * 将窗口消息分派给您可以覆盖的虚拟
WndProc
方法,或者分派给您可能在表单类上定义的任何message
处理程序。(在FMX.Platform.Win
单元内的私有WndProc()
函数中),它们不会公开。任何未处理的消息(包括WM_MOVE
)都将被丢弃。在Windows上在FireMonkey中拦截窗口消息的唯一方法是调用Win32
SetWindowSubclass()
或SetWindowLongPtr(GWLP_WNDPROC)
API,以直接挂钩窗体的底层Win32HWND
(有关详细信息,请参阅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: NSWindow
、View: NSView
和Handle: TOCLocal
属性,您可以将这些属性用于本机MacOS API。也就是说,还有一个更好的替代方法--您根本不需要直接挂钩底层平台窗口,您可以使用FireMonkey's Save State特性。在窗体的
OnSaveState
事件中,根据需要将窗体的当前Left
/Top
值保存到窗体的SaveState
属性中,然后在窗体的OnCreate
事件中,如果先前保存了这些值,则可以从SaveState
属性恢复这些值。