treectrl.cpp
来自「A*算法 A*算法 A*算法 A*算法A*算法A*算法」· C++ 代码 · 共 2,196 行 · 第 1/5 页
CPP
2,196 行
/////////////////////////////////////////////////////////////////////////////
// Name: src/msw/treectrl.cpp
// Purpose: wxTreeCtrl
// Author: Julian Smart
// Modified by: Vadim Zeitlin to be less MSW-specific on 10.10.98
// Created: 1997
// RCS-ID: $Id: treectrl.cpp,v 1.208.2.1 2005/12/01 11:05:31 ABX Exp $
// Copyright: (c) Julian Smart
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
// ============================================================================
// declarations
// ============================================================================
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
#pragma implementation "treectrl.h"
#endif
// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#if wxUSE_TREECTRL
#include "wx/msw/private.h"
// include <commctrl.h> "properly"
#include "wx/msw/wrapcctl.h"
#include "wx/msw/missing.h"
// Set this to 1 to be _absolutely_ sure that repainting will work for all
// comctl32.dll versions
#define wxUSE_COMCTL32_SAFELY 0
#include "wx/app.h"
#include "wx/log.h"
#include "wx/dynarray.h"
#include "wx/imaglist.h"
#include "wx/settings.h"
#include "wx/msw/treectrl.h"
#include "wx/msw/dragimag.h"
// macros to hide the cast ugliness
// --------------------------------
// ptr is the real item id, i.e. wxTreeItemId::m_pItem
#define HITEM_PTR(ptr) (HTREEITEM)(ptr)
// item here is a wxTreeItemId
#define HITEM(item) HITEM_PTR((item).m_pItem)
// the native control doesn't support multiple selections under MSW and we
// have 2 ways to emulate them: either using TVS_CHECKBOXES style and let
// checkboxes be the selection status (checked == selected) or by really
// emulating everything, i.e. intercepting mouse and key events &c. The first
// approach is much easier but doesn't work with comctl32.dll < 4.71 and also
// looks quite ugly.
#define wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE 0
// ----------------------------------------------------------------------------
// private functions
// ----------------------------------------------------------------------------
// wrapper for TreeView_HitTest
static HTREEITEM GetItemFromPoint(HWND hwndTV, int x, int y)
{
TV_HITTESTINFO tvht;
tvht.pt.x = x;
tvht.pt.y = y;
return (HTREEITEM)TreeView_HitTest(hwndTV, &tvht);
}
#if !wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE
// wrappers for TreeView_GetItem/TreeView_SetItem
static bool IsItemSelected(HWND hwndTV, HTREEITEM hItem)
{
TV_ITEM tvi;
tvi.mask = TVIF_STATE | TVIF_HANDLE;
tvi.stateMask = TVIS_SELECTED;
tvi.hItem = hItem;
if ( !TreeView_GetItem(hwndTV, &tvi) )
{
wxLogLastError(wxT("TreeView_GetItem"));
}
return (tvi.state & TVIS_SELECTED) != 0;
}
static bool SelectItem(HWND hwndTV, HTREEITEM hItem, bool select = true)
{
TV_ITEM tvi;
tvi.mask = TVIF_STATE | TVIF_HANDLE;
tvi.stateMask = TVIS_SELECTED;
tvi.state = select ? TVIS_SELECTED : 0;
tvi.hItem = hItem;
if ( TreeView_SetItem(hwndTV, &tvi) == -1 )
{
wxLogLastError(wxT("TreeView_SetItem"));
return false;
}
return true;
}
static inline void UnselectItem(HWND hwndTV, HTREEITEM htItem)
{
SelectItem(hwndTV, htItem, false);
}
static inline void ToggleItemSelection(HWND hwndTV, HTREEITEM htItem)
{
SelectItem(hwndTV, htItem, !IsItemSelected(hwndTV, htItem));
}
// helper function which selects all items in a range and, optionally,
// unselects all others
static void SelectRange(HWND hwndTV,
HTREEITEM htFirst,
HTREEITEM htLast,
bool unselectOthers = true)
{
// find the first (or last) item and select it
bool cont = true;
HTREEITEM htItem = (HTREEITEM)TreeView_GetRoot(hwndTV);
while ( htItem && cont )
{
if ( (htItem == htFirst) || (htItem == htLast) )
{
if ( !IsItemSelected(hwndTV, htItem) )
{
SelectItem(hwndTV, htItem);
}
cont = false;
}
else
{
if ( unselectOthers && IsItemSelected(hwndTV, htItem) )
{
UnselectItem(hwndTV, htItem);
}
}
htItem = (HTREEITEM)TreeView_GetNextVisible(hwndTV, htItem);
}
// select the items in range
cont = htFirst != htLast;
while ( htItem && cont )
{
if ( !IsItemSelected(hwndTV, htItem) )
{
SelectItem(hwndTV, htItem);
}
cont = (htItem != htFirst) && (htItem != htLast);
htItem = (HTREEITEM)TreeView_GetNextVisible(hwndTV, htItem);
}
// unselect the rest
if ( unselectOthers )
{
while ( htItem )
{
if ( IsItemSelected(hwndTV, htItem) )
{
UnselectItem(hwndTV, htItem);
}
htItem = (HTREEITEM)TreeView_GetNextVisible(hwndTV, htItem);
}
}
// seems to be necessary - otherwise the just selected items don't always
// appear as selected
UpdateWindow(hwndTV);
}
// helper function which tricks the standard control into changing the focused
// item without changing anything else (if someone knows why Microsoft doesn't
// allow to do it by just setting TVIS_FOCUSED flag, please tell me!)
static void SetFocus(HWND hwndTV, HTREEITEM htItem)
{
// the current focus
HTREEITEM htFocus = (HTREEITEM)TreeView_GetSelection(hwndTV);
if ( htItem )
{
// set the focus
if ( htItem != htFocus )
{
// remember the selection state of the item
bool wasSelected = IsItemSelected(hwndTV, htItem);
if ( htFocus && IsItemSelected(hwndTV, htFocus) )
{
// prevent the tree from unselecting the old focus which it
// would do by default (TreeView_SelectItem unselects the
// focused item)
TreeView_SelectItem(hwndTV, 0);
SelectItem(hwndTV, htFocus);
}
TreeView_SelectItem(hwndTV, htItem);
if ( !wasSelected )
{
// need to clear the selection which TreeView_SelectItem() gave
// us
UnselectItem(hwndTV, htItem);
}
//else: was selected, still selected - ok
}
//else: nothing to do, focus already there
}
else
{
if ( htFocus )
{
bool wasFocusSelected = IsItemSelected(hwndTV, htFocus);
// just clear the focus
TreeView_SelectItem(hwndTV, 0);
if ( wasFocusSelected )
{
// restore the selection state
SelectItem(hwndTV, htFocus);
}
}
//else: nothing to do, no focus already
}
}
#endif // wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE
// ----------------------------------------------------------------------------
// private classes
// ----------------------------------------------------------------------------
// a convenient wrapper around TV_ITEM struct which adds a ctor
#ifdef __VISUALC__
#pragma warning( disable : 4097 ) // inheriting from typedef
#endif
struct wxTreeViewItem : public TV_ITEM
{
wxTreeViewItem(const wxTreeItemId& item, // the item handle
UINT mask_, // fields which are valid
UINT stateMask_ = 0) // for TVIF_STATE only
{
wxZeroMemory(*this);
// hItem member is always valid
mask = mask_ | TVIF_HANDLE;
stateMask = stateMask_;
hItem = HITEM(item);
}
};
// wxVirutalNode is used in place of a single root when 'hidden' root is
// specified.
class wxVirtualNode : public wxTreeViewItem
{
public:
wxVirtualNode(wxTreeItemData *data)
: wxTreeViewItem(TVI_ROOT, 0)
{
m_data = data;
}
~wxVirtualNode()
{
delete m_data;
}
wxTreeItemData *GetData() const { return m_data; }
void SetData(wxTreeItemData *data) { delete m_data; m_data = data; }
private:
wxTreeItemData *m_data;
DECLARE_NO_COPY_CLASS(wxVirtualNode)
};
#ifdef __VISUALC__
#pragma warning( default : 4097 )
#endif
// a macro to get the virtual root, returns NULL if none
#define GET_VIRTUAL_ROOT() ((wxVirtualNode *)m_pVirtualRoot)
// returns true if the item is the virtual root
#define IS_VIRTUAL_ROOT(item) (HITEM(item) == TVI_ROOT)
// a class which encapsulates the tree traversal logic: it vists all (unless
// OnVisit() returns false) items under the given one
class wxTreeTraversal
{
public:
wxTreeTraversal(const wxTreeCtrl *tree)
{
m_tree = tree;
}
// do traverse the tree: visit all items (recursively by default) under the
// given one; return true if all items were traversed or false if the
// traversal was aborted because OnVisit returned false
bool DoTraverse(const wxTreeItemId& root, bool recursively = true);
// override this function to do whatever is needed for each item, return
// false to stop traversing
virtual bool OnVisit(const wxTreeItemId& item) = 0;
protected:
const wxTreeCtrl *GetTree() const { return m_tree; }
private:
bool Traverse(const wxTreeItemId& root, bool recursively);
const wxTreeCtrl *m_tree;
DECLARE_NO_COPY_CLASS(wxTreeTraversal)
};
// internal class for getting the selected items
class TraverseSelections : public wxTreeTraversal
{
public:
TraverseSelections(const wxTreeCtrl *tree,
wxArrayTreeItemIds& selections)
: wxTreeTraversal(tree), m_selections(selections)
{
m_selections.Empty();
if (tree->GetCount() > 0)
DoTraverse(tree->GetRootItem());
}
virtual bool OnVisit(const wxTreeItemId& item)
{
// can't visit a virtual node.
if ( (GetTree()->GetRootItem() == item) && (GetTree()->GetWindowStyle() & wxTR_HIDE_ROOT))
{
return true;
}
#if wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE
if ( GetTree()->IsItemChecked(item) )
#else
if ( ::IsItemSelected(GetHwndOf(GetTree()), HITEM(item)) )
#endif
{
m_selections.Add(item);
}
return true;
}
size_t GetCount() const { return m_selections.GetCount(); }
private:
wxArrayTreeItemIds& m_selections;
DECLARE_NO_COPY_CLASS(TraverseSelections)
};
// internal class for counting tree items
class TraverseCounter : public wxTreeTraversal
{
public:
TraverseCounter(const wxTreeCtrl *tree,
const wxTreeItemId& root,
bool recursively)
: wxTreeTraversal(tree)
{
m_count = 0;
DoTraverse(root, recursively);
}
virtual bool OnVisit(const wxTreeItemId& WXUNUSED(item))
{
m_count++;
return true;
}
size_t GetCount() const { return m_count; }
private:
size_t m_count;
DECLARE_NO_COPY_CLASS(TraverseCounter)
};
// ----------------------------------------------------------------------------
// This class is needed for support of different images: the Win32 common
// control natively supports only 2 images (the normal one and another for the
// selected state). We wish to provide support for 2 more of them for folder
// items (i.e. those which have children): for expanded state and for expanded
// selected state. For this we use this structure to store the additional items
// images.
//
// There is only one problem with this: when we retrieve the item's data, we
// don't know whether we get a pointer to wxTreeItemData or
// wxTreeItemIndirectData. So we always set the item id to an invalid value
// in this class and the code using the client data checks for it and retrieves
// the real client data in this case.
// ----------------------------------------------------------------------------
class wxTreeItemIndirectData : public wxTreeItemData
{
public:
// ctor associates this data with the item and the real item data becomes
// available through our GetData() method
wxTreeItemIndirectData(wxTreeCtrl *tree, const wxTreeItemId& item)
{
for ( size_t n = 0; n < WXSIZEOF(m_images); n++ )
{
m_images[n] = -1;
}
// save the old data
m_data = tree->GetItemData(item);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?