经常能在论坛上见人问tab控件应该如何使用,总是有很多网友热心的解答。回想起自己初学MFC的时候对于这个问题也是比较纠结,也曾到处查找资料和范例。想想初学时总希望什么事情都可以轻松实现,加一个tab控件就想直接实现界面切换的功能,看到网上介绍要自己创建对话框按非模态方式调用通过tab切换自己还认为这种方法有问题,把简单问题复杂化了。呵呵,现在想想自己当时太可笑了,如今看来做程序设计不要追求简单易行,而应该更多的考虑合理规范。
好了,闲言少叙切入正题。tab控件其实只是提供了一组标签按钮,其相互切换有响应的消息,而且实现了对这些按钮管理的功能。至于通过这些标签按钮来管理我们自己的界面那就要我们通过其提供的各种方法自己实现了,这一方面减轻了tab控件自身的设计压力,另一方面也为开发者提供了很大的灵活性和自主性,想来应该是较为合理的。
在网络盛行、资源共享的时代,我们遇到问题第一个反应就是上网看看有没有成熟的解决方案或可用示例可供参考,至少我是这样。所以在tab控件的使用上我也是参考了一些例子,选择了一个自己认比较不错的加以改进和使用,今天就把自己现在使用的方法拿出来与大家分享一下,希望能对不了解tab控件使用的朋友有所帮助。
按着面向对象的思想,我们应该在MFC原有CTabCtrl的基础上加以继承来扩展其功能,同时封装我们扩展出的新功能以方便今后使用,基于这种考虑我创建了CTabPage,而且制作了一个使用CTabPage的例子,这个例子中做了三个简单的对话框实现了通过tab控件实现了界面切换。具体到CTabPage其实很简单,其定义如下
class CTabPage : public CTabCtrl
{
DECLARE_DYNAMIC(CTabPage)
int m_nPageCount; //页数
public:
CTabPage();
virtual ~CTabPage();
void AddPage(CWnd* pPageWnd, LPTSTR lpTitle); //添加选项卡
void ShowCurPage(UINT nShowState); //显示当前页面
public:
afx_msg void OnTcnSelchanging(NMHDR *pNMHDR, LRESULT *pResult);
afx_msg void OnTcnSelchange(NMHDR *pNMHDR, LRESULT *pResult);
DECLARE_MESSAGE_MAP()
};
其中OnTcnSelchanging和OnTcnSelchange是通过向导添加的消息函数,也是实现界面切换的关键。这两个函数在执行顺序上是OnTcnSelchanging先执行而OnTcnSelchange后执行,而且在OnTcnSelchanging执行时tab的当前选中的item没有完成切换,而在OnTcnSelchange执行时tab控件就以完成当前选中item的切换。知道了这个原理我们就可以在OnTcnSelchanging中隐藏先前选中的页面而在OnTcnSelchange显示当前选择了的页面了。而显示和隐藏页面的操作是通过自定义函数ShowCurPage完成的。看到这相信大家就会有一个疑问,我们怎么获取tab控件所管理的页面的指针或句柄呢?解决这个问题就不得不说一个结构:
typedef struct tagTCITEMW
{
UINT mask;
#if (_WIN32_IE >= 0x0300)
DWORD dwState;
DWORD dwStateMask;
#else
UINT lpReserved1;
UINT lpReserved2;
#endif
LPWSTR pszText;
int cchTextMax;
int iImage;
LPARAM lParam;
} TCITEMW, *LPTCITEMW;
这个结构是CTabCtrl的item的结构,它记录了TabCtrl的item的全部信息,其中有一个LPARAM型的参数lParam可以用来存储用户附加的信息,而这个参数正好用来存储由此item控制的页面的指针,到此我们再来看AddPage和ShowCurPage的代码就可以很好的理解了
[c-sharp] view plaincopy
void CTabPage::AddPage(CWnd *pPageWnd, LPTSTR lpTitle)
{
TCITEM itemPage;
itemPage.mask = TCIF_TEXT|TCIF_PARAM;
itemPage.lParam = LPARAM(pPageWnd);
itemPage.pszText = lpTitle;
InsertItem(m_nPageCount, &itemPage);
m_nPageCount==0?pPageWnd->ShowWindow(SW_SHOW):pPageWnd->ShowWindow(SW_HIDE);
m_nPageCount++;
}
void CTabPage::ShowCurPage(UINT nShowState)
{
int nCurItem;
TCITEM itemCur;
nCurItem = GetCurSel();
itemCur.mask = TCIF_PARAM;
GetItem(nCurItem, &itemCur);
((CWnd*)itemCur.lParam)->ShowWindow(nShowState);
}
到此CTabPage的核心功能就已经介绍完毕了,应该说通过本文的方法实现tab控件对页面的控制是十分科学合理的,而且很多控件都有类似的item结构,也都可以通过相同或相似的方法实现模块控制。
由于水平有限,例子制作的较为简陋,可能实现方法也有可以改进之处,还希望朋友们加以斧正,在此谢过。