📄 treeoptionsctrl.cpp
字号:
/*
Module : TreeOptionsCtrl.cpp
Purpose: Implementation for an MFC class to implement a tree options control
similiar to the advanced tab as seen on the "Internet options" dialog in
Internet Explorer 4 and later
Created: PJN / 31-03-1999
History: PJN / 21-04-1999 Added full support for enabling / disabling all the item types
PJN / 05-10-1999 Made class more self contained by internally managing the image list
PJN / 07-10-1999 1. Added support for including combo boxes aswell as edit boxes into the
edit control.
2. Added support for customizing the image list to use
PJN / 29-02-2000 Removed a VC 6 level 4 warning
PJN / 03-04-2000 Added support for navigation into and out of the combo boxes and edit controls
inside the control
PJN / 10-05-2000 1. Fixed a bug where the text was not being transferred to the control when the
in inplace combo or edit box is active and the tree control gets destroyed.
2. Added support for having check box items as children of other check box items
3. Setting the check box state of a parent now also sets the check box state
for all child box children.
4. Setting the check box state afects the check box state of the parent if that
parent is also a check box.
PJN / 30-05-2000 Code now uses ON_NOTIFY_REFLECT_EX instead of ON_NOTIFY_REFLECT. This allows
derived classes to handle the reflected messages also.
PJN / 03-07-2000 Now includes support for edit boxes with accompanying spin controls
PJN / 25-04-2001 1. Creation of the image list is now virtual. This allows customisation such as
being able to use high color bitmaps
2. Added an option which determines if check box state should be changed when you
click anywhere on an item or just over the checkbox icon
3. Updated copyright message
PJN / 12-08-2001 1. Fixed an issue in GetComboText and GetEditText where the code was modifying the
contents of the combo/edit box when it was being read. This was because that
function is doing double duty as it is called when the child control is about to be
created in place, and you want to remove the text from the tree control and put it
in the child control. Thanks to "Jef" for spotting this.
2. Made the code in SetComboText more robust. Thanks to "Jef" for this also.
3. Added a DDX method for integers in a edit box. Thanks to Colin Urquhart for this.
4. Added an extra member to CTreeOptionsItemData to be used as an item data. This
allows you to avoid having to implement multiple derived classes and instead use
the item data's I now provide to stash away pointers etc.
PJN / 27-08-2001 1. Provided a "GetUserItemData" member to provide access to the item data provided
by the class. Thanks to Colin Urquhart for this.
2. Fixed a redraw problem which occured when you scrolled using an wheel enabled
mouse. Thanks to "Jef" for spotting this.
3. Provided an AutoSelect option which automatically sets focus to child control
in the tree control. Thanks to "Jef" for this suggestion.
4. Added full support for CBS_DROPDOWN and CBS_SIMPLE style combo boxes. Thanks
to "Jef" for this suggestion.
PJN / 16-08-2001 1. Provided support for specify a color via CColorDialog.
2. Controls are now created to fill the full width of the tree control
3. Provided support for specifying a font via CFontDialog
4. Provided support for specifying a font name from a combo box
5. Provided support for specifying a boolean value from a combo box
PJN / 27-11-2001 1. Fixed a bug where the message map for OnMouseWheel was setup incorrectly. It
should have been ON_WM_MOUSEWHEEL instead of ON_MESSAGE!!!.
2. Allowed passing in the hAfter item for the InsertItem calls. All parms are defaulted
as to not affect any current code.
3. Made possible the use of radio button groups followed by other items (in which case
the group is considered complete).
4. Added a couple of utility functions at the bottom of the cpp file. Thanks to Mike
Funduc for all these updates.
PJN / 05-11-2001 1. Minor code tidy up following development of the author's CTreeOptionsCtrl class
PJN / 13-12-2001 1. Fixed an assertion in OnClick. Thanks to "flipposwitch" for spotting the problem
PJN / 14-02-2002 1. Now allows item data to be associated with any item added to the control
2. Fixed issue with return value from GetUserItemData
PJN / 02-06-2002 1. Moved sample app to VC 6 to facilitate support for IP Address control and date and
time controls.
2. Fixed a bug where the child controls can get orphaned when a node in the tree
control is expaned or contracted. Thanks to Lauri Ott for spotting this problem.
3. Now fully supports the CDateTimeCtrl for editing of dates and times
4. Now fully supports the CIPAddressCtrl for editing of IP addresses
5. Custom draw support for color browser items is now configurable via an additional
parameter of the AddColorBrowser method
PJN / 24-09-2002 1. Updated documentation which incorrectly stated that the parent of a check box item
must be a group item as inserted with InsertGroup. Thanks to K鰃l Christoph for
spotting this.
2. Fixed an issue with "IMPLEMENT_DYNAMIC(CDateTimeCtrl..." not being declared propertly.
Some users reported that it worked ok, while others said that my fix was causing link
problems. The problem should be sorted out for good now. Thanks to K鰃l Christoph for
reporting this.
3. Renamed the SetImageListToUse function to "SetImageListResourceIDToUse".
4. Provided a GetImageListResourceIDToUse function to match up with the Set function.
5. Provided a method to allow the user item data to be changed after an item has
been created.
6. Provided some documentation info how how to safely use item data in the control.
Thanks to K鰃l Christoph for reporting this.
7. Fixed a potential memory leak in AddComboBox if the function is invoked twice without
an explicit delete of the item first. Thanks to K鰃l Christoph for reporting this.
8. Fixed sometypos in the documentation. It incorectly stated that the return type of
member functions InsertGroup, InsertCheckBox, and InsertRadioButton is BOOL when in fact
it is HTREEITEM. Thanks to K鰃l Christoph for reporting this.
9. Improved the look of the disabled checked check button. Thanks to K鰃l Christoph for
reporting this.
10. Improved the look of the disabled radio button which is selected. Thanks to K鰃l
Christoph for reporting this.
PJN / 17-10-2002 1. Added a method to add an "Opaque Browser" to the Tree options control. An
Opaque Browser is where the tree options control allows a end user specified
structure to be edited by the tree options control without it explicitly
knowing what it is editing.
PJN / 25-10-2002 1. Updated the download to include the missing files OpaqueShow.cpp/h. Thanks to K鰃l
Christoph for reporting this.
2. Made the class more const-correct. e.g. the Get... member functions are now const.
Thanks to K鰃l Christoph for reporting this. Also updated the documentation for this.
3. Updated the documentation to refer to the "Opaque Browser" support.
PJN / 28-10-2002 1. Fixed a bug where upon a combo losing focus it will also result in the associated
button control would also be destroyed. Thanks to K鰃l Christoph for reporting this
problem. Fixed this bug should also fix an intermittent release bug which was occurring
in this area.
PJN / 30-10-2002 1. Made a number of other methods const. Thanks to K鰃l Christoph for reporting this.
PJN / 15-11-2002 1. Now allows the Field Data separator i.e. ": " to be configured. Please note that the
characters you pick should be avoided in the descriptive text you display for an item
as it is used as the divider between the descriptive text and the actual data to be
edited. Thanks to K鰃l Christoph for this update.
2. Fixed an access violation in CTreeOptionsCtrl::OnSelchanged when there is no selected
item in the control. Thanks to K鰃l Christoph for this update.
PJN / 06-03-2003 1. Fixed a memory leak which can occur when the control is used in a property sheet.
Thanks to David Rainey for reporting this problem.
2. Fixed another memory leak in the destructor of the CTreeOptionsCtrl class when the
test app is closed
PJN / 14-05-2003 1. Fixed a bug where the OnSelChanged function was getting in the way when the control was
being cleared down, leading to an ASSERT. Thanks to Chen Fu for reporting this problem.
PJN / 07-06-2003 1. Fixed a bug where the date time control was not reflecting the changes when the child
control was displayed. Thanks to Tom Serface for reporting this problem.
PJN / 17-07-2003 1. Made SetRadioButton methods in CTreeOptionsCtrl virtual to allow further client
customisation.
Copyright (c) 1999 - 2003 by PJ Naughter. (Web: www.naughter.com, Email: pjna@naughter.com)
All rights reserved.
Copyright / Usage Details:
You are allowed to include the source code in any product (commercial, shareware, freeware or otherwise)
when your product is released in binary form. You are allowed to modify the source code in any way you want
except you cannot modify the copyright details at the top of each module. If you want to distribute source
code with your application, then you are only allowed to distribute versions released by the author. This is
to maintain a single distribution point for the source code.
*/
//////////////// Includes ////////////////////////////////////////////
#include "stdafx.h"
#include "resource.h"
#ifndef _SHLOBJ_H_
#pragma message("To avoid this message, please put shlobj.h in your pre compiled header (normally stdafx.h)")
#include <shlobj.h>
#endif
#include "TreeOptionsCtrl.h"
//////////////// Macros / Locals /////////////////////////////////////
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
const UINT TREE_OPTIONS_COMBOBOX_ID = 100;
const UINT TREE_OPTIONS_EDITBOX_ID = 101;
const UINT TREE_OPTIONS_SPINCTRL_ID = 102;
const UINT TREE_OPTIONS_BROWSEBUTTONCTRL_ID = 103;
const UINT TREE_OPTIONS_STATIC_ID = 104;
const UINT TREE_OPTIONS_DATETIMECTRL_ID = 105;
const UINT TREE_OPTIONS_IPADDRESSCTRL_ID = 106;
#define WM_TOC_SETFOCUS_TO_CHILD WM_APP + 1
#define WM_TOC_REPOSITION_CHILD_CONTROL WM_APP + 2
//////////////// Implementation //////////////////////////////////////
IMPLEMENT_DYNAMIC(CTreeOptionsCtrl, CTreeCtrl)
BEGIN_MESSAGE_MAP(CTreeOptionsCtrl, CTreeCtrl)
//{{AFX_MSG_MAP(CTreeOptionsCtrl)
ON_WM_LBUTTONDOWN()
ON_WM_CHAR()
ON_WM_DESTROY()
ON_WM_VSCROLL()
ON_WM_HSCROLL()
ON_WM_KEYDOWN()
ON_WM_KILLFOCUS()
ON_WM_LBUTTONDOWN()
//}}AFX_MSG_MAP
ON_WM_MOUSEWHEEL()
ON_MESSAGE(WM_TOC_SETFOCUS_TO_CHILD, OnSetFocusToChild)
ON_MESSAGE(WM_TOC_REPOSITION_CHILD_CONTROL, OnRepositionChild)
ON_NOTIFY_REFLECT_EX(NM_CLICK, OnClick)
ON_NOTIFY_REFLECT_EX(TVN_SELCHANGED, OnSelchanged)
ON_NOTIFY_REFLECT_EX(TVN_ITEMEXPANDING, OnItemExpanding)
ON_NOTIFY_REFLECT_EX(TVN_DELETEITEM, OnDeleteItem)
ON_NOTIFY_REFLECT_EX(NM_CUSTOMDRAW, OnCustomDraw)
END_MESSAGE_MAP()
CTreeOptionsCtrl::CTreeOptionsCtrl()
{
m_pCombo = NULL;
m_pEdit = NULL;
m_pSpin = NULL;
m_pButton = NULL;
m_pDateTime = NULL;
m_pIPAddress = NULL;
#ifdef IDB_TREE_CTRL_OPTIONS
m_nilID = IDB_TREE_CTRL_OPTIONS;
#endif
m_hControlItem = NULL;
m_bToggleOverIconOnly = FALSE;
m_bAutoSelect = FALSE;
m_sSeparator = _T(": ");
m_bBeingCleared = FALSE;
}
CTreeOptionsCtrl::~CTreeOptionsCtrl()
{
DestroyOldChildControl();
ASSERT(m_pCombo == NULL);
ASSERT(m_pEdit == NULL);
ASSERT(m_pSpin == NULL);
ASSERT(m_pButton == NULL);
ASSERT(m_pDateTime == NULL);
ASSERT(m_pIPAddress == NULL);
}
LRESULT CTreeOptionsCtrl::OnSetFocusToChild(WPARAM /*wParam*/, LPARAM /*lParam*/)
{
if (m_pCombo)
m_pCombo->SetFocus();
else if (m_pEdit)
m_pEdit->SetFocus();
else if (m_pDateTime)
m_pDateTime->SetFocus();
else if (m_pIPAddress)
m_pIPAddress->SetFocus();
return 0L;
}
LRESULT CTreeOptionsCtrl::OnRepositionChild(WPARAM /*wParam*/, LPARAM /*lParam*/)
{
HTREEITEM hItem = GetSelectedItem();
if (hItem)
{
UpdateTreeControlValueFromChildControl(hItem);
DestroyOldChildControl();
CreateNewChildControl(hItem);
}
return 0L;
}
DWORD CTreeOptionsCtrl::GetUserItemData(HTREEITEM hItem) const
{
CTreeOptionsItemData* pItemData = (CTreeOptionsItemData*) GetItemData(hItem);
ASSERT(pItemData);
return pItemData->m_dwItemData;
}
BOOL CTreeOptionsCtrl::SetUserItemData(HTREEITEM hItem, DWORD dwData)
{
CTreeOptionsItemData* pItemData = (CTreeOptionsItemData*) GetItemData(hItem);
ASSERT(pItemData);
pItemData->m_dwItemData = dwData;
return TRUE;
}
BOOL CTreeOptionsCtrl::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
{
//Clean up any controls currently open we used
if (m_hControlItem)
{
UpdateTreeControlValueFromChildControl(m_hControlItem);
DestroyOldChildControl();
}
//Let the parent class do its thing
return CTreeCtrl::OnMouseWheel(nFlags, zDelta, pt);
}
BOOL CTreeOptionsCtrl::OnDeleteItem(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
*pResult = 0;
//Free up the memory we had allocated in the item data (if needed)
CTreeOptionsItemData* pItemData = (CTreeOptionsItemData*) GetItemData(pNMTreeView->itemOld.hItem);
if (pItemData)
delete pItemData;
return FALSE;
}
void CTreeOptionsCtrl::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags )
{
if (nChar == VK_RIGHT)
{
HTREEITEM hItem = GetSelectedItem();
if (GetItemData(hItem) && m_hControlItem != NULL)
{
// if we have a children and VK_RIGHT -> Focus on it !
CTreeOptionsItemData* pItemData = (CTreeOptionsItemData*) GetItemData(hItem);
if (pItemData->m_pRuntimeClass1->IsDerivedFrom(RUNTIME_CLASS(CTreeOptionsCombo)))
{
if (m_pCombo->IsWindowVisible())
m_pCombo->SetFocus();
}
else if (pItemData->m_pRuntimeClass1->IsDerivedFrom(RUNTIME_CLASS(CTreeOptionsEdit)))
{
if (m_pEdit->IsWindowVisible())
m_pEdit->SetFocus();
}
else if (pItemData->m_pRuntimeClass1->IsDerivedFrom(RUNTIME_CLASS(CTreeOptionsDateCtrl)))
{
if (m_pDateTime->IsWindowVisible())
m_pDateTime->SetFocus();
}
else if (pItemData->m_pRuntimeClass1->IsDerivedFrom(RUNTIME_CLASS(CTreeOptionsIPAddressCtrl)))
{
if (m_pIPAddress->IsWindowVisible())
m_pIPAddress->SetFocus();
}
else if (pItemData->m_pRuntimeClass1->IsDerivedFrom(RUNTIME_CLASS(CTreeOptionsBrowseButton)))
{
if (m_pButton->IsWindowVisible())
m_pButton->SetFocus();
}
else
{
//Pass on to the parent since we didn't handle it
CTreeCtrl::OnKeyDown(nChar, nRepCnt, nFlags);
}
}
else
{
//Pass on to the parent since we didn't handle it
CTreeCtrl::OnKeyDown(nChar, nRepCnt, nFlags);
}
}
else
{
//Pass on to the parent since we didn't handle it
CTreeCtrl::OnKeyDown(nChar, nRepCnt, nFlags);
}
}
void CTreeOptionsCtrl::HandleCheckBox(HTREEITEM hItem, BOOL bCheck)
{
//Turn of redraw to Q all the changes we're going to make here
SetRedraw(FALSE);
//Toggle the state
VERIFY(SetCheckBox(hItem, !bCheck));
//If the item has children, then iterate through them and for all items
//which are check boxes set their state to be the same as the parent
HTREEITEM hChild = GetNextItem(hItem, TVGN_CHILD);
while (hChild)
{
if (IsCheckBox(hChild))
SetCheckBox(hChild, !bCheck);
//Move on to the next item
hChild = GetNextItem(hChild, TVGN_NEXT);
}
//Get the parent item and if it is a checkbox, then iterate through
//all its children and if all the checkboxes are checked, then also
//automatically check the parent. If no checkboxes are checked, then
//also automatically uncheck the parent.
HTREEITEM hParent = GetNextItem(hItem, TVGN_PARENT);
if (hParent && IsCheckBox(hParent))
{
BOOL bNoCheckBoxesChecked = TRUE;
BOOL bAllCheckBoxesChecked = TRUE;
hChild = GetNextItem(hParent, TVGN_CHILD);
while (hChild)
{
if (IsCheckBox(hChild))
{
BOOL bThisChecked;
VERIFY(GetCheckBox(hChild, bThisChecked));
bNoCheckBoxesChecked = bNoCheckBoxesChecked && !bThisChecked;
bAllCheckBoxesChecked = bAllCheckBoxesChecked && bThisChecked;
}
//Move on to the next item
hChild = GetNextItem(hChild, TVGN_NEXT);
}
if (bNoCheckBoxesChecked)
SetCheckBox(hParent, FALSE);
else if (bAllCheckBoxesChecked)
{
SetCheckBox(hParent, FALSE); //gets rid of the semi state
SetCheckBox(hParent, TRUE);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -