GetWindowRect坐标不是屏幕相对的

问题描述:

我在Visual Studio 2008 C++中工作。我有一个MFC对话框,里面有一个控件。我正试图在控件中放置另一个对话框。GetWindowRect坐标不是屏幕相对的

SetWindowPos()在第二个对话框上清楚地使用了屏幕坐标,所以我需要获取控件的屏幕坐标或父对话框。 MSDN文档说GetWindowRect()提供了“屏幕坐标相对于显示屏幕的左上角”,但这不是我所得到的。在控件上,它给出了相对于父项的坐标。在父项上,它给出了left = 0和top = 0。我也尝试了GetWindowPlacement()中的矩形,它给出了同样的事情。一切都与父母有关。

为什么GetWindowRect()不返回屏幕相对坐标?有没有另一种方法来获得他们?我不是新的编程,但对于Windows编程,Visual Studio和MFC来说是相当新颖的,所以我可能会错过某些明显的东西。

这是我在OnInitDialog正在做父对话框:

// 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\n",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包含:

left=0 top=0 right=297 bottom=400 
+0

从来没有! GetWindowRect永远不会返回任何相对坐标。你总是得到屏幕坐标。告诉我们你的代码来澄清这一点! – xMRi 2014-10-06 16:20:17

+0

而不是描述,显示你的代码。海报宣称他们在做“这个和那个”的次数太多了,结果他们没有做他们自称的东西。 – PaulMcKenzie 2014-10-06 16:21:09

+0

如果您不熟悉Windows编程,请不要使用需要熟悉Windows API的框架(如MFC)。相反,首先要了解Windows API。这既容易学习和理解,也容易直接影响。 [学习使用C++编程Windows](http://msdn.microsoft.com/en-us/library/windows/desktop/ff381399.aspx)是一个很好的起点。 – IInspectable 2014-10-06 16:24:03

写在对方的回答:

的OnInitDialog被称为前的窗口移动到其最终位置。如果稍后调用GetWindowRect,则会看到它返回适当的坐标。

只需使用带有WM_APP + n消息的PostMessage即可。该消息将在消息泵运行时到达,并且消息将在窗口定位并显示在屏幕上时到达。

或使用计时器。这具有相同的效果。

+0

向您发布消息不是解决方案。发布的消息以严格的FIFO顺序由窗口接收。如果您发布信息太早,将会过早处理。您必须在系统发布其“WM_WINDOWPOSCHANGED”消息后立即发布消息。既然你不知道系统何时做,你就回到原点。另一方面,使用定时器具有非常不同的效果:低优先级消息被移动到消息队列的后面,并且只有在没有可用的发布消息或输入消息时,窗口才会收到它们。 – IInspectable 2014-10-07 13:07:10

+0

WM_WINDOWPOSCHANGED与SendMessage一起发送。它不通过消息队列发送。所以没有先入先出!任何使用SendMessage发送的消息都将在对话框的消息泵启动之前到达。只需设置一个断点并查看调用堆栈!并且因为窗口在消息循环开始之前显示,所有事情都完成了...... – xMRi 2014-10-07 19:45:08

+0

@IInspectable:使用PostMessage WM_APP + n的代码完美地工作。窗口位置在消息到达时设置。没有必要在WM_WINDOWPOSCHANGED中发布此消息!在WM_INITDIALOG中完成它就足够了。 – xMRi 2014-10-08 06:51:21

OnInitDialog在之前被称为窗口被移动到其最终位置。如果您稍后致电GetWindowRect,则会看到它返回适当的坐标。

+0

是否有一个OnSomething函数,我可以把它放在窗口移动到最终位置后立即调用它?我查看了CWnd的成员函数,但我不知道要使用哪一个。 – blippi 2014-10-06 17:32:39

OnInitDialog在显示对话框之前由框架调用。在这点上,既没有最终尺寸也不位置是已知的:

视窗期间CreateCreateIndirect,或DoModal呼叫时,显示对话框之前其立即发生发送WM_INITDIALOG消息到对话框。

对话框的最终大小和位置是窗口定位协商的结果。发送到可用信息的对话框的第一条消息是WM_WINDOWPOSCHANGED。使用MFC,此消息通过CWnd::OnWindowPosChanged处理。自定义处理代码可以通过在您的CDialog派生类中重写OnWindowPosChanged来实现。

+0

这里的缺点是您不止一次收到该消息... – xMRi 2014-10-08 06:52:01

+0

@xMRi:问题中没有提到应用程序只需要通知一次。如果存在额外的需求,我相信你甚至可以解决跨呼叫存储状态信息的挑战。总而言之,这是一个相当蹩脚的解释,用于解决一个合适的答案。 – IInspectable 2014-10-08 10:52:07