GetWindowRect coordinates not screen-relative
我正在使用Visual Studio 2008 C ++。我有一个带有控件的MFC对话框。我试图在控件中放置另一个对话框。
第二个对话框上的SetWindowPos()显然是在使用屏幕坐标,因此我需要获取控件或父对话框的屏幕坐标。 MSDN文档说GetWindowRect()提供"相对于显示屏幕左上角的屏幕坐标",但这不是我要的。在控件上,它给出相对于父级的坐标。在父级上,它给出left = 0和top = 0。我也尝试了GetWindowPlacement()中的矩形,它给出了同样的东西。一切都与父母有关。
为什么GetWindowRect()不返回屏幕相对坐标?还有另一种获取方法吗?
我对编程并不陌生,但是对Windows编程,Visual Studio和MFC却不是很陌生,因此我可能会遗漏一些明显的东西。
这是我在OnInitDialog中为父对话框所做的操作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| // TestApp message handlers
BOOL TestApp::OnInitDialog()
{
CDialog::OnInitDialog();
FILE * pFile = fopen("out.txt","w");
CRect winRect;
GetWindowRect(&winRect);
fprintf(pFile,"left=%li top=%li right=%li bottom=%li\
",winRect.left,winRect.top,winRect.right,winRect.bottom); fflush(pFile);
fclose(pFile);
return TRUE; // return TRUE unless you set the focus to a control
} |
运行时,对话框不会出现在屏幕的左上角,但是out.txt包含:
1
| left=0 top=0 right=297 bottom=400 |
-
决不! GetWindowRect永远不会返回任何相对坐标。 您将始终获得屏幕坐标。 向我们显示您的代码以澄清这一点!
-
不用描述,而是显示您的代码。 张贴者多次宣称他们在做"这个和那个",结果发现他们没有做他们所声称的。
-
如果您不熟悉Windows编程,请不要使用需要对Windows API有深入了解的框架(就像MFC一样)。 相反,请先了解Windows API。 它不仅易于学习和理解,而且在效果上更为直接。 学习使用C ++进行Windows编程是一个很好的起点。
在显示对话框之前,框架会调用OnInitDialog。在这一点上,最终大小和位置都不知道:
Windows sends the WM_INITDIALOG message to the dialog box during the Create, CreateIndirect, or DoModal calls, which occur immediately before the dialog box is displayed.
对话框的最终大小和位置是窗口定位协商的结果。发送到该信息可用的对话框的第一条消息是WM_WINDOWPOSCHANGED。使用MFC,可通过CWnd::OnWindowPosChanged处理此消息。可以通过在源自CDialog的类中重写OnWindowPosChanged来实现自定义处理代码。
-
@xMRi:问题中没有任何内容表明该应用程序只希望被通知一次。如果存在该额外要求,我什至可以确定甚至可以解决跨调用存储状态信息的难题。总而言之,这就是对适当答案的低俗解释。
正如在其他答案中所写:
在窗口移至其最终位置之前,将调用OnInitDialog。如果稍后调用GetWindowRect,将会看到它返回正确的坐标。
只需将PostMessage与WM_APP + n消息一起使用。当消息泵运行时,此消息将到达;当窗口定位并显示在屏幕上时,消息将到达。
或使用计时器。这具有相同的效果。
-
向自己发布消息不是解决方案。窗口以严格的FIFO顺序接收已发布的消息。如果过早发布您的消息,它将被过早处理。您必须在系统发布其WM_WINDOWPOSCHANGED消息后立即发布该消息。由于您不知道系统何时运行,因此请回到平方。另一方面,使用计时器会产生非常不同的效果:将低优先级的消息移到消息队列的后面,只有在没有张贴的消息或输入消息可用时,窗口才会接收它们。
-
WM_WINDOWPOSCHANGED与SendMessage一起发送。它不是通过消息队列发送的。因此没有FIFO!使用SendMessage发送的任何消息都将在对话框的消息泵启动之前到达。只需设置一个断点并查看调用堆栈即可!并且由于在消息循环开始之前出现了窗口,所以一切都完成了……
-
@IInspectable:我使用PostMessage WM_APP + n的代码可以正常工作。消息到达时,将设置窗口位置。无需在WM_WINDOWPOSCHANGED中发布此消息!只需在WM_INITDIALOG中进行即可。
-
例如,您的代码停止为决定推迟窗口定位协商的窗口工作,并在第一次收到WM_WINDOWPOSCHANGING消息时退出。您提出的解决方案很复杂,难以理解和记录,并且有随时变得难以维护的趋势。如果要响应窗口位置更改,请在WM_WINDOWPOSCHANGED消息处理程序中进行。就那么简单。
-
:)是的,但这不是问题!问题不是:"一直让我得到真正的窗户……"您还告诉我,我的解决方案根本不起作用。但是确实如此。您还注意到(关于FIFO)不会影响我的解决方案。是的,我的解决方案可能无法在您提到的情况下起作用。以及为什么N#t id难以理解。写一条评论行。好,我们在这里停止讨论...
-
我并没有声称您的解决方案永远无法奏效。我概述了为什么它不能可靠地工作,以及它不必要地难以正确使用以及不必要地难以维护。存在一个干净,可靠的解决方案。
在窗口移至最终位置之前,将调用OnInitDialog。如果稍后调用GetWindowRect,您将看到它返回正确的坐标。
-
我是否可以放置一个OnSomething函数,以便在窗口移至最终位置后立即调用它?我浏览了CWnd成员函数,但无法确定要使用哪个。