📄 treepropsheet.cpp
字号:
return hResult;
}
hItem = m_pwndPageTree->GetNextItem(hItem, TVGN_NEXT);
}
return hItem;
}
BOOL CTreePropSheet::SelectPageTreeItem(int nPage)
{
HTREEITEM hItem = GetPageTreeItem(nPage);
if (!hItem)
return FALSE;
return m_pwndPageTree->SelectItem(hItem);
}
BOOL CTreePropSheet::SelectCurrentPageTreeItem()
{
CTabCtrl *pTab = GetTabControl();
if (!IsWindow(pTab->GetSafeHwnd()))
return FALSE;
return SelectPageTreeItem(pTab->GetCurSel());
}
void CTreePropSheet::UpdateCaption()
{
HWND hPage = PropSheet_GetCurrentPageHwnd(GetSafeHwnd());
BOOL bRealPage = IsWindow(hPage) && ::IsWindowVisible(hPage);
HTREEITEM hItem = m_pwndPageTree->GetSelectedItem();
if (!hItem)
return;
CString strCaption = m_pwndPageTree->GetItemText(hItem);
//若页为空则更新页的文本
if (!bRealPage)
m_pFrame->SetMsgText(GenerateEmptyPageMessage(m_strEmptyPageMessage, strCaption));
//如果没有标题则取消它
if (!m_pFrame->GetShowCaption())
return;
//获取tab控件
CTabCtrl *pTabCtrl = GetTabControl();
if (!IsWindow(pTabCtrl->GetSafeHwnd()))
{
ASSERT(FALSE);
return;
}
if (m_bTreeImages)
{
//从树上获取图标
int nImage;
m_pwndPageTree->GetItemImage(hItem, nImage, nImage);
HICON hIcon = m_Images.ExtractIcon(nImage);
m_pFrame->SetCaption(strCaption, hIcon);
if (hIcon)
DestroyIcon(hIcon);
}
else if (bRealPage)
{
//从隐藏的tab获取图像
CImageList *pImages = pTabCtrl->GetImageList();
if (pImages)
{
TCITEM ti;
ZeroMemory(&ti, sizeof(ti));
ti.mask = TCIF_IMAGE;
HICON hIcon = NULL;
if (pTabCtrl->GetItem((int)m_pwndPageTree->GetItemData(hItem), &ti))
hIcon = pImages->ExtractIcon(ti.iImage);
m_pFrame->SetCaption(strCaption, hIcon);
if (hIcon)
DestroyIcon(hIcon);
}
else
m_pFrame->SetCaption(strCaption);
}
else
m_pFrame->SetCaption(strCaption);
}
void CTreePropSheet::ActivatePreviousPage()
{
if (!IsWindow(m_hWnd))
return;
if (!IsWindow(m_pwndPageTree->GetSafeHwnd()))
{
//常规的tab属性表,简单使用页索引
int nPageIndex = GetActiveIndex();
if (nPageIndex<0 || nPageIndex>=GetPageCount())
return;
int nPrevIndex = (nPageIndex==0)? GetPageCount()-1 : nPageIndex-1;
SetActivePage(nPrevIndex);
}
else
{
//这里需要复杂的处理而非简单地使用页索引,
//因为我们不能略过空页,所以必须寻访页树
HTREEITEM hItem = m_pwndPageTree->GetSelectedItem();
ASSERT(hItem);
if (!hItem)
return;
HTREEITEM hPrevItem = NULL;
if (hPrevItem=m_pwndPageTree->GetPrevSiblingItem(hItem))
{
while (m_pwndPageTree->ItemHasChildren(hPrevItem))
{
hPrevItem = m_pwndPageTree->GetChildItem(hPrevItem);
while (m_pwndPageTree->GetNextSiblingItem(hPrevItem))
hPrevItem = m_pwndPageTree->GetNextSiblingItem(hPrevItem);
}
}
else
hPrevItem=m_pwndPageTree->GetParentItem(hItem);
if (!hPrevItem)
{
//前一项不存在,则循环至最后项
hPrevItem = m_pwndPageTree->GetRootItem();
while (TRUE)
{
while (m_pwndPageTree->GetNextSiblingItem(hPrevItem))
hPrevItem = m_pwndPageTree->GetNextSiblingItem(hPrevItem);
if (m_pwndPageTree->ItemHasChildren(hPrevItem))
hPrevItem = m_pwndPageTree->GetChildItem(hPrevItem);
else
break;
}
}
if (hPrevItem)
m_pwndPageTree->SelectItem(hPrevItem);
}
}
void CTreePropSheet::ActivateNextPage()
{
if (!IsWindow(m_hWnd))
return;
if (!IsWindow(m_pwndPageTree->GetSafeHwnd()))
{
//常规的tab属性表,简单使用页索引
int nPageIndex = GetActiveIndex();
if (nPageIndex<0 || nPageIndex>=GetPageCount())
return;
int nNextIndex = (nPageIndex==GetPageCount()-1)? 0 : nPageIndex+1;
SetActivePage(nNextIndex);
}
else
{
//这里需要复杂的处理而非简单地使用页索引,
//因为我们不能略过空页,所以必须寻访页树
HTREEITEM hItem = m_pwndPageTree->GetSelectedItem();
ASSERT(hItem);
if (!hItem)
return;
HTREEITEM hNextItem = NULL;
if (hNextItem=m_pwndPageTree->GetChildItem(hItem))
;
else if (hNextItem=m_pwndPageTree->GetNextSiblingItem(hItem))
;
else if (m_pwndPageTree->GetParentItem(hItem))
{
while (!hNextItem)
{
hItem = m_pwndPageTree->GetParentItem(hItem);
if (!hItem)
break;
hNextItem = m_pwndPageTree->GetNextSiblingItem(hItem);
}
}
if (!hNextItem)
//前一项不存在,则循环至第一项
hNextItem = m_pwndPageTree->GetRootItem();
if (hNextItem)
m_pwndPageTree->SelectItem(hNextItem);
}
}
/////////////////////////////////////////////////////////////////////
// Overridings
BOOL CTreePropSheet::OnInitDialog()
{
if (m_bTreeViewMode)
{
//确保属性表标签没有堆积,否则在树形模式下页标题将会很大
EnableStackedTabs(FALSE);
//初始化图像列表
if (m_DefaultImages.GetSafeHandle())
{
IMAGEINFO ii;
m_DefaultImages.GetImageInfo(0, &ii);
if (ii.hbmImage) DeleteObject(ii.hbmImage);
if (ii.hbmMask) DeleteObject(ii.hbmMask);
m_Images.Create(ii.rcImage.right-ii.rcImage.left, ii.rcImage.bottom-ii.rcImage.top, ILC_COLOR32|ILC_MASK, 0, 1);
}
else
m_Images.Create(16, 16, ILC_COLOR32|ILC_MASK, 0, 1);
}
//完成缺省的实现
BOOL bResult = CPropertySheet::OnInitDialog();
if (!m_bTreeViewMode)
//如果使用常规的属性表则直接返回即可
return bResult;
//获取属性表的标签控件
CTabCtrl *pTab = GetTabControl();
if (!IsWindow(pTab->GetSafeHwnd()))
{
ASSERT(FALSE);
return bResult;
}
//隐藏标签控件
pTab->ShowWindow(SW_HIDE);
pTab->EnableWindow(FALSE);
//实际上放置的是一个空的tab控件,目的是在Tab的位置上创建框架
//相当于将Tab控件当作占位符
CRect rectFrame;
pTab->GetWindowRect(rectFrame);
ScreenToClient(rectFrame);
//创建CPropPageFrame 对象
m_pFrame = CreatePageFrame();
if (!m_pFrame)
{
ASSERT(FALSE);
AfxThrowMemoryException();
}
//创建CPropPageFrame窗口
m_pFrame->Create(WS_CHILD|WS_VISIBLE|WS_CLIPSIBLINGS, rectFrame, this, 0xFFFF);
m_pFrame->ShowCaption(m_bPageCaption);
//为树控件提供空间,默认宽度120像素
const int nTreeWidth = m_nPageTreeWidth;
//树形控件和属性表标签控件之间的距离
const int nTreeSpace = 5;
CRect rectSheet;
//获取属性表大小
GetWindowRect(rectSheet);
//将属性表加宽nTreeWidth,以便为额外的树形控件提供空间
rectSheet.right+= nTreeWidth;
//根据新的大小,重新设置属性表
SetWindowPos(NULL, -1, -1, rectSheet.Width(), rectSheet.Height(), SWP_NOZORDER|SWP_NOMOVE);
//将属性表调整到父窗口中央
CenterWindow();
//将所有的子窗口向右移动nTreeWidth像素
MoveChildWindows(nTreeWidth, 0);
//计算树形控件的矩形大小
CRect rectTree(rectFrame);
//树形控件的右边界为:
rectTree.right = rectTree.left + nTreeWidth - nTreeSpace;
//计算标题的高度
//创建Tab控件,只是用来计算标签的高度,因为树形控件的标题栏高度将等于此值
CTabCtrl wndTabCtrl;
wndTabCtrl.Create(WS_CHILD|WS_VISIBLE|WS_CLIPSIBLINGS, rectFrame, this, 0x1234);
wndTabCtrl.InsertItem(0, _T(""));
CRect rectFrameCaption;
wndTabCtrl.GetItemRect(0, rectFrameCaption);
wndTabCtrl.DestroyWindow();
//设置标题栏高度
m_pFrame->SetCaptionHeight(rectFrameCaption.Height());
//如果不需要显示标题,则可使该窗口的高度小一些
if (!m_bPageCaption)
{
//使框架小一些
m_pFrame->GetWnd()->GetWindowRect(rectFrame);
ScreenToClient(rectFrame);
rectFrame.top+= rectFrameCaption.Height();
m_pFrame->GetWnd()->MoveWindow(rectFrame);
//移动所有的子窗口
MoveChildWindows(0, -rectFrameCaption.Height());
//修改树控件的矩形
rectTree.bottom-= rectFrameCaption.Height();
//减小窗口的大小
CRect rect;
GetWindowRect(rect);
rect.top+= rectFrameCaption.Height()/2;
rect.bottom-= rectFrameCaption.Height()-rectFrameCaption.Height()/2;
if (GetParent())
GetParent()->ScreenToClient(rect);
MoveWindow(rect);
}
//最后创建树控件对象
const DWORD dwTreeStyle = TVS_SHOWSELALWAYS|TVS_TRACKSELECT|TVS_HASLINES|TVS_LINESATROOT|TVS_HASBUTTONS;
m_pwndPageTree = CreatePageTreeObject();
if (!m_pwndPageTree)
{
ASSERT(FALSE);
AfxThrowMemoryException();
}
//并创建树控件窗口
m_pwndPageTree->CreateEx(
WS_EX_CLIENTEDGE|WS_EX_NOPARENTNOTIFY,
_T("SysTreeView32"), _T("属性页树视"),
WS_TABSTOP|WS_CHILD|WS_VISIBLE|dwTreeStyle,
rectTree, this, s_unPageTreeId);
if (m_bTreeImages)
{
m_pwndPageTree->SetImageList(&m_Images, TVSIL_NORMAL);
m_pwndPageTree->SetImageList(&m_Images, TVSIL_STATE);
}
//设置树控件颜色
m_pwndPageTree->SetBkColor(RGB(192,192,192));
//填充树控件
RefillPageTree();
// 选择当前页对应的项
if (pTab->GetCurSel() > -1)
SelectPageTreeItem(pTab->GetCurSel());
return bResult;
}
void CTreePropSheet::OnDestroy()
{
CPropertySheet::OnDestroy();
if (m_Images.GetSafeHandle())
m_Images.DeleteImageList();
delete m_pwndPageTree;
m_pwndPageTree = NULL;
delete m_pFrame;
m_pFrame = NULL;
}
LRESULT CTreePropSheet::OnAddPage(WPARAM wParam, LPARAM lParam)
{
LRESULT lResult = DefWindowProc(PSM_ADDPAGE, wParam, lParam);
if (!m_bTreeViewMode)
return lResult;
RefillPageTree();
SelectCurrentPageTreeItem();
return lResult;
}
LRESULT CTreePropSheet::OnRemovePage(WPARAM wParam, LPARAM lParam)
{
LRESULT lResult = DefWindowProc(PSM_REMOVEPAGE, wParam, lParam);
if (!m_bTreeViewMode)
return lResult;
RefillPageTree();
SelectCurrentPageTreeItem();
return lResult;
}
LRESULT CTreePropSheet::OnSetCurSel(WPARAM wParam, LPARAM lParam)
{
LRESULT lResult = DefWindowProc(PSM_SETCURSEL, wParam, lParam);
if (!m_bTreeViewMode)
return lResult;
SelectCurrentPageTreeItem();
UpdateCaption();
return lResult;
}
void CTreePropSheet::OnPageTreeSelChanging(NMHDR *pNotifyStruct, LRESULT *plResult)
{
*plResult = 0;
if (m_bPageTreeSelChangedActive)
return;
else
m_bPageTreeSelChangedActive = TRUE;
NMTREEVIEW *pTvn = reinterpret_cast<NMTREEVIEW*>(pNotifyStruct);
int nPage = m_pwndPageTree->GetItemData(pTvn->itemNew.hItem);
BOOL bResult;
if (nPage<0 || (unsigned)nPage>=m_pwndPageTree->GetCount())
bResult = KillActiveCurrentPage();
else
bResult = SetActivePage(nPage);
if (!bResult)
//防止选择的变化
*plResult = TRUE;
//设置树控件焦点
m_pwndPageTree->SetFocus();
m_bPageTreeSelChangedActive = FALSE;
return;
}
void CTreePropSheet::OnPageTreeSelChanged(NMHDR *pNotifyStruct, LRESULT *plResult)
{
*plResult = 0;
UpdateCaption();
return;
}
LRESULT CTreePropSheet::OnIsDialogMessage(WPARAM wParam, LPARAM lParam)
{
MSG *pMsg = reinterpret_cast<MSG*>(lParam);
if (pMsg->message==WM_KEYDOWN && pMsg->wParam==VK_TAB && GetKeyState(VK_CONTROL)&0x8000)
{
if (GetKeyState(VK_SHIFT)&0x8000)
ActivatePreviousPage();
else
ActivateNextPage();
return TRUE;
}
return CPropertySheet::DefWindowProc(PSM_ISDIALOGMESSAGE, wParam, lParam);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -