Chinaunix首页 | 论坛 | 博客
  • 博客访问: 530642
  • 博文数量: 576
  • 博客积分: 40000
  • 博客等级: 大将
  • 技术积分: 5020
  • 用 户 组: 普通用户
  • 注册时间: 2008-10-13 14:47
文章分类

全部博文(576)

文章存档

2011年(1)

2008年(575)

我的朋友

分类:

2008-10-14 14:51:38

如何实现由列表控件控制的属性表


作者:

关键字:属性页,属性表,MFC,界面

摘要:很多MFC的程序都用到了属性表和属性页来实现选项设置的界面,但是MFC本身提供的属性表页功能有限,界面也很原始,一些新软件都实现了自己定义的更为美观的属性页。MFC原始的属性页是通过CTabCtrl进行切换控制的,本文给出了一种现在较为常见的用CListCtrl进行页面切换的属性页的方法,并且对对列表控件进行了重绘。 CMyPropertySheet是一个从CPropertySheet派生而来的类,因此你仍然可以不费力的利用MFC CPropertySheet的诸多特性,具体使用方法稍后我会详细说明。

该属性表的实现效果如下:


图一

一、使用

  CMyPropertySheet的使用方法与MFC的CPropertySheet类似,首先要在程序中创建两个属性页,也就是两个CPropertyPage的派生对象。然后将MyPropertySheet.cpp 和 MyPropertySheet.h添加至工程,在程序的视图类头文件中(假定是个SDI程序)将CMyPropertySheet的头文件包含进来

#include “MyPropertySheet.h”
  在资源视图里设置一个新的菜单项“选项”(放在哪儿随你) 用ClassWizard添加响应函数,在该函数里添加如下代码创建一个属性表对象myPS
CMyPropertySheet myPS;
然后向属性表添加两个属性页。
myPS.AddPage(&m_page1);
myPS.AddPage(&m_page2);
接下来要添加属性页的图标,该图标会在对应列表项以及属性页的标题上显示,注意这里添加的顺序要与属性页的添加顺序保持一致。
myPS.AddIcon(IDI_GLOBAL);       
myPS.AddIcon(IDI_ADDITION);
最后创建并显示该属性页。
myPS.DoModal();
剩下的工作就跟一般属性表完全一样了。

CMyPropertySheet类提供如下自定义函数,可以对属性表的外观进行设置。

  SetSepratorColor,SetCaptionColor与SetSelectedColor都接受一个类型为COLORREF的参数,分别用以设置列表分隔线,属性页标题以及列表选择项背景的颜色。

SetListFont设置列表的字体。

读者也可以根据自己的需要对其进行扩充。

二、实现逻辑

  MFC原来的属性页是由TabCtrl控制的,而且属性页的大小已经与属性表按比例设置好,因此,要实现如图一所示的属性页,我们有如下几步工作需要做:

1. 对属性页原来的TabCtrl进行隐藏。
2. 调整属性表的大小,将属性页移至属性表右侧,以容纳列表控件。
3. 获得TabCtrl的矩形,根据该矩形画属性页标题。
4. 初始化列表控件内容,调整列表项高度。
5. 响应列表的NM_CLICK事件,根据得到的点击项ID进行属性页的切换。

其中调整尺寸的工作必须在OnInitDialog函数中进行。

BOOL CMyPropertySheet::OnInitDialog()
{
	
	BOOL bResult = CPropertySheet::OnInitDialog();	
 
	//计算属性页的矩形,扩大属性表并将属性页其移至右侧
	CRect rect, rectPage, rectTab;
	GetPage(0)->GetWindowRect(&rectPage);
	
	GetWindowRect(&rect);
	rect.right += 150;
	
    int nWidth = rectPage.Width();
	rectPage.right = rect.right - 20; 
	rectPage.left = rect.right - nWidth;
	ScreenToClient(&rectPage);
	m_rectPage = rectPage;
	MoveWindow(&rect);
	GetPage(0)->MoveWindow(&rectPage);
    
	//隐藏属性页原来的TabControl
	CTabCtrl *pTab = GetTabControl() ;
	pTab->GetWindowRect(&rectTab);
	ScreenToClient(&rectTab);
	if(!pTab->ShowWindow(SW_HIDE))
		return FALSE;	
   
	//创建列表控件并用一个CImageList对象与之关联
	if(!m_wndList.Create(WS_CHILD | WS_VISIBLE | LVS_REPORT | LVS_NOCOLUMNHEADER , 
	            CRect(10 ,rectTab.top,150,rectPage.bottom ),this,0xFFFF))
		return FALSE;
	m_wndList.SetExtendedStyle(LVS_EX_FULLROWSELECT);
	m_wndList.SetImageList(&m_imgList, LVSIL_SMALL);
	
	InitList();

	//设置行高度
	CFont font;
	font.CreatePointFont(240,_T("宋体"));
	m_wndList.SetFont(&font);
	
	CString strCaption;
	GetPage(0)->GetWindowText(strCaption);	
	_tcscpy(m_szCaption, strCaption.GetBuffer(strCaption.GetLength()));	

	return bResult;
}
属性页的切换:
void CMyPropertySheet::OnNMClick(NMHDR *pNMHDR, LRESULT *pResult)
{
	LPNMITEMACTIVATE lpItem = reinterpret_cast(pNMHDR);
	m_nSelectedItem = lpItem->iItem ;

   if (lpItem->iItem  >= 0 && lpItem->iItem < m_wndList.GetItemCount())
   {
	   m_nSelectedItem = lpItem->iItem;
	   CString strCaption = m_wndList.GetItemText(lpItem->iItem,0);
	  _tcscpy(m_szCaption, strCaption);	

	SetActivePage(m_nSelectedItem);
	
	Invalidate();	
	
	GetPage(m_nSelectedItem)->MoveWindow(&m_rectPage);

	m_wndList.SetFocus();
   }
	
}
三、总结

   关于列表控件自绘的问题在这里不做详细讨论,可以参考源代码里面OnNMCustomDraw的部分以及MSDN上的相关资料。对属性页的修改还有很多种方法和很多种方式,比如还可以用树型控件进行控制,这里提供的方法也可以做一般意义上的推广 ,并不难实现其它方式的控制。程序在Visual C++ 2005 下编译通过。
--------------------next---------------------

在当前页,有EDIT变量受最大最小值限制时,当输入的值超出范围,并马上换页时,因为系统检查当前页某变量的最大最小值问题,而出错, 怎么解决这个问题呢,, ( cai_vc++ 发表于 2008-8-2 21:57:00)
 
一个比较大的问题是,属性页是继承CPropertyPage的,而在初始化以及设置活动页时是硬生的MoveWindow到所计算好的位置,这样在切换时有一定的闪烁,不太自然.
还望能改进.
codeproject上有个很好例子,是以CTreeCtrl来做的. ( frog_ma 发表于 2008-5-21 0:31:00)
 
不错,不错。。。。 ( chinaluou 发表于 2008-4-22 16:56:00)
 
能否给个例子,源代码,谢谢!!!!!!!!!!!! ( gaixq 发表于 2008-3-12 17:06:00)
 
我想把该属性表嵌入对话框或CFORMview内,始终不能成功?能否给个例子。谢谢! ( analy 发表于 2008-3-5 9:32:00)
 
.......................................................

--------------------next---------------------

阅读(499) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~