⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 treelistview.h

📁 这是一本学习 window编程的很好的参考教材
💻 H
📖 第 1 页 / 共 2 页
字号:
#if !defined(AFX_TREELISTVIEW_H__20010510_B3AE_CB5E_0BEB_0080AD509054__INCLUDED_)
#define AFX_TREELISTVIEW_H__20010510_B3AE_CB5E_0BEB_0080AD509054__INCLUDED_

#pragma once

/////////////////////////////////////////////////////////////////////////////
// CTreeListView - A TreeView with additional columns
//
// Written by Bjarke Viksoe (bjarke@viksoe.dk)
// Copyright (c) 2001-2002 Bjarke Viksoe.
//
// Partly implemented from a MFC CTreeListView control by Gerolf K黨nel
// available at www.codeproject.com.
// Horizontal scrolling supplied by Oleg Reabciuc (olegr@compudava.com).
// Nail Kaipov fixed the horizontal scrollbar code (roof@crypt.nsk.ru).
//
// This code may be used in compiled form in any way you desire. This
// file may be redistributed by any means PROVIDING it is 
// not sold for profit without the authors written consent, and 
// providing that this notice and the authors name is included. 
//
// This file is provided "as is" with no expressed or implied warranty.
// The author accepts no liability if it causes any damage to you or your
// computer whatsoever. It's free, so don't hassle me about it.
//
// Beware of bugs.
//


#ifndef __cplusplus
  #error ATL requires C++ compilation (use a .cpp suffix)
#endif

#ifndef __ATLAPP_H__
  #error TreeListView.h requires atlapp.h to be included first
#endif

#ifndef __ATLCTRLS_H__
  #error TreeListView.h requires atlctrls.h to be included first
#endif

#if (_WIN32_IE < 0x0400)
  #error TreeListView.h requires _WIN32_IE >= 0x0400
#endif


// The TreeListView item structure
typedef struct tagTLVITEM
{
   UINT     mask;
   int      iSubItem;
   UINT     state;
   UINT     stateMask;
   UINT     format;
   LPTSTR   pszText;
   UINT     cchTextMax;
   int      iImage;
   COLORREF clrText;
   COLORREF clrBack;
   LPARAM   lParam;
} TLVITEM, *LPTLVITEM;

// TreeListView mask flags
#define TLVIF_TEXT               0x0001
#define TLVIF_IMAGE              0x0002
#define TLVIF_PARAM              0x0004
#define TLVIF_STATE              0x0008
#define TLVIF_FORMAT             0x0010
#define TLVIF_TEXTCOLOR          0x0020

// TreeListView format flags
#define TLVIFMT_LEFT             0x00000000
#define TLVIFMT_CENTER           0x00000001
#define TLVIFMT_RIGHT            0x00000002

// TreeListView state flags
#define TLVIS_BOLD               0x0001
#define TLVIS_ITALIC             0x0002
#define TLVIS_UNDERLINE          0x0004
#define TLVIS_STRIKEOUT          0x0008


template< class T, class TBase = CWindow, class TWinTraits = CControlWinTraits >
class ATL_NO_VTABLE CTreeListViewImpl : 
   public CWindowImpl< T, TBase, TWinTraits >,
   public CCustomDraw< T >
{
public:
   typedef CTreeListViewImpl< T , TBase, TWinTraits > thisClass;

   DECLARE_WND_SUPERCLASS(NULL, TBase::GetWndClassName())

   CContainedWindowT< CTreeViewCtrl > m_ctrlTree;
   CContainedWindowT< CHeaderCtrl > m_ctrlHeader;
   //
   typedef CSimpleArray< TLVITEM* > tMapItem;
   CSimpleMap< HTREEITEM, tMapItem* > m_mapItems;
   CSimpleArray< RECT > m_rcColumns;
   //
   CFont m_fontHeader;
   LONG m_cxHeader;
   LONG m_nOffset;
   //
   UINT m_iItemState;
   RECT m_rcItem;

   CTreeListViewImpl() : 
      m_cxHeader(0),
      m_nOffset(0)
   { 
   }

   // Operations

   BOOL SubclassWindow(HWND hWnd)
   {
      ATLASSERT(m_hWnd==NULL);
      ATLASSERT(::IsWindow(hWnd));
      BOOL bRet = CWindowImpl< T, TBase, TWinTraits >::SubclassWindow(hWnd);
      if( bRet ) _Init();
      return bRet;
   }
   BOOL SetSubItem(HTREEITEM hItem, const LPTLVITEM pItem)
   {
      ATLASSERT(::IsWindow(m_hWnd));
      ATLASSERT(hItem);
      ATLASSERT(!::IsBadReadPtr(pItem, sizeof(TLVITEM)));
      if( pItem->iSubItem < 0 || pItem->iSubItem >= m_ctrlHeader.GetItemCount() ) return FALSE;

      LPTLVITEM pItemT = _GetSubItem(hItem, pItem->iSubItem);
      ATLASSERT(pItemT);
      if( pItemT == NULL ) return FALSE;

      // Copy attributes from caller's TLVITEM to internally
      // stored TLVITEM structure.
      if( pItem->mask & TLVIF_TEXT ) {
         if( pItemT->mask & TLVIF_TEXT ) ATLTRY(delete [] pItemT->pszText);
         ATLTRY(pItemT->pszText = new TCHAR[ ::lstrlen(pItem->pszText)+1 ]);
         ::lstrcpy(pItemT->pszText, pItem->pszText);
         pItemT->mask |= TLVIF_TEXT;
      }
      if( pItem->mask & TLVIF_IMAGE ) {
         pItemT->iImage = pItem->iImage;
         pItemT->mask |= TLVIF_IMAGE;
      }
      if( pItem->mask & TLVIF_PARAM ) {
         pItemT->lParam = pItem->lParam;
         pItemT->mask |= TLVIF_PARAM;
      }
      if( pItem->mask & TLVIF_FORMAT ) {
         pItemT->format = pItem->format;
         pItemT->mask |= TLVIF_FORMAT;
      }
      if( pItem->mask & TLVIF_STATE ) {
         pItemT->state &= ~pItem->stateMask;
         pItemT->state |= (pItem->state & pItem->stateMask);
         pItemT->mask |= TLVIF_STATE;
      }
      if( pItem->mask & TLVIF_TEXTCOLOR ) {
         pItemT->clrText = pItem->clrText;
         pItemT->mask |= TLVIF_TEXTCOLOR;
      }

      return TRUE;
   }
   BOOL GetSubItem(HTREEITEM hItem, LPTLVITEM pItem)
   {
      ATLASSERT(::IsWindow(m_hWnd));
      ATLASSERT(hItem);
      ATLASSERT(!::IsBadWritePtr(pItem, sizeof(TLVITEM)));
      LPTLVITEM pItemT = _GetSubItem(hItem, pItem->iSubItem);      
      if( pItemT == NULL ) return FALSE;
      // Copy item data
      UINT mask = pItem->mask;
      if( mask & TLVIF_TEXT ) {
         ATLASSERT(!::IsBadWritePtr(pItem->pszText, pItem->cchTextMax));
         ::lstrcpyn( pItem->pszText, pItemT->pszText == NULL ? _T("") : pItemT->pszText, pItem->cchTextMax );
      }
      if( mask & TLVIF_IMAGE ) pItem->iImage = pItemT->iImage;
      if( mask & TLVIF_FORMAT ) pItem->format = pItemT->format;
      if( mask & TLVIF_STATE ) {
         pItem->state &= ~pItem->stateMask;
         pItem->state |= pItemT->state & pItem->stateMask;
      }
      if( mask & TLVIF_TEXTCOLOR ) pItem->clrText = pItemT->clrText;
      if( mask & TLVIF_PARAM ) pItem->lParam = pItemT->lParam;     
      return TRUE;
   }
   BOOL SetSubItemText(HTREEITEM hItem, int nSubItem, LPCTSTR pstrString)
   {
      ATLASSERT(::IsWindow(m_hWnd));
      ATLASSERT(hItem);
      ATLASSERT(!::IsBadStringPtr(pstrString, (UINT)-1));
      TLVITEM itm = { 0 };
      itm.iSubItem = nSubItem;
      itm.mask = TLVIF_TEXT;
      itm.pszText = const_cast<LPTSTR>(pstrString);
      return SetSubItem(hItem, &itm);
   }
   BOOL GetSubItemText(HTREEITEM hItem, int nSubItem, LPTSTR pstrString, UINT cchMax)
   {
      ATLASSERT(::IsWindow(m_hWnd));
      ATLASSERT(hItem);
      ATLASSERT(!::IsBadWritePtr(pstrString,cchMax));
      LPTLVITEM pItem = _GetSubItem(hItem, nSubItem);
      if( pItem == NULL ) return FALSE;
      ::lstrcpyn(pstrString, pItem->pszText, cchMax);
      return TRUE;
   }
   CTreeViewCtrl GetTreeControl() const
   {
      ATLASSERT(::IsWindow(m_ctrlTree));
      return m_ctrlTree;
   }
   CHeaderCtrl GetHeaderControl() const
   {
      ATLASSERT(::IsWindow(m_ctrlHeader));
      return m_ctrlHeader;
   }

   // Implementation

   void _Init()
   {
      ATLASSERT(::IsWindow(m_hWnd));

      // This is a Platform SDK define which we need
#ifndef TVS_NOHSCROLL
      const UINT TVS_NOHSCROLL = 0x8000;
#endif

      // Create the tree control
      // Thanks to Nicola Tufarelli for suggesting using the GetDlgCtrlID() to
      // preserve the original control ID...
      DWORD dwStyle = GetStyle();
      UINT nID = GetDlgCtrlID();
      m_ctrlTree.Create(this, 1, m_hWnd, &rcDefault, NULL, dwStyle, 0, nID);
      ATLASSERT(m_ctrlTree.IsWindow());
      m_ctrlTree.ModifyStyle(0, TVS_NOHSCROLL | TVS_FULLROWSELECT);  // we need these

      // Create the header control
      dwStyle = WS_CHILD | WS_VISIBLE | HDS_BUTTONS | HDS_HORZ | HDS_DRAGDROP;
      m_ctrlHeader.Create(this, 2, m_hWnd, &rcDefault, NULL, dwStyle);
      ATLASSERT(m_ctrlHeader.IsWindow());

      SendMessage(WM_SETTINGCHANGE);

      T* pT = static_cast<T*>(this);
      pT->UpdateLayout();

      // FIX: When used in a view...
      m_ctrlTree.ShowWindow(SW_SHOW);
      m_ctrlHeader.ShowWindow(SW_SHOW);
   }
   LPTLVITEM _GetSubItem(HTREEITEM hItem, int iSubItem)
   {
      ATLASSERT(hItem);
      if( iSubItem<0 || iSubItem>m_ctrlHeader.GetItemCount() ) return NULL;
      tMapItem* pVal = m_mapItems.Lookup(hItem);
      ATLASSERT(pVal);
      ATLASSERT(iSubItem < pVal->GetSize());
      if( pVal == NULL ) return NULL;
      if( iSubItem >= pVal->GetSize() ) return NULL;
      return (*pVal)[iSubItem];
   }
   void _DeleteSubItem(const LPTLVITEM pItem)
   {
      ATLASSERT(!::IsBadReadPtr(pItem, sizeof(TLVITEM)));
      if( pItem->mask & TLVIF_TEXT ) ATLTRY(delete [] pItem->pszText);
      ATLTRY(delete pItem);
   }
   void _CalcColumnSizes()
   {
      // Keep track of header sizes
      m_rcColumns.RemoveAll();
      m_cxHeader = 0;
      int nHeaders = m_ctrlHeader.GetItemCount();
      for( int i = 0; i < nHeaders; i++ ) {
         RECT rc;
         m_ctrlHeader.GetItemRect(i, &rc);
         m_rcColumns.Add(rc);
         m_cxHeader += rc.right - rc.left;
      }

      // FIX: Nail Kaipov fixed the horizontal scrollbar code
      // If the width of all headers is bigger than the width of the client-area 
      // of the TreeView, then the Scrollbar is to be enabled
      RECT rcClient;
      GetClientRect(&rcClient);
      if( GetStyle() & WS_VSCROLL ) rcClient.right += ::GetSystemMetrics(SM_CXHTHUMB);
      LONG cxClient = (rcClient.right - rcClient.left);
      if( m_cxHeader - cxClient >= 0 ) {
         SCROLLINFO si;
         si.cbSize = sizeof(si);
         si.fMask = SIF_ALL;
         si.nMax  = m_cxHeader;
         si.nMin  = 0;
         si.nPage = cxClient;
         si.nPos  = GetScrollPos(SB_HORZ);   // Preserve scroller position
         SetScrollInfo(SB_HORZ, &si, TRUE);  // Setup scrollbar params
         ModifyStyle(0, WS_HSCROLL, SWP_FRAMECHANGED);
         m_nOffset = -si.nPos;    // Save scrollbar position for correct drawing
         if( si.nPos ) {          // Scroll position is non-zero. code is stolen from OnHScroll()
            RECT rcHeader, rcTree;
            m_ctrlHeader.GetClientRect(&rcHeader);
            m_ctrlTree.GetClientRect(&rcTree);
            m_ctrlHeader.SetWindowPos(NULL, 
               -si.nPos, 
               0, 
               abs(si.nPos) + ::GetSystemMetrics(SM_CXVSCROLL) + 1 + rcTree.right - rcTree.left,
               rcHeader.bottom - rcHeader.top, 
               SWP_SHOWWINDOW);
         }
      }
      else {
         SetScrollPos(SB_HORZ, 0, TRUE);
         ModifyStyle(WS_HSCROLL, 0, SWP_FRAMECHANGED);
         m_nOffset = 0;
         Invalidate();
      }
   }

   // Message map and handlers

   BEGIN_MSG_MAP( thisClass )
      MESSAGE_HANDLER(WM_CREATE, OnCreate)
      MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBkGnd)
      CHAIN_MSG_MAP( CCustomDraw< T > )
      MESSAGE_HANDLER(WM_SIZE, OnSize)
      MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus)
      MESSAGE_HANDLER(WM_HSCROLL, OnHScroll)
      MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange)
      NOTIFY_CODE_HANDLER(TVN_DELETEITEMA, OnTreeItemDelete)
      NOTIFY_CODE_HANDLER(TVN_DELETEITEMW, OnTreeItemDelete)
      NOTIFY_CODE_HANDLER(TVN_ITEMEXPANDEDA, OnTreeItemExpanded)
      NOTIFY_CODE_HANDLER(TVN_ITEMEXPANDEDW, OnTreeItemExpanded)
      NOTIFY_CODE_HANDLER(HDN_ITEMCHANGEDA, OnHeaderItemChanged)
      NOTIFY_CODE_HANDLER(HDN_ITEMCHANGEDW, OnHeaderItemChanged)
      NOTIFY_CODE_HANDLER(NM_RELEASEDCAPTURE, OnHeaderItemChanged)
      NOTIFY_CODE_HANDLER(HDN_BEGINDRAG, OnHeaderBeginDrag)
      NOTIFY_CODE_HANDLER(HDN_ENDDRAG, OnHeaderEndDrag)
      FORWARD_NOTIFICATIONS()
   ALT_MSG_MAP(1) // Tree
      MESSAGE_HANDLER(WM_KILLFOCUS, OnTreeKillFocus)
      MESSAGE_HANDLER(WM_NCDESTROY, OnTreeNcDestroy)
      MESSAGE_HANDLER(WM_LBUTTONDOWN, OnTreeFixButtonHit)
      MESSAGE_HANDLER(WM_LBUTTONDBLCLK, OnTreeFixButtonHit)
      MESSAGE_HANDLER(TVM_INSERTITEM, OnTreeItemInsert)
      MESSAGE_HANDLER(TVM_SETBKCOLOR, OnTreeSetColor)
      MESSAGE_HANDLER(TVM_SETTEXTCOLOR, OnTreeSetColor)
   ALT_MSG_MAP(2) // Header
      MESSAGE_HANDLER(HDM_INSERTITEM, OnHeaderItemInsert)
      MESSAGE_HANDLER(HDM_DELETEITEM, OnHeaderItemDelete)
   END_MSG_MAP()

   LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
   {
      // Do not allow the TreeView control to initialize here! 
      // We are creating new child controls ourselves in the _Init() method.
      _Init();
      return 0;
   }
   LRESULT OnSettingChange(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
   {
      if( !m_fontHeader.IsNull() ) m_fontHeader.DeleteObject();
      NONCLIENTMETRICS ncm = { 0 };
      ncm.cbSize = sizeof(ncm);
      ::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0);
      m_fontHeader.CreateFontIndirect(&ncm.lfMenuFont);
      m_ctrlHeader.SetFont(m_fontHeader);
     
      Invalidate();
      return 0;
   }
   LRESULT OnSetFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
   {
      m_ctrlTree.SetFocus();
      return 0;
   }
   LRESULT OnSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
   {
      T* pT = static_cast<T*>(this);
      pT->UpdateLayout();     
      return 0;
   }
   LRESULT OnEraseBkGnd(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
   {
      return 1; // Children fill entire client area
   }
   LPARAM OnHScroll(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
   {  
      // Thanks to Oleg Reabciuc for providing the horizontal scrolling
      // support for this control

      int nSBCode = (int) LOWORD(wParam);
      int nPos = (int) HIWORD(wParam);
      
      RECT rcClient;
      m_ctrlTree.GetClientRect(&rcClient);

      int cxClient = abs(rcClient.right - rcClient.left);   // One Page
      const int nWidthLine = 6;               // Microsoft's line-step in a CListCtrl, got from MFC - sourcecode
      int nCurPos = GetScrollPos(SB_HORZ);    // Current scrollingposition
      int nPrevPos = nCurPos;                 // Save current scrolling position for calculating

      int nScrollMin;                         // Minimum scrolling value
      int nScrollMax;                         // Maximum scrolling value
      GetScrollRange(SB_HORZ, &nScrollMin, &nScrollMax);

      // Check which kind of scoll is wanted
      switch( nSBCode ) {
      case SB_LEFT :                          // Scoll to left most position
         nCurPos = 0;
         break;
      case SB_RIGHT :                         // Scroll to right most position
         nCurPos = nScrollMax;
         break;
      case SB_LINELEFT :                      // Scroll left with the button
         nCurPos = max(nCurPos - nWidthLine, 0);
         break;
      case SB_LINERIGHT :                     // Scroll right with the button
         nCurPos = min(nCurPos + nWidthLine, nScrollMax);
         break;
      case SB_PAGELEFT :                      // Scroll left with a click to the background of the scrollbar
         nCurPos = max(nCurPos - cxClient, 0);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -