📄 treepropsheetbase.cpp
字号:
//
bool CTreePropSheetBase::IsItemExpanded(HTREEITEM hItem) const
{
if( NULL == m_pwndPageTree || NULL == hItem )
return false;
return ( TVIS_EXPANDED | TVIS_EXPANDPARTIAL) &
m_pwndPageTree->GetItemState( hItem, TVIS_EXPANDED | TVIS_EXPANDPARTIAL )?true:false;
}
//////////////////////////////////////////////////////////////////////
//
bool CTreePropSheetBase::IsTreeItemDisplayable(const HTREEITEM hItem) const
{
// Determine if the provided hItem has a property page associated with it.
bool bHasValidPropertyPageAssociated = HasValidPropertyPageAssociated( hItem );
bool bDisplayEmpty = bHasValidPropertyPageAssociated || m_bSkipEmptyPages ;
bool bDisplayDisabled = !bHasValidPropertyPageAssociated || IsAssociatedPropertyPageEnabled( hItem ) || !m_bSkipDisabledPages;
return bDisplayEmpty && bDisplayDisabled;
}
//////////////////////////////////////////////////////////////////////
//
void CTreePropSheetBase::Init()
{
m_bTreeViewMode = FALSE;
m_bPageCaption = FALSE;
m_bTreeImages = FALSE;
m_nPageTreeWidth = 150;
m_nSeparatorWidth = 5;
m_pwndPageTree = NULL;
m_pFrame = NULL;
m_nRefillingPageTreeContent = 0;
m_bAutoExpandTree = false;
m_bSkipDisabledPages = true;
m_bSkipEmptyPages = false;
}
//////////////////////////////////////////////////////////////////////
//
void CTreePropSheetBase::SetSkipEmptyPages(const bool bSkipEmptyPages)
{
m_bSkipEmptyPages = bSkipEmptyPages;
}
//////////////////////////////////////////////////////////////////////
//
bool CTreePropSheetBase::IsSkippingEmptyPages() const
{
return m_bSkipEmptyPages;
}
/////////////////////////////////////////////////////////////////////
// Overridings
/////////////////////////////////////////////////////////////////////
BOOL CTreePropSheetBase::OnInitDialog()
{
if (m_bTreeViewMode && !IsWizardMode() )
{
// Fix suggested by Przemek Miszczuk
// http://www.codeproject.com/property/TreePropSheetEx.asp?msg=1024928#xx1024928xx
TreePropSheet::CIncrementScope RefillingPageTreeContentGuard(m_nRefillingPageTreeContent );
// be sure, there are no stacked tabs, because otherwise the
// page caption will be to large in tree view mode
EnableStackedTabs(FALSE);
// Initialize image list.
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);
}
// perform default implementation
BOOL bResult = CPropertySheet::OnInitDialog();
// If in wizard mode, stop here.
if( IsWizardMode() )
return bResult;
// Get tab control...
CTabCtrl *pTab = GetTabControl();
if (!IsWindow(pTab->GetSafeHwnd()))
{
ASSERT(FALSE);
return bResult;
}
// HighColorTab::UpdateImageList to change the internal image list to 24 bits colors)
HighColorTab::UpdateImageList( *this );
// If not in tree mode, stop here.
if (!m_bTreeViewMode)
// stop here, if we would like to use tabs
return bResult;
// ... and hide it
pTab->ShowWindow(SW_HIDE);
pTab->EnableWindow(FALSE);
// Place another (empty) tab ctrl, to get a frame instead
CRect rectFrame;
pTab->GetWindowRect(rectFrame);
ScreenToClient(rectFrame);
m_pFrame = CreatePageFrame();
if (!m_pFrame)
{
ASSERT(FALSE);
AfxThrowMemoryException();
}
m_pFrame->Create(WS_CHILD|WS_VISIBLE|WS_CLIPSIBLINGS, rectFrame, this, 0xFFFF);
m_pFrame->ShowCaption(m_bPageCaption);
// Lets make place for the tree ctrl
const int nTreeWidth = m_nPageTreeWidth;
CRect rectSheet;
GetWindowRect(rectSheet);
rectSheet.right+= nTreeWidth;
SetWindowPos(NULL, -1, -1, rectSheet.Width(), rectSheet.Height(), SWP_NOZORDER|SWP_NOMOVE);
CenterWindow();
MoveChildWindows(nTreeWidth, 0);
// Lets calculate the rectangle for the tree ctrl
CRect rectTree(rectFrame);
rectTree.right = rectTree.left + nTreeWidth - m_nSeparatorWidth;
// calculate caption height
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 no caption should be displayed, make the window smaller in
// height
if (!m_bPageCaption)
{
// make frame smaller
m_pFrame->GetWnd()->GetWindowRect(rectFrame);
ScreenToClient(rectFrame);
rectFrame.top+= rectFrameCaption.Height();
m_pFrame->GetWnd()->MoveWindow(rectFrame);
// move all child windows up
MoveChildWindows(0, -rectFrameCaption.Height());
// modify rectangle for the tree ctrl
rectTree.bottom-= rectFrameCaption.Height();
// make us smaller
CRect rect;
GetWindowRect(rect);
rect.top+= rectFrameCaption.Height()/2;
rect.bottom-= rectFrameCaption.Height()-rectFrameCaption.Height()/2;
if (GetParent())
GetParent()->ScreenToClient(rect);
MoveWindow(rect);
CenterWindow();
}
// finally create the tree control
const DWORD dwTreeStyle = TVS_SHOWSELALWAYS|TVS_TRACKSELECT|TVS_HASLINES|TVS_LINESATROOT|TVS_HASBUTTONS;
m_pwndPageTree = CreatePageTreeObject();
if (!m_pwndPageTree)
{
ASSERT(FALSE);
AfxThrowMemoryException();
}
// MFC7-support here (Thanks to Rainer Wollgarten)
// YT: Cast tree control to CWnd and calls CWnd::CreateEx in all cases (VC 6 and7).
((CWnd*)m_pwndPageTree)->CreateEx(
WS_EX_CLIENTEDGE|WS_EX_NOPARENTNOTIFY,
_T("SysTreeView32"), _T("PageTree"),
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);
}
// TreePropSheetEx: Fix refresh problem.
// Fill the tree ctrl
{
TreePropSheet::CWindowRedrawScope WindowRedrawScope( m_pwndPageTree, true );
// Populate the tree control.
RefillPageTree();
// Expand the tree if necessary.
if( IsAutoExpandTree() )
{
ExpandTreeItem( m_pwndPageTree, m_pwndPageTree->GetRootItem(), TVE_EXPAND );
}
// Select item for the current page
if (pTab->GetCurSel() > -1)
SelectPageTreeItem(pTab->GetCurSel());
}
return bResult;
}
/////////////////////////////////////////////////////////////////////
//
void CTreePropSheetBase::OnDestroy()
{
CPropertySheet::OnDestroy();
// Fix for TN017
if( m_pwndPageTree && m_pwndPageTree->m_hWnd )
m_pwndPageTree->DestroyWindow();
if( m_pFrame && m_pFrame->GetWnd()->m_hWnd )
m_pFrame->GetWnd()->DestroyWindow();
if (m_Images.GetSafeHandle())
m_Images.DeleteImageList();
delete m_pwndPageTree;
m_pwndPageTree = NULL;
delete m_pFrame;
m_pFrame = NULL;
}
/////////////////////////////////////////////////////////////////////
//
LRESULT CTreePropSheetBase::OnAddPage(WPARAM wParam, LPARAM lParam)
{
LRESULT lResult = DefWindowProc(PSM_ADDPAGE, wParam, lParam);
if (!m_bTreeViewMode)
return lResult;
// TreePropSheetEx: Fix refresh problem.
{
TreePropSheet::CWindowRedrawScope WindowRedrawScope( m_pwndPageTree, true );
RefillPageTree();
SelectCurrentPageTreeItem();
}
return lResult;
}
/////////////////////////////////////////////////////////////////////
//
LRESULT CTreePropSheetBase::OnRemovePage(WPARAM wParam, LPARAM lParam)
{
LRESULT lResult = DefWindowProc(PSM_REMOVEPAGE, wParam, lParam);
if (!m_bTreeViewMode)
return lResult;
// TreePropSheetEx: Fix refresh problem.
{
TreePropSheet::CWindowRedrawScope WindowRedrawScope( m_pwndPageTree, true );
RefillPageTree();
SelectCurrentPageTreeItem();
}
return lResult;
}
/////////////////////////////////////////////////////////////////////
//
LRESULT CTreePropSheetBase::OnSetCurSel(WPARAM wParam, LPARAM lParam)
{
LRESULT lResult = DefWindowProc(PSM_SETCURSEL, wParam, lParam);
if (!m_bTreeViewMode)
return lResult;
SelectCurrentPageTreeItem();
UpdateCaption();
return lResult;
}
/////////////////////////////////////////////////////////////////////
//
LRESULT CTreePropSheetBase::OnSetCurSelId(WPARAM wParam, LPARAM lParam)
{
LRESULT lResult = DefWindowProc(PSM_SETCURSEL, wParam, lParam);
if (!m_bTreeViewMode)
return lResult;
SelectCurrentPageTreeItem();
UpdateCaption();
return lResult;
}
/////////////////////////////////////////////////////////////////////
//
void CTreePropSheetBase::OnPageTreeSelChanging(NMHDR *pNotifyStruct, LRESULT *plResult)
{
if( m_nRefillingPageTreeContent )
return;
*plResult = 0;
NMTREEVIEW *pTvn = reinterpret_cast<NMTREEVIEW*>(pNotifyStruct);
int nPage = m_pwndPageTree->GetItemData(pTvn->itemNew.hItem);
BOOL bResult;
// Is the data item pointing to a valid page?
if (nPage<0 || (unsigned)nPage>=m_pwndPageTree->GetCount())
{
// No, see if we are skipping empty page.
if( IsTreeItemDisplayable( pTvn->itemNew.hItem ) )
{
// Skipping empty page, get the next valid page.
HTREEITEM hNewItem = GetNextValidPageTreeItem( pTvn->itemNew.hItem );
if( hNewItem )
m_pwndPageTree->SelectItem( hNewItem );
bResult = false;
}
else
{
// Not skipping empty pages, kill the current page so that we can display
// the generic message.
bResult = KillActiveCurrentPage();
}
}
else
{
if( IsTreeItemDisplayable( pTvn->itemNew.hItem ) )
{
// OK, set the new active page.
TreePropSheet::CIncrementScope RefillingPageTreeContentGuard( m_nRefillingPageTreeContent );
bResult = SetActivePage(nPage);
}
else
{
HTREEITEM hNewItem = GetNextValidPageTreeItem( pTvn->itemNew.hItem );
if( hNewItem )
m_pwndPageTree->SelectItem( hNewItem );
bResult = false;
}
}
if (!bResult)
// prevent selection to change
*plResult = TRUE;
// Set focus to tree control (I guess that's what the user expects)
m_pwndPageTree->SetFocus();
return;
}
/////////////////////////////////////////////////////////////////////
//
void CTreePropSheetBase::OnPageTreeSelChanged(NMHDR *pNotifyStruct, LRESULT *plResult)
{
UNREFERENCED_PARAMETER(pNotifyStruct);
// Refilling the tree control, ignore selection change.
if( m_nRefillingPageTreeContent )
return;
*plResult = 0;
UpdateCaption();
return;
}
/////////////////////////////////////////////////////////////////////
//
LRESULT CTreePropSheetBase::OnEnablePage(WPARAM wParam, LPARAM lParam)
{
// Convert parameters
CPropertyPage* pPage = reinterpret_cast<CPropertyPage*>( wParam );
bool bEnable = lParam?true:false;
// Make sure that this page is inside this sheet.
// Enable/Disable the page.
EnablePage( pPage, bEnable );
return 1L;
}
/////////////////////////////////////////////////////////////////////
//
LRESULT CTreePropSheetBase::OnIsDialogMessage(WPARAM wParam, LPARAM lParam)
{
MSG *pMsg = reinterpret_cast<MSG*>(lParam);
ASSERT( pMsg );
if (pMsg->message==WM_KEYDOWN && GetKeyState(VK_CONTROL)&0x8000)
{
if( pMsg->wParam==VK_TAB )
{
if (GetKeyState(VK_SHIFT)&0x8000)
{
ActivatePreviousPage();
}
else
{
ActivateNextPage();
}
}
else
{
if( pMsg->wParam==VK_PRIOR ) /*PageUp*/
{
ActivatePreviousPage();
}
else
{
if( pMsg->wParam==VK_NEXT ) /*PageDown*/
{
ActivateNextPage();
}
}
}
return TRUE;
}
return CPropertySheet::DefWindowProc(PSM_ISDIALOGMESSAGE, wParam, lParam);
}
/////////////////////////////////////////////////////////////////////
//
BOOL CTreePropSheetBase::PreTranslateMessage(MSG* pMsg)
{
if( pMsg->hwnd == GetPageTreeControl()->GetSafeHwnd() )
{
// If not in skipping empty page mode, keep the standard behavior.
if( !m_bSkipEmptyPages )
return CPropertySheet::PreTranslateMessage(pMsg);
if( pMsg->message == WM_KEYDOWN )
{
// Get the current tree item.
HTREEITEM hCurrentItem = m_pwndPageTree->GetSelectedItem();
if( NULL == hCurrentItem )
return TRUE;
if( pMsg->wParam == VK_UP )
{
// Active the previous page according to tree ordering -
// skipping empty pages on the way.
ActivatePreviousPage( hCurrentItem );
return TRUE;
}
else if ( pMsg->wParam == VK_DOWN )
{
// Active the next page according to tree ordering -
// skipping empty pages on the way.
ActivateNextPage( hCurrentItem );
return TRUE;
}
else if( pMsg->wParam == VK_LEFT )
{
/* Here, we try to mimic the tree keyboard handling by doing
one of the two things:the following
- If the tree item is expanded, collapse it
- If the tree item is collapse, find a parent item that has a page
associated with it and select it, collapsing all items along the
way. */
if( IsItemExpanded( hCurrentItem ) )
{
// Collapse the item since it is expanded.
m_pwndPageTree->Expand( hCurrentItem, TVE_COLLAPSE );
}
else
{
// Already collapsed, search for a candidate for selection.
HTREEITEM hItem = m_pwndPageTree->GetParentItem( hCurrentItem );
while( NULL != hItem && !HasValidPropertyPageAssociated( hItem ) )
{
// Add item to the stack.
hItem = m_pwndPageTree->GetParentItem( hItem );
}
// If the item points to a valid page, select it and collapse
if( NULL != hItem && HasValidPropertyPageAssociated( hItem ) )
{
m_pwndPageTree->SelectItem( hItem );
}
}
return TRUE;
}
else if( pMsg->wParam == VK_RIGHT )
{
/* Here, we try to mimic the tree keyboard handling by doing
one of the two things:the following
- If the tree item is collapsed, expand it
- If the tree item is expanded, find a child item that has a page
associated with it and select it, expanding all items along the
way. The child has to be a first child in the hierarchy. */
if( IsItemExpanded( hCurrentItem ) )
{
// Already expanded, search for a candidate for selection.
HTREEITEM hItem = m_pwndPageTree->GetChildItem( hCurrentItem );
while( NULL != hItem && !HasValidPropertyPageAssociated( hItem ) )
{
// Add item to the stack.
hItem = m_pwndPageTree->GetChildItem( hItem );
}
// If the item points to a valid page, select it and collapse
if( NULL != hItem && HasValidPropertyPageAssociated( hItem ) )
{
m_pwndPageTree->SelectItem( hItem );
}
}
else
{
// Expand the item since it is collapsed.
m_pwndPageTree->Expand( hCurrentItem, TVE_EXPAND );
}
return TRUE;
}
}
}
else if( WM_ENABLE == pMsg->message)
{
// Handle WM_ENABLE messages for property pages: Update the property page
// information map.
TRACE("");
}
return CPropertySheet::PreTranslateMessage(pMsg);
}
} //namespace TreePropSheet
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -