OutLook_Bar风格CMFCPropertySheet无法修改标签位图问题求助
问题根因
CMFCPropertySheet::SetIconsList设计上仅允许初始化阶段调用1次,内部通过ENSURE(m_Icons.GetSafeHandle()==NULL)强制校验,重复调用必然触发断言失败- 原有代码手动调用
CBitmap析构函数属于严重错误,栈分配的CBitmap对象不能手动触发析构,会导致内存损坏、重复释放等未定义行为,应该调用CBitmap::DeleteObject()释放资源
可行解决方案
方案1:预加载所有图标,切换标签时动态修改标签图标索引(最稳定,推荐)
不需要反复重建ImageList,完全规避重复调用SetIconsList的问题,性能和兼容性最优。
实现步骤:
- 初始化阶段(属性表
OnInitDialog回调中)一次性加载全部6张位图到ImageList,仅调用一次SetIconsList完成赋值 - 切换标签时调用
CMFCPropertySheet::SetPageIcon方法修改对应页面的图标索引即可
代码示例:
// AppPropSheet的OnInitDialog中执行初始化 BOOL AppPropSheet::OnInitDialog() { CMFCPropertySheet::OnInitDialog(); // 一次性加载全部6张位图到ImageList m_shtAllImages.Create(81, 81, ILC_COLOR24|ILC_MASK, 6, 1); m_shtAllImages.Add(LoadBitmap(IDB_BITMAP77), RGB(128,128,128)); // 页0未选中态图标 m_shtAllImages.Add(LoadBitmap(IDB_BITMAP86), RGB(128,128,128)); // 页0选中态图标 m_shtAllImages.Add(LoadBitmap(IDB_BITMAP81), RGB(128,128,128)); // 页1未选中态图标 m_shtAllImages.Add(LoadBitmap(IDB_BITMAP87), RGB(128,128,128)); // 页1选中态图标 m_shtAllImages.Add(LoadBitmap(IDB_BITMAP79), RGB(128,128,128)); // 页2未选中态图标 m_shtAllImages.Add(LoadBitmap(IDB_BITMAP88), RGB(128,128,128)); // 页2选中态图标 // 全局仅调用一次SetIconsList SetIconsList(m_shtAllImages); // 初始状态所有页设为未选中图标 SetPageIcon(0, 0); SetPageIcon(1, 2); SetPageIcon(2, 4); return TRUE; } // 切换标签时调用该方法即可 void AppPropSheet::ChangeImgList(int sel) { // 所有页重置为未选中态图标 SetPageIcon(0, 0); SetPageIcon(1, 2); SetPageIcon(2, 4); // 当前选中页切换为选中态图标 SetPageIcon(sel, sel*2 + 1); }
方案2:绕过单次调用限制(不推荐,依赖MFC内部实现)
如果必须沿用原有重建ImageList的逻辑,可以通过子类化释放内部m_Icons成员绕过断言校验
实现步骤:
- 在AppPropSheet类中新增
ResetIconsList成员函数,释放框架内部持有的ImageList - 替换原有手动调用CBitmap析构的逻辑,改用
DeleteObject释放资源 - 每次调用
SetIconsList前先执行ResetIconsList
代码示例:
// 先在AppPropSheet头文件中声明该成员函数,用于释放内部ImageList void AppPropSheet::ResetIconsList() { m_Icons.DeleteImageList(); } // 修改后的ChangeImgList函数 void AppPropSheet::ChangeImgList(int sel) { static bool firsttime = true; int retval; if(!firsttime) { for(int i=0;i<3;i++) m_bmpimgs[i].DeleteObject(); // 正确释放位图资源 m_shtSelImages.DeleteImageList(); ResetIconsList(); // 释放内部旧ImageList,使断言通过 } if (sel == 0) m_bmpimgs[0].LoadBitmapA(IDB_BITMAP86); else m_bmpimgs[0].LoadBitmapA(IDB_BITMAP77); if (sel == 1) m_bmpimgs[1].LoadBitmapA(IDB_BITMAP87); else m_bmpimgs[1].LoadBitmapA(IDB_BITMAP81); if (sel == 2) m_bmpimgs[2].LoadBitmapA(IDB_BITMAP88); else m_bmpimgs[2].LoadBitmapA(IDB_BITMAP79); retval = m_shtSelImages.Create(81, 81, ILC_COLOR24|ILC_MASK , 1, 1); retval = m_shtSelImages.Add(&m_bmpimgs[0], RGB(128, 128, 128)); retval = m_shtSelImages.Add(&m_bmpimgs[1], RGB(128, 128, 128)); retval = m_shtSelImages.Add(&m_bmpimgs[2], RGB(128, 128, 128)); SetIconsList(m_shtSelImages.m_hImageList); firsttime = false; }
内容的提问来源于stack exchange,提问作者ramesh_deekonda
相关产品推荐
相关产品推荐

