实现类似Excel和Visual C++里文件夹式样的标签控制(一)
2007-11-01 20:23:03 来源:WEB开发网有关CFolderTabCtrl的实现细节请参考源代码。其头文件为Ftab.h,实现文件为Ftab.cpp。在分析CFolderTabCtrl的实现原理之前,让我先来说明一下这个类的使用方法。当FldrTab程序的InitInstance函数获得控制权时,它创建一个主对话框的实例,并运行这个对话框:
BOOL CApp::InitInstance()
{
CMyDialog dlg;
m_pMainWnd = &dlg;
dlg.DoModal();
return FALSE;
}
CMyDialog有两个控制:一个是m_wndStaticInfo,另一个是m_wndFolderTab。顾名思义,第一个控制为一个静态文本窗口,它显示选中的标签,第二个是标签控制本身,即CFolderTabCtrl实例。通过调用SubclassDlgItem,CMyDialog::OnInitDialog以常规方式子类化静态文本,遗憾的是它不能子类化标签控制,因为对话框中并没有实际的标签控制窗口。此外也没有办法借助COM技术将此标签控制实现为一个带运行时接口的定制控件。我的办法是在对话框想要放置标签控制的地方创建一个静态文本控件。如图五所示:
图五 用静态文本控件定位标签控制
在OnDialogInit中通过调用一个特殊的函数,在运行时将静态文本替换成标签控制。
m_wndFolderTab.CreateFromStatic(IDC_FOLDERTAB, this);
CFolderTabCtrl::CreateFromStatic 在静态文本控件的位置上创建一个标签控制,然后删除静态文本控件。这是我创建特殊对话框控制常用的绝招,我认为这个诀窍是超一流的。在调用Create之前,CreateFromStatic调用CFolderTab::GetDesiredHeight来获得控制的高度,而忽略静态文本控件的高度。在非对话框应用中不能调用CreateFromStatic;而是要直接调用CFolderTab::Create。创建了标签控制后,接下来你必须设置标签名字。这里是在CMyDialog中调用现成的Load函数。
m_wndFolderTab.Load(IDR_FOLDERTABS);
IDR_FOLDERTABS是串资源的ID,它是一个包含新行指示符(“\n”)分割的标签名(“在线杂志第一期\n在线杂志第二期\n……”),一旦创建了控制并调用Load,那么你的标签控制就完全happy了。它看起来就象图三所示的那样。
当然,这时它还不能做任何事情,你还必须处理它们的通知消息。当用户按下一个标签时,CFolderTab便用特殊代码FTN_TABCHANGED向对话框发送一个WM_NOTIFY消息。然后对话框处理这条消息,也就是在上面的静态文本控件中显示一条信息。
void CMyDialog::OnChangedTab(NMFOLDERTAB* nmtab,LRESULT* pRes)
NMFOLDERTAB 结构在FTab.h. 文件中定义。
{
CString s;
s.Format(_T("选中 %d: %s"),nmtab->iItem,nmtab->pItem->GetText());
m_wndStaticInfo.SetWindowText(s);
} struct NMFOLDERTAB : public NMHDR {
int iItem; // 项目索引
const CFolderTab* pItem; // 标签
};
这个结构除了NMHDR所包含的成员之外,还有项目索引和指向当前标签CFolderTab的指针,它与CFolderTabCtrl有所不同,从CFolderTab中你可以得到标签的文本。以上就是CFolderTabCtrl的使用方法。
下面我们就来揭示这个C++类的实现原理。前面已经对CreateFromStatic进行了描述,那么CFolderTabCtrl::Load是个什么样的函数呢,这个函数的功能是加载一个串标签名,这个串是用新行指示符(“\n”)分割的字符串,吸取其中的子串,并调用CFolderTabCtrl::AddItem将它添加到每一个标签上。
int CFolderTabCtrl::AddItem(LPCTSTR lpszText)
{
m_lsTabs.AddTail(new CFolderTab(lpszText));
return m_lsTabs.GetCount() - 1;
}
就这么简单,创建一个新的CFolderTab对象并将它添加到一个列表中。与AddItem相对的是RemoveItem函数,它们的实现都在Ftab.cpp文件中,这两个函数分别负责动态添加和删除标签页,而不是存取资源串。然后是GetItem和GetItemCount函数,一看它们的名字你就应该明白它们的作用,前者用来获取CFolderTab标签的索引号(从0开始),后者则返回m_lsTabs.GetCount,即总共有多少标签。此外,你一定想需要有个函数来获取和设置标签文本,没问题,每一个CFolderTab对象都有一个m_sText成员变量来存储标签名,存取方法是GetText和SetText,我想你闭着眼睛都能写出这些代码!
更多精彩
赞助商链接