网上看了一些资料,对于MFC显示位置坐标等说明文档主要是讨论GetWindowRect()与GetClientRect(),由于最近修改公司项目上的一些小问题是遇到相关内容,因此记录一下便于以后查找。感觉网友们形容的已经很详细了,所以在这参考一些MSDN上的说明和网友博客中的一些内容,并小小的测试几个细节问题。
对于GetWindowRect()解释在MSDN上写的非常明白:
This function retrieves the dimensions of the bounding rectangle of the specified window. The dimensions are given in screen coordinates that are relative to the upper-left corner of the screen.
给函数获取窗口边框位置尺寸,且提供的信息是相对屏幕左上角位置。
对于GetClientRect()函数,也有相应解释,清晰明了:
Retrieves the coordinates of a window's client area. The client coordinates specify the upper-left and lower-right corners of the client area. Because client coordinates are relative to the upper-left corner of a window's client area, the coordinates of the upper-left corner are (0,0).
获取用户区域位置尺寸,最后一句已经写清楚得到位置坐标即为左上角坐标值为(0,0)。
下面进行一个非常简单而又草率的测试。
我用this和IDC_STATIC控件(随便拖了个Picture Control进去)分别调用两种方法,当我的主窗口11111在随机位置时,得到结果如下:
这个已经非常简单明了了吧,完全符合说明文档字面意思,要说明的一点是有位老铁在博客中说一个没有父类的窗口调用GetWindowRect()后会显示位置坐标为(0,0),调用某控件时才会出现相对屏幕左上角位置的坐标值。再次我只想问一句这位老铁你是不是把窗口给最大化,或对齐到了屏幕左上角后进行的测试。。。在那种情况下时你的主窗口位置与屏幕左上角坐标重合导致的坐标(0,0)。
顺便再提一句ScreenToClient() 就是把屏幕坐标系下的RECT坐标转换为客户区坐标系下的RECT坐标,其实通俗点说我们调用GetWindowRect()后再调用ScreenToClient()的效果和直接使用GetClientRect()没什么区别,但通过调用两个方法实现提供的信息是多于只使用GetClientRect()的,因此也要根据具体情况安排。
当然ClientToScreen()方法的使用和ScreenToClient()的使用方法没什么区别,根据字面意思也很好理解。
其实我想记录的主要问题是关于使用SetWindowPos()方法操作一些窗口的显示顺序。因为最近工程上的一些小bug,简单来说就是我的pc端程序线程比较复杂,功能端交互和显示界面比较多,且需要和设备A(Linux环境)端进行通信,设备A还要去驱动另一个带有工业相机和操作板的设备B。维护程序时发现正常操作设备B控制PC端的某些功能界面端显示正常,一旦我将程序最小化隐藏后,再通过设备B的按键响应操作PC端程序就会在UI显示上出现一些异常。由于属于小问题,而我又懒得去解析CWnd::OnSysCommand()方法,因此只考虑在恢复程序界面前端显示时重置一下需求界面的位置顺序。这里要使用SetWindowPos()方法来实现,可以参考以下函数:
BOOL SetWindowPos(
HWND hWnd,
HWND hWndInsertAfter,
int X,
int Y,
int cx,
int cy,
UINT uFlags
);
在MSDN中只找到上述引用,而在MFC中我们常使用:
BOOL SetWindowPos(HWND hWndlnsertAfter, int X,int Y,int cX,int cY,UNIT Flags);
下面搬运一些简单说明和操作方便以后使用:
hWndInsertAfter
Type: HWND
A handle to the window to precede the positioned window in the Z order. This parameter must be a window handle or one of the following values.
其中的X,Y,Cx,Cy解释为:The new position of the left /top side of the window, in client coordinates. and The new width/height of the window, in pixels.
uFlags
Type: UINT
The window sizing and positioning flags. This parameter can be a combination of the following values.
Value Meaning SWP_ASYNCWINDOWPOS
0x4000
If the calling thread and the thread that owns the window are attached to different input queues, the system posts the request to the thread that owns the window. This prevents the calling thread from blocking its execution while other threads process the request.
如果调用进程不拥有窗口,系统会向拥有窗口的线程发出需求。这就防止调用线程在其他线程处理需求的时候发生死锁。
SWP_DEFERERASE
0x2000
Prevents generation of the WM_SYNCPAINT message.
防止产生WM_SYNCPAINT消息。
SWP_DRAWFRAME
0x0020
Draws a frame (defined in the window's class description) around the window.
在窗口周围画一个边框(定义在窗口类描述中)。
SWP_FRAMECHANGED
0x0020
Applies new frame styles set using the SetWindowLong function. Sends a WM_NCCALCSIZE message to the window, even if the window's size is not being changed. If this flag is not specified, WM_NCCALCSIZE is sent only when the window's size is being changed.
给窗口发送WM_NCCALCSIZE消息,即使窗口尺寸没有改变也会发送该消息。如果未指定这个标志,只有在改变了窗口尺寸时才发送WM_NCCALCSIZE。
SWP_HIDEWINDOW
0x0080
Hides the window.
隐藏窗口。
SWP_NOACTIVATE
0x0010
Does not activate the window. If this flag is not set, the window is activated and moved to the top of either the topmost or non-topmost group (depending on the setting of the hWndInsertAfter parameter).
不激活窗口。如果未设置标志,则窗口被激活,并被设置到其他最高级窗口或非最高级组的顶部(根据参数hWndlnsertAfter设置)。
SWP_NOCOPYBITS
0x0100
Discards the entire contents of the client area. If this flag is not specified, the valid contents of the client area are saved and copied back into the client area after the window is sized or repositioned.
清除客户区的所有内容。如果未设置该标志,客户区的有效内容被保存并且在窗口尺寸更新和重定位后拷贝回客户区。
SWP_NOMOVE
0x0002
Retains the current position (ignores X and Y parameters).
维持当前位置(忽略X和Y参数)。
SWP_NOOWNERZORDER
0x0200
Does not change the owner window's position in the Z order.
不改变z序中的所有者窗口的位置。
SWP_NOREDRAW
0x0008
Does not redraw changes. If this flag is set, no repainting of any kind occurs. This applies to the client area, the nonclient area (including the title bar and scroll bars), and any part of the parent window uncovered as a result of the window being moved. When this flag is set, the application must explicitly invalidate or redraw any parts of the window and parent window that need redrawing.
不重画改变的内容。如果设置了这个标志,则不发生任何重画动作。适用于客户区和非客户区(包括标题栏和滚动条)和任何由于窗回移动而露出的父窗口的所有部分。如果设置了这个标志,应用程序必须明确地使窗口无效并区重画窗口的任何部分和父窗口需要重画的部分。
SWP_NOREPOSITION
0x0200
Same as the SWP_NOOWNERZORDER flag.
与SWP_NOOWNERZORDER标志相同。
SWP_NOSENDCHANGING
0x0400
Prevents the window from receiving the WM_WINDOWPOSCHANGING message.
防止窗口接收WM_WINDOWPOSCHANGING消息。
SWP_NOSIZE
0x0001
Retains the current size (ignores the cx and cy parameters).
维持当前尺寸(忽略cx和Cy参数)。
SWP_NOZORDER
0x0004
Retains the current Z order (ignores the hWndInsertAfter parameter).
维持当前Z序(忽略hWndlnsertAfter参数)。
SWP_SHOWWINDOW
0x0040
Displays the window.
显示窗口。
至此通过恢复主程序窗口时进行一下相应的刷新就能解决显示异常的问题,虽然工作做得比较草率,但本文重点是还是记录一下关于日常使用MFC窗口显示的一些Tips。方便与大家交流和日后自己回顾和完善修改。
参考文章:https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setwindowpos
https://www.cnblogs.com/canger/p/5869173.html?utm_source=itdadao&utm_medium=referral
https://www.cnblogs.com/wb-DarkHorse/archive/2013/07/08/3178201.html