【转载】SetWindowPos 详解

函数名:

 

  SetWindowPos

头文件:

  winuser.h

函数原型:

  BOOL SetWindowPos
  (
  HWND hWnd, //窗口句柄
  HWND hWndInsertAfter, //排列顺序的句柄
  int X, //水平坐标
  int Y, //垂直坐标
  int cx, //宽
  int cy, //高
  UINT uFlags //窗口定位标识
  );

说明:

  这个函数能改变窗口的大小、位置和设置子窗口、弹出窗口或顶层窗口的排列顺序。
  返回值:

  BOOL,如果返回值非零表示成功,返回零表示失败。错误信息请参看GetLastError函数。

参数表:

  参数 类型及说明
  hwnd HWND,欲定位的窗口句柄
  hWndInsertAfter HWND,置于hwnd前面的窗口句柄。这个参数必须是窗口的句柄或是下面的值之一:    HWND_BOTTOM 将窗口置于其它所有窗口的底部
  HWND_NOTOPMOST 将窗口置于其它所有窗口的顶部,并位于任何最顶部窗口的后面。如果这个窗口非顶部窗口,这个标记对该窗口并不产生影响
  HWND_TOP 将窗口置于它所有窗口的顶部
  HWND_TOPMOST 将窗口置于其它所有窗口的顶部,并位于任何最顶部窗口的前面。即使这个窗口不是活动窗口,也维持最顶部状态

x: 
 
  int,指定窗口新的X坐标

Y:  

  int,指定窗口新的Y坐标

cx:  

  int,指定窗口新的宽度

cy:  

  int,指定窗口新的高度

wFlags:

  UINT,指定窗口状态和位置的标记。这个参数使用下面值的组合: SWP_DRAWFRAME 围绕窗口画一个框
  SWP_FRAMECHANGED 发送一条WM_NCCALCSIZE消息进入窗口,即使窗口的大小没有发生改变。如果不指定这个参数,消息WM_NCCALCSIZE只有在窗口大小发生改变时才发送
  SWP_HIDEWINDOW 隐藏窗口
  SWP_NOACTIVATE 不激活窗口
  SWP_NOCOPYBITS 屏蔽客户区域
  SWP_NOMOVE 保持当前位置(X和Y参数将被忽略)
  SWP_NOOWNERZORDER 不改变所有窗口的位置和排列顺序
  SWP_NOREDRAW 窗口不自动重画
  SWP_NOREPOSITION 与SWP_NOOWNERZORDER标记相同
  SWP_NOSENDCHANGING 防止这个窗口接受WM_WINDOWPOSCHANGING消息
  SWP_NOSIZE 保持当前大小(cx和cy会被忽略)
  SWP_NOZORDER 保持窗口在列表的当前位置(hWndInsertAfter将被忽略)
  SWP_SHOWWINDOW 显示窗口


备注:

  如果设置了SWP_SHOWWINDOW或SWP_HIDEWINDOW标记,这个窗口不发生移动或改变大小。窗口成为最顶级窗口后,它的所有子窗口也会进入最顶级。一旦将其设为非最顶级,则它的所有子窗口也会转为非最顶级。

相关函数:

  MoveWindow,SetActiveWindow,SetForegroundWindow

例子:

  //设置顶层窗口
  SetWindowPos( Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE||SWP_NOSIZE);

  //取消顶层窗口
  SetWindowPos( Handle, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE||SWP_NOSIZE);

<think>好的,我需要帮助用户在ATL界面中使用SetWindowPos移动控件位置,并提供示例。用户已经提供了一些引用内容,我需要结合这些引用和之前的回答来生成一个合适的解决方案。 首先,用户的问题是关于如何在ATL界面中使用SetWindowPos移动控件位置,并要求示例。根据引用[1]和[2],调整控件大小和位置可以使用MoveWindow或SetWindowPos,而用户之前的问题中已经提到了使用SetWindowPos时需要注意Z序的问题,特别是SWP_NOZORDER标志的重要性,以避免破坏控件组(如Radio按钮的分组)或导致绘制问题。 在之前的回答中,我详细说明了正确使用SetWindowPos的步骤,包括确保窗口样式配置、安全移动控件、处理Radio控件组以及错误规避。现在需要将这些信息整理成一个具体的示例,展示如何在ATL中使用SetWindowPos移动控件。 首先,我需要确认用户可能需要的示例结构。通常,代码示例应包括如何获取控件句柄,然后调用SetWindowPos函数。根据引用[2],拖动效果通常涉及鼠标消息处理,但用户可能只需要基本的移动示例,不需要完整的拖动实现。 引用[4]提到静态使用控件时添加变量和类,这可能涉及到在ATL中如何获取控件句柄。例如,在ATL中,可能需要使用CWindow或GetDlgItem来获取控件的句柄。 此外,用户之前的回答中提到了窗口样式WS_CLIPSIBLINGS的重要性,以避免绘制残留,这应该在示例中体现,比如在窗口创建时设置该样式。 接下来,我需要确保示例代码正确使用SetWindowPos,特别是包含SWP_NOZORDER标志,避免改变Z序。同时,可能需要展示如何处理控件组的移动,如Radio按钮组。 可能的步骤包括: 1. 在ATL窗口中创建控件,例如一个按钮。 2. 在消息处理函数(如按钮点击或定时器)中调用SetWindowPos移动控件。 3. 展示如何正确设置标志(SWP_NOZORDER | SWP_NOSIZE等)。 4. 提供获取控件句柄的方法,如使用CWindow或FindWindowEx。 需要注意,ATL中通常使用CWindow包装句柄,因此示例可能需要展示CWindow的用法,如m_hWnd或GetDlgItem。 另外,用户引用[3]中的OnMouseActivate处理可能与激活有关,但当前问题主要关注移动控件,所以可能不需要涉及这部分,除非移动控件需要在鼠标激活时触发。 最后,确保示例代码符合ATL的结构,例如使用消息映射和处理函数,并在代码注释中解释关键点。 现在需要将这些思考整合成一个清晰的步骤示例,确保代码正确并附有说明,同时引用相关的引用内容。</think>### 在ATL界面中使用`SetWindowPos`移动控件位置的示例 #### 一、核心实现步骤 1. **控件创建与句柄获取** 在ATL窗口中创建控件(如按钮),并通过`GetDlgItem`或`FindWindowEx`获取其句柄。 ```cpp // 窗口类声明中定义控件ID #define IDC_MY_BUTTON 1001 // 创建按钮控件(在OnCreate消息处理中) LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { CWindow wndButton = CreateWindowEx( 0, L"BUTTON", L"点击移动", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 10, 10, 80, 24, // 初始位置和尺寸 m_hWnd, (HMENU)IDC_MY_BUTTON, _Module.GetModuleInstance(), NULL ); return 0; } ``` 2. **安全移动控件的代码示例** 使用`SetWindowPos`时需包含`SWP_NOZORDER`标志,避免破坏Z序[^1][^2]: ```cpp // 在按钮点击消息或定时器中移动控件 LRESULT OnButtonClick(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled) { HWND hButton = GetDlgItem(IDC_MY_BUTTON); // 获取控件句柄 if (hButton) { // 移动控件到新位置(x=50, y=50),保持尺寸和Z序 ::SetWindowPos( hButton, NULL, // 不改变Z序 50, 50, // 新坐标 0, 0, // 尺寸不变(SWP_NOSIZE生效) SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE ); } return 0; } ``` 3. **Radio控件组的特殊处理** 对分组控件需保持Z序连续性,避免破坏互斥逻辑[^1]: ```cpp // 移动Radio控件组时显式指定Z序 HWND hRadio1 = GetDlgItem(IDC_RADIO1); HWND hRadio2 = GetDlgItem(IDC_RADIO2); // 移动Radio2时将其置于Radio1之后 ::SetWindowPos( hRadio2, hRadio1, // 指定Z序参考窗口 100, 20, 80, 24, SWP_NOACTIVATE ); ``` --- #### 二、关键配置与错误规避 | 场景 | 正确配置 | 错误示例 | |--------------------|--------------------------------------------------------------------------|------------------------------| | 移动普通控件 | `SWP_NOZORDER | SWP_NOSIZE` | 漏掉`SWP_NOZORDER`导致Z序错乱 | | 窗口刷新优化 | 在窗口类中启用`WS_CLIPSIBLINGS`样式[^3]:<br>`ModifyStyle(0, WS_CLIPSIBLINGS)` | 未设置样式导致残影 | | 控件句柄获取 | 使用`GetDlgItem`或精确匹配`FindWindowEx`参数[^4] | 错误类名或标题导致句柄获取失败 | --- #### 三、完整流程示例 1. **ATL窗口类定义** ```cpp class CMyWindow : public CWindowImpl<CMyWindow> { public: DECLARE_WND_CLASS_EX(L"MyATLWindow", CS_HREDRAW | CS_VREDRAW, COLOR_WINDOW) BEGIN_MSG_MAP(CMyWindow) MESSAGE_HANDLER(WM_CREATE, OnCreate) COMMAND_ID_HANDLER(IDC_MY_BUTTON, OnButtonClick) END_MSG_MAP() LRESULT OnCreate(...) { /* 创建控件 */ } LRESULT OnButtonClick(...) { /* 移动控件逻辑 */ } }; ``` 2. **动态布局调整(响应窗口大小变化)** ```cpp LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { // 批量移动控件 HDWP hDefer = ::BeginDeferWindowPos(2); hDefer = ::DeferWindowPos( hDefer, GetDlgItem(IDC_BUTTON1), NULL, 10, 10, 0, 0, SWP_NOZORDER | SWP_NOSIZE ); hDefer = ::DeferWindowPos( hDefer, GetDlgItem(IDC_BUTTON2), NULL, 10, 40, 0, 0, SWP_NOZORDER | SWP_NOSIZE ); ::EndDeferWindowPos(hDefer); return 0; } ``` --- #### 四、验证与调试 1. **Z序验证** 使用Spy++工具查看窗口树结构,确认控件Z序未改变。 2. **功能测试** 点击Radio按钮验证互斥性,快速拖动窗口检查是否有残影。 --- ### 相关问题 1. 如何在不破坏互斥性的情况下动态创建ATL Radio控件组? 2. `BeginDeferWindowPos`与直接调用`SetWindowPos`的性能差异有多大? 3. 在ATL中如何处理无句柄的自定义控件的移动? [^1]: 调整控件大小和位置的标准API方法。 [^2]: 拖动效果的实现原理及基础消息处理。 [^3]: 窗口激活时的行为控制。 [^4]: 控件与类的静态关联方法。
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值