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

📄 treelistview.h

📁 这是一本学习 window编程的很好的参考教材
💻 H
📖 第 1 页 / 共 2 页
字号:
         break;
      case SB_PAGERIGHT :                     // Scroll left with a click to the background of the scrollbar
         nCurPos = min(nCurPos + cxClient, nScrollMax);
         break;
      case SB_THUMBPOSITION :                 // Scroll by moving the scrollbutton with the mouse
      case SB_THUMBTRACK :                    // Drop the scrollbarbutton
         // Check for illegal positions and correct them (out of the scrollbar?)
         if( nPos == 0 ) {
            nCurPos = 0;
         }
         else {
            nCurPos = min( StretchWidth(nPos, nWidthLine), nScrollMax);
         }
      }

      // Move the scrollbarbutton to the position (graphically)
      SetScrollPos(SB_HORZ, nCurPos, TRUE);
      m_nOffset = -nCurPos;

      // Smoothly Scroll the Tree control
      RECT rcTree;
      m_ctrlTree.GetClientRect(&rcTree);
      m_ctrlTree.ScrollWindowEx(nPrevPos - nCurPos, 0, NULL, NULL, NULL, NULL, SW_INVALIDATE);

      RECT rcHeader;
      GetClientRect(&rcClient);
      m_ctrlHeader.GetClientRect(&rcHeader);

      if( rcTree.right - rcTree.left != 0 ) {
         int iVSWidth = ::GetSystemMetrics(SM_CXVSCROLL) + 1;
         m_ctrlHeader.SetWindowPos(NULL, m_nOffset, 0, abs(m_nOffset) + iVSWidth + rcTree.right - rcTree.left, rcHeader.bottom - rcHeader.top, SWP_SHOWWINDOW);
      }

      // Redraw the treecontrol so you can see the scrolling
      m_ctrlTree.Invalidate();
      return 0;
   }

   // Tree control

   LRESULT OnTreeNcDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
   {
      // Clean up memory on destruction
      m_ctrlTree.DeleteAllItems();
      bHandled = FALSE;
      return 0;
   }
   LRESULT OnTreeKillFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
   {
      // HACK: Fix the TreeView focus paint problem
      m_ctrlTree.Invalidate();
      bHandled = FALSE;
      return 0;
   }
   LRESULT OnTreeFixButtonHit(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
   {
      // If a click is to the right of the label then we're still clicking on the item...
      // Handling TVM_HITTEST would be a lot nicer, but the TreeView control doesn't 
      // actually use it internally :-(
      RECT rcClient;
      GetClientRect(&rcClient);
      int x = GET_X_LPARAM(lParam) - m_nOffset;
      int y = GET_Y_LPARAM(lParam);
      if( x > rcClient.right - rcClient.left ) x = rcClient.right - 40;
      TVHITTESTINFO hti;
      hti.pt.x = x;
      hti.pt.y = y;
      m_ctrlTree.HitTest(&hti);
      if( hti.flags == TVHT_ONITEMRIGHT ) {
         RECT rc;
         m_ctrlTree.GetItemRect(hti.hItem, &rc, TRUE);
         x = rc.left;
      }
      lParam = MAKELONG(x, y);
      return m_ctrlTree.DefWindowProc(uMsg, wParam, lParam);
   }
   LRESULT OnTreeItemInsert(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
   {
      HTREEITEM hItem = (HTREEITEM) m_ctrlTree.DefWindowProc(uMsg, wParam, lParam);
      if( hItem == NULL ) return (LRESULT) hItem;

      // Create a new item
      tMapItem* pVal;
      ATLTRY(pVal = new tMapItem);
      ATLASSERT(pVal);
      LPTLVITEM pItem;
      int nHeaders = m_ctrlHeader.GetItemCount();
      for( int i = 0; i < nHeaders; i++ ) {
         ATLTRY(pItem = new TLVITEM);
         ATLASSERT(pItem);
         ::ZeroMemory(pItem, sizeof(TLVITEM));
         pVal->Add( pItem );
      }
      // Add the new item
      m_mapItems.Add(hItem, pVal);
      // Then add the item structure...
      if( nHeaders > 0 ) {
         // Convert TVITEM into a TLVITEM
         LPTVINSERTSTRUCT pTVIS = reinterpret_cast<LPTVINSERTSTRUCT>(lParam);
         ATLASSERT(pTVIS);
         TLVITEM itm = { 0 };
         itm.iSubItem = 0;
         if( pTVIS->item.mask & TVIF_TEXT ) {
            ATLASSERT(pTVIS->item.pszText != LPSTR_TEXTCALLBACK); // Not supported
            itm.mask |= TLVIF_TEXT;
            itm.pszText = pTVIS->item.pszText;
         }
         SetSubItem(hItem, &itm);
      }
      
      return (LRESULT) hItem;
   }
   LRESULT OnTreeItemDelete(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled)
   {
      LPNMTREEVIEW pnmt = (LPNMTREEVIEW) pnmh;
      HTREEITEM hItem = pnmt->itemOld.hItem;
      tMapItem* pVal = m_mapItems.Lookup(hItem);
      ATLASSERT(pVal);
      if( pVal == NULL ) return 0;
      int cnt = pVal->GetSize();
      for( int i = 0; i < cnt; i++ ) {
         LPTLVITEM pItem = (*pVal)[i];
         _DeleteSubItem(pItem);
      }
      ATLTRY(delete pVal);
      m_mapItems.Remove(hItem);
      bHandled = FALSE;
      return 0;
   }
   LRESULT OnTreeItemExpanded(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& bHandled)
   {
      // Auto-scale the first column to the largest tree-item
      if( m_ctrlHeader.GetItemCount() > 0 ) {
         int cx = 0;
         HTREEITEM hItem = m_ctrlTree.GetNextItem(NULL, TVGN_FIRSTVISIBLE);
         while( hItem != NULL ) {
            RECT rc;
            m_ctrlTree.GetItemRect(hItem, &rc, TRUE);
            if( rc.left > cx ) cx = rc.left;
            hItem = m_ctrlTree.GetNextItem(hItem, TVGN_NEXTVISIBLE);
         }
         HDITEM hdr = { 0 };
         hdr.mask = HDI_WIDTH;
         m_ctrlHeader.GetItem(0, &hdr);
         cx = max(hdr.cxy, cx);
         if( hdr.cxy != cx ) {
            hdr.cxy = cx;
            m_ctrlHeader.SetItem(0, &hdr);
         }
      }
      bHandled = FALSE;
      return 0;
   }
   LRESULT OnTreeSetColor(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
   {
      LRESULT lRes = m_ctrlTree.DefWindowProc(uMsg, wParam, lParam);
      T* pT = static_cast<T*>(this);
      BOOL bDummy;
      pT->OnSettingChange(0,0,0,bDummy);
      return lRes;
   }

   // Header control

   LRESULT OnHeaderItemInsert(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
   {
      ATLASSERT((int)wParam==m_ctrlHeader.GetItemCount()); // Only supports appending right now!
      // When adding a header we need to place a TLVITEM in
      // each tree item as well...
      LRESULT lRes = m_ctrlHeader.DefWindowProc(uMsg, wParam, lParam);
      if( lRes != -1 ) {
         LPTLVITEM pItem;
         for( int i = 0; i < m_mapItems.GetSize(); i++ ) {
            tMapItem* pVal = m_mapItems.GetValueAt(i);
            ATLTRY(pItem = new TLVITEM);
            ATLASSERT(pItem);
            ::ZeroMemory(pItem, sizeof(TLVITEM));
            pVal->Add( pItem );
         }
         _CalcColumnSizes();
      }
      return lRes;
   }
   LRESULT OnHeaderItemDelete(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
   {
      // Deleting a column header also means cleaning up all
      // the TLVITEM structures in each of the column's sub-items.
      for( int i = 0; i < m_mapItems.GetSize(); i++ ) {
         tMapItem* pVal = m_mapItems.GetValueAt(i);
         ATLASSERT(pVal);
         LPTLVITEM pItem = (*pVal)[ (int) wParam ];
         ATLASSERT(pItem);
         pVal->RemoveAt( (int) wParam );
         _DeleteSubItem(pItem);
      }
      bHandled = FALSE;
      return 0;
   }
   LRESULT OnHeaderItemChanged(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& bHandled)
   {
      // Reposition first header columns
      BOOL bDummy;
      OnTreeItemExpanded(0, NULL, bDummy);
      // Recalc column sizes
      _CalcColumnSizes();
      // Repaint, just in case...
      T* pT = static_cast<T*>(this);
      pT->UpdateLayout();     

      bHandled = FALSE;
      return 0;
   }
   LRESULT OnHeaderBeginDrag(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled)
   {
      LPNMHEADER pnmhd = (LPNMHEADER) pnmh;
      if( pnmhd->iItem == 0 ) return TRUE; // Cannot drag first column!
      bHandled = FALSE;
      return 0;
   }
   LRESULT OnHeaderEndDrag(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled)
   {
      LPNMHEADER pnmhd = (LPNMHEADER) pnmh;

      // Cannot drag first column, really!
      // Bug in MS control requires this extra check.
      if( pnmhd->iItem == 0 ) return TRUE; 
      RECT rcItem;
      m_ctrlHeader.GetItemRect(0, &rcItem);
      DWORD dwPos = ::GetMessagePos();
      POINT pt = { GET_X_LPARAM(dwPos), GET_Y_LPARAM(dwPos) };
      ScreenToClient(&pt);
      if( pt.x <= rcItem.right ) return TRUE; // Cannot re-order first column

      // Need to reposition the header
      T* pT = static_cast<T*>(this);
      pT->UpdateLayout();     

      bHandled = FALSE;
      return 0;
   }

   // Helper methods

   static long StretchWidth(long nWidth, long nMeasure)
   {
      return ((nWidth / nMeasure) + 1) * nMeasure;
   }

   // Custom draw

   DWORD OnPrePaint(int /*idCtrl*/, LPNMCUSTOMDRAW lpNMCustomDraw)
   {
      if( lpNMCustomDraw->hdr.hwndFrom != m_ctrlTree ) return CDRF_DODEFAULT;
      ::SetViewportOrgEx(lpNMCustomDraw->hdc, m_nOffset, 0, NULL);
      return CDRF_NOTIFYITEMDRAW;   // We need per-item notifications
   }
   DWORD OnItemPrePaint(int /*idCtrl*/, LPNMCUSTOMDRAW lpNMCustomDraw)
   {
      if( lpNMCustomDraw->hdr.hwndFrom != m_ctrlTree ) return CDRF_DODEFAULT;

      // Reset the focus because it will be drawn by us
      m_iItemState = lpNMCustomDraw->uItemState;
      lpNMCustomDraw->uItemState &= ~(CDIS_FOCUS | CDIS_SELECTED);

      // Remember the drawing rectangle of the item so we can draw it ourselves
      m_ctrlTree.GetItemRect( (HTREEITEM)lpNMCustomDraw->dwItemSpec, &m_rcItem, TRUE);
      m_rcItem.right = max(lpNMCustomDraw->rc.right, m_cxHeader);

      return CDRF_NOTIFYPOSTPAINT;   // We need more notifications
   }
   DWORD OnItemPostPaint(int /*idCtrl*/, LPNMCUSTOMDRAW lpNMCustomDraw)
   {
      if( lpNMCustomDraw->hdr.hwndFrom != m_ctrlTree ) return CDRF_DODEFAULT;
      T* pT = static_cast<T*>(this);
      LPNMTVCUSTOMDRAW pCustomDraw = reinterpret_cast<LPNMTVCUSTOMDRAW>(lpNMCustomDraw);
      pT->DrawTreeItem( pCustomDraw, m_iItemState, m_rcItem);
      return CDRF_DODEFAULT;
   }

   // Overridables

   void UpdateLayout()
   {
      ATLASSERT(::IsWindow(m_ctrlTree));
      ATLASSERT(::IsWindow(m_ctrlHeader));

      // FIX: Horizontal scrollbar fix by Nail Kaipov
      m_nOffset = 0;
      if( GetStyle() & WS_HSCROLL ) {
         m_nOffset = -GetScrollPos(SB_HORZ); // read scrollbar position
      }

      // Reposition the header and tree control
      RECT rcClient;
      GetClientRect(&rcClient);
      if( m_ctrlHeader.GetStyle() & WS_VISIBLE ) {
         HDLAYOUT hdl = { 0 };
         WINDOWPOS wpos;
         hdl.prc = &rcClient;
         hdl.pwpos = &wpos;
         m_ctrlHeader.Layout(&hdl);
         ATLASSERT(wpos.y==0);
         ATLASSERT(rcClient.top!=0); // We assume that HDLAYOUT is updated (MSDN docs doesn't mention it)
         m_ctrlTree.SetWindowPos(HWND_TOP, &rcClient, SWP_NOACTIVATE | SWP_NOZORDER);
         m_ctrlHeader.SetWindowPos(HWND_TOP, wpos.x, wpos.y, wpos.cx, wpos.cy, SWP_NOACTIVATE);
      }
      else {
         m_ctrlTree.SetWindowPos(HWND_TOP, &rcClient, SWP_NOACTIVATE | SWP_NOZORDER);
      }

      _CalcColumnSizes();

      // FIX: Repaint entire control.
      // NOTE:Cannot just use Invalidate() since WS_CLIPCHILDREN may not be there!!!
      m_ctrlHeader.Invalidate();
      m_ctrlTree.Invalidate();
   }

   void DrawTreeItem(LPNMTVCUSTOMDRAW lptvcd, UINT iState, const RECT& rcItem)
   {
      CDCHandle dc = lptvcd->nmcd.hdc;
      HTREEITEM hItem = (HTREEITEM) lptvcd->nmcd.dwItemSpec;
      
      tMapItem* pVal = m_mapItems.Lookup(hItem);
      if( pVal == NULL ) return;

      // NOTE: Having an ImageList attached to the TreeView control seems
      //       to produce some extra WM_ERASEBKGND msgs, which we can use to
      //       optimize the painting...
      CImageList il = m_ctrlTree.GetImageList(TVSIL_NORMAL);

      // If the item had focus then draw it
      // NOTE: Only when images are used (see note above)
      if( (iState & CDIS_FOCUS) != 0 && !il.IsNull() ) {
         RECT rcFocus = rcItem;
         rcFocus.left = 1;
         dc.SetTextColor(::GetSysColor(COLOR_BTNTEXT));
         dc.DrawFocusRect(&rcFocus);
      }

      // If it's selected, paint the selection background
      if( iState & CDIS_SELECTED ) {
         RECT rcHigh = rcItem;
         dc.FillSolidRect(&rcHigh, ::GetSysColor(COLOR_HIGHLIGHT));
      }
      else if( il.IsNull() ) {
         RECT rcHigh = rcItem;
         dc.FillSolidRect(&rcHigh, lptvcd->clrTextBk);
      }

      // Always write text with background
      dc.SetBkMode(OPAQUE);
      dc.SetBkColor(::GetSysColor((iState & CDIS_SELECTED) != 0 ? COLOR_HIGHLIGHT : COLOR_WINDOW));

      // Draw all columns of the item
      RECT rc = rcItem;
      int cnt = pVal->GetSize();
      for( int i = 0; i < cnt; i++ ) {
         LPTLVITEM pItem = (*pVal)[i];
         ATLASSERT(pItem);
         
         if( i != 0 ) rc.left = m_rcColumns[i].left;
         rc.right = m_rcColumns[i].right;
         
         if( pItem->mask & TLVIF_IMAGE ) {
            ATLASSERT(!il.IsNull());
            int cx, cy;
            il.GetIconSize(cx, cy);
            il.DrawEx(
               pItem->iImage, 
               dc, 
               rc.left, rc.top, 
               min(cx, rc.right - rc.left), cy,
               CLR_NONE, CLR_NONE,
               ILD_TRANSPARENT);
            rc.left += cx;
         }

         if( pItem->mask & TLVIF_TEXT ) {

            rc.left += 2;

            COLORREF clrText = lptvcd->clrText;
            if( pItem->mask & TLVIF_TEXTCOLOR ) clrText = pItem->clrText;
            if( iState & CDIS_SELECTED ) clrText = ::GetSysColor(COLOR_HIGHLIGHTTEXT);
            dc.SetTextColor(clrText);

            CFont font;
            HFONT hOldFont = NULL;
            if( pItem->mask & TLVIF_STATE ) {
               LOGFONT lf;
               ::GetObject(m_ctrlTree.GetFont(), sizeof(LOGFONT), &lf);
               if( pItem->state & TLVIS_BOLD ) lf.lfWeight += FW_BOLD - FW_NORMAL;
               if( pItem->state & TLVIS_ITALIC ) lf.lfItalic = TRUE;
               if( pItem->state & TLVIS_UNDERLINE ) lf.lfUnderline = TRUE;
               if( pItem->state & TLVIS_STRIKEOUT ) lf.lfStrikeOut = TRUE;
               font.CreateFontIndirect(&lf);
               ATLASSERT(!font.IsNull());
               hOldFont = dc.SelectFont(font);
            }

            UINT format = pItem->mask & TLVIF_FORMAT ? pItem->format : 0;
         
            dc.DrawText(pItem->pszText, 
               -1, 
               &rc, 
               DT_VCENTER | DT_SINGLELINE | DT_WORD_ELLIPSIS | format);

            if( pItem->mask & TLVIF_STATE ) dc.SelectFont(hOldFont);
         }
      }
   }
};


class CTreeListViewCtrl : public CTreeListViewImpl<CTreeListViewCtrl>
{
public:
   DECLARE_WND_SUPERCLASS(_T("WTL_TreeListView"), GetWndClassName())  
};


#endif // !defined(AFX_TREELISTVIEW_H__20010510_B3AE_CB5E_0BEB_0080AD509054__INCLUDED_)

⌨️ 快捷键说明

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