CWnd::SetIcon究竟做了什么事?

本文解析了VC++中对话框程序的图标设置过程,详细解释了`SetIcon`函数的作用及其实现原理,并介绍了如何通过该函数分别设置大图标和小图标。

用VC向导生成的基于对话框的程序中,在对话框的OnInitDialog()函数中,总可以看到如下的代码段:

 

BOOL CXXXDlg::OnInitDialog()
{
     ......
     // Set the icon for this dialog.  The framework does this automatically
     //  when the application's main window is not a dialog
     SetIcon(m_hIcon, TRUE);   // Set big icon
     SetIcon(m_hIcon, FALSE);  // Set small icon
     ......
}

 

那SetIcon究竟做了什么事?为什么需要调用这函数两次?对于此函数,MSDN上的解释说:"Call this member function to set the handle to a specific icon, as identified by hIcon."看了后仍然不甚了了。

 

自己动手,丰衣足食。在SetIcon处设置一个端点,单步进去,看CWnd::SetIcon究竟做了些什么。像其它MFC中的代码一样,CWnd::SetIcon也只是对消息进行了简单的封装。

 

AFXWIN_INLINE HICON CWnd::SetIcon(HICON hIcon, BOOL bBigIcon)
{
    ASSERT(::IsWindow(m_hWnd));
    return (HICON)::SendMessage(m_hWnd, WM_SETICON, bBigIcon, (LPARAM)hIcon);
}

 

哦,原来是向窗口(窗口句柄为m_hWnd)发送了一个WM_SETICON消息,再呼出MSDN,对于这个消息,MSND上有比较详细的解释。如消息名SETICON所揭示的那样,发送这个消息给窗口,是为了让这个窗口和大图标(large icon)或者小图标(small icon)关联。在用户按ALT+TAB键切换窗口时,显示的就是大图标,小图标就是对话框窗口标题栏上的那个图标。

 

同一的参数m_hIcon, 却带有TRUE或者FALSE,这是颇让人感到疑惑的地方。说白了其实也是很简单的事情,我们在用VC的资源编辑器编辑图标(icon)时,不是可以选择不同大小的图片来进行编辑吗?这些大小不同的图,最终都存入到同一个.ico文件中去了。所以m_hIcon指向的是一组图标,第二个参数(TRUE或者FALSE)就是用来指定这一组图标中某一类大小的图标的,参数值为TRUE时,指明使用大图标(32*32相素),FALSE指明使用小图标(16*16像素)。

 

当然,一般程序中我们并没有对WM_SETICON消息进行处理,所以这些设置大小图标的事情,都被默认的消息处理函数DefWindowProc给做掉了。

<think>嗯,用户询问调用CWnd::Invalidate()后的具体执行流程。根据引用[3]的关键描述,结合MFC框架原理,需要分步骤解释这个API触发的连锁反应。 用户应该是MFC开发者,可能遇到了界面刷新问题。ta特意区分了Invalidate和UpdateWindow的区别,说明对消息机制已有基础认知,但需要更底层的执行细节。考虑到ta引用了Attach的示例代码,可能正在处理窗口重绘相关的性能优化。 核心要解答三个层次:1) 消息队列层面发生了什么(WM_PAINT的投递)2) 框架如何响应消息(OnPaint/OnDraw调用链)3) 绘制过程中的关键细节(背景擦除、区域无效化)。特别要注意强调"延迟重绘"这个特性,这是很多开发者困惑的点。 咦,引用[2]里那个CaptureDIB的案例很有参考价值——用户可能在处理图像采集相关的功能,所以对刷新效率敏感。回答时要暗示Invalidate(false)跳过背景擦除可能提升性能,但需谨慎应对闪烁问题。 需要警惕一个易错点:很多人以为调用Invalidate()会立即触发OnDraw,实际必须澄清消息泵的工作机制。可以类比用户点击窗口时的消息产生-分发-处理全流程,但WM_PAINT有特殊合并规则。 最后补充的"最佳实践"段落很重要。观察到用户代码示例里用了Invalidate(false),说明可能有闪烁优化需求,这里可以埋个伏笔:建议用户结合双缓冲技术,不过当前问题不需要展开。 </think>以下是调用 `CWnd::Invalidate()` 后的详细执行流程及注意事项: --- ### **调用 `CWnd::Invalidate()` 后会发生什么?** 1. **标记窗口区域为“无效”** - 函数会将窗口的**整个客户区**(Client Area)标记为需要重绘的状态[^3]。 - 若需仅重绘部分区域,可用 `InvalidateRect()` 指定矩形范围。 2. **向消息队列发送 `WM_PAINT` 消息** - 系统检测到无效区域后,会在**消息队列末尾**添加 `WM_PAINT` 消息[^3]。 - **注意**:由于 `WM_PAINT` 优先级较低,该消息不会立即处理,需等待其他高优先级消息(如鼠标、键盘事件)处理完毕。 3. **触发重绘流程** - 当消息循环处理到 `WM_PAINT` 时,MFC 框架会调用窗口的 `OnPaint()` 函数。 - 在视图类(`CView`)中,`OnPaint()` 默认调用 `OnDraw()` 执行实际绘制逻辑(例如绘制文本、图形)[^3]。 4. **背景擦除控制** - 参数 `bErase = TRUE`(默认值):系统先擦除背景(发送 `WM_ERASEBKGND`),再重绘内容。 - `bErase = FALSE`:保留原有背景,仅重绘新内容(避免闪烁时常用)[^3]。 5. **窗口恢复有效性** - 重绘完成后,系统自动将窗口区域标记为**有效**,直至再次调用 `Invalidate()`。 --- ### **与 `UpdateWindow()` 的关键区别** | **方法** | **行为** | |----------------------|--------------------------------------------------------------------------| | `Invalidate()` | 异步重绘:仅标记区域,`WM_PAINT` 延迟执行(需等待消息队列空闲)[^3]。 | | `UpdateWindow()` | 同步重绘:绕过消息队列,**立即发送 `WM_PAINT`** 强制重绘(可能阻塞当前线程)[^3]。 | > **典型用法**: > ```cpp > Invalidate(); // 标记重绘区域 > UpdateWindow(); // 立即强制执行重绘 > ``` --- ### **注意事项** 1. **频繁调用问题** - 过度调用 `Invalidate()` 会导致 `WM_PAINT` 消息堆积,可能引发界面卡顿。 - **优化方案**:合并多次重绘请求(如用 `InvalidateRect()` 指定局部区域)。 2. **防止死循环** - 在 `OnPaint()` 中调用 `Invalidate()` 会导致无限重绘(需确保有终止条件)。 --- ### **最佳实践场景** ```cpp void CMyView::UpdateDisplay() { Invalidate(FALSE); // 保留背景,仅重绘内容(减少闪烁) // UpdateWindow(); // 若需即时刷新可取消注释 } ``` ---
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值