为MFC控件ListCtrl添加背景图

来源:互联网 发布:网络被骗怎么把钱追回 编辑:程序博客网 时间:2024/05/15 01:17

      今天碰到个客户硬跟我拗要把登录界面上的Report类型的ListCtrl改成Icon型还要给登录界面也贴图,于是研究了下ListCtrl,放图标这些都很好解决,做到最后发现全部贴了图的界面上放一个默认背景的ListCtrl很是突兀,于是准备给ListCtrl也上个背景图,google一番后发现这并非是个简单的问题。从google的结果来看,基本是用DrawItem的方式来做,但是这种方式看了下代码量实在太大(虽然可以直接复制粘贴),然后是在VCKBASE看到一个ListBox的上背景图方法,这种方法相对简单,但试了下发现贴背景图后的图标放上去后会在图标周围及文字周围有块难看的白色。于是花了点时间把这些问题都解决了。下面贴出方法。

1、还是要子类化,所以首先是自己定义一个从CListCtrl继承而来的CImageListCtrl类(后来意识到这个名字很不好,因为有CImageList)。

2、加入成员CBitmap m_bmpBkImage,设置方法SetBkImage(CString strImagePath),用来载入背景图。这个方法很简单,只是普通的载入,然后设置一个标志在重画的时候使用这个位图做bitblt

int CImageListCtrl::SetBkImage(CString strImagePath)
{
 HBITMAP hBitmap = (HBITMAP)::LoadImage(AfxGetInstanceHandle(),strImagePath.GetBuffer(0),IMAGE_BITMAP,0,0,LR_LOADFROMFILE | LR_CREATEDIBSECTION);
 m_bmpBkImage.Attach(hBitmap);
 m_bLoaded = TRUE;
 Invalidate();
 return 0;
}

3、处理ON_WM_ERASEBKGND消息,bitblt背景图

BOOL CImageListCtrl::OnEraseBkgnd(CDC* pDC)
{
 // TODO: 在此添加消息处理程序代码和/或调用默认值
 if (m_bLoaded)
 {
  BITMAP bmp;
  m_bmpBkImage.GetBitmap(&bmp);

  CRect rcClient;
  GetClientRect(&rcClient);

  CDC dcMem;
  dcMem.CreateCompatibleDC(pDC);
  dcMem.SelectObject(m_bmpBkImage);
  pDC->SetStretchBltMode(COLORONCOLOR);
  pDC->StretchBlt(0,0,rcClient.Width(),rcClient.Height(),&dcMem,0,0,bmp.bmWidth,bmp.bmHeight,SRCCOPY);
 }

 return TRUE;
}

千万注意返回值,把默认的调用基类方法去掉,否则只会看到你的图一闪而过。

4、这个时候背景图已经看见了,问题是图标和字下面都有膏药一样的一块。怎么解决?试了好久,处理WM_CTLCOLOR消息是不行的。但是偶然之中试到了这个方法是可行的:主对话框会使用这个类,在InitDialog的时候调用这两个方法

//CImageListCtrl m_ctlList

m_ctlList.SetBkColor(CLR_NONE);
m_ctlList.SetTextColor(CLR_NONE);

这样,膏药就不见了。

5、这个时候以为大功告成了,其实还有问题,比如说,图标一多出滚动条的时候一滚动背景图不刷新。然后是图标之间选择是没有问题,一旦图标失去焦点,又没有刷新。

针对第一个问题,处理在CImageListCtrl当中处理WM_HSCROLL和WM_VSCROLL消息,做Invalide刷新。

第二个问题,在CImageListCtrl处理LVN_ITEMCHANGED消息,也是Invalide刷新,但是由于会触发这个消息的情况太多,于是我们做个筛选,条件是当前选中项为空。具体代码如下

void CImageListCtrl::OnLvnItemchanged(NMHDR *pNMHDR, LRESULT *pResult)
{
 LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
 // TODO: 在此添加控件通知处理程序代码

 POSITION pos = GetFirstSelectedItemPosition();
 if (pos == NULL)
  Invalidate();

 *pResult = 0;
}

 

     好了,到这里基本上就完成了。然后顺带解决一个关于图标的问题,如果你使用的是旧式的图标(也就是颜色较少的WIN2K/98用的那种)就没问题,如果你用了一个真彩的XP中的图标就会发现图标周围有些黑色的东西,看MSDN上说想要支持更多色彩的图标只要在CImageList对象Create时使用标志ILC_COLOR24或者ILC_COLOR32这些,后面的数字表示图标的颜色位数,24表示24位彩色。实际试下来还是不行,百思不得其解的时候手痒试了下把应用程序界面改成xp的样式,结果这个问题就解决了。VS2005(2003也一样)下把应用程序改成XP样式的方法是这样的:

首先,建立这样的一个文件

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
     <assemblyIdentity name="XP style manifest" processorArchitecture="x86" version="1.0.0.0" type="win32"></assemblyIdentity>
     <dependency>
         <dependentAssembly>
             <assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="x86" publicKeyToken="6595b64144ccf1df" language="*"></assemblyIdentity>
         </dependentAssembly>
     </dependency>
</assembly>

另存为xpstyle.manifest

然后,编译器打开项目属性-清单工具-输入和输出,在附加清单文件的地方填好xpstyle.manifest然后重新编译即可。

 

好了,ListCtrl设置背景图大概就是这么些,CSDN不知道怎么贴图,所以就不贴了。需要源码的可以发信给phil2360@gmail.com我会给你发去的。

原创粉丝点击