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

📄 catlistbox.cpp

📁 vc++的部分比较经典的源码
💻 CPP
📖 第 1 页 / 共 3 页
字号:
// CatListBox.cpp : Category Listbox implementation file.
//
// Author: Joshua Quick
//
// Features:
// -  Organizes listbox strings by categories.
// -  Categories can be opened to reveal their strings or closed to hide them.
// -  Category items can have checkboxes.
// -  Can store a DWORD with each category item.
//
// Do the following to add this control to a dialog:
// 1) Add a listbox to a dialog resource.
// 2) Setup listbox resource for "Owner Draw: Fixed" and check "Has Strings".
// 3) Create CCatListBox member variable in dialog by hand or wizard.
// *) If created by hand, then call <variable>.SubclassDlgItem(LISTBOX_ID,this).
//
/////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "CatListBox.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif


//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CCatListBox::CCatListBox()
{
   m_mapCat.clear();
   m_bShowStates = false;
   m_bDoDraw     = true;
}

CCatListBox::~CCatListBox()
{
   ResetCategoryInfo();
}


//////////////////////////////////////////////////////////////////////
// Message mapping.
//////////////////////////////////////////////////////////////////////

BEGIN_MESSAGE_MAP(CCatListBox, CListBox)
   //{{AFX_MSG_MAP(CCatListBox)
   ON_WM_LBUTTONDOWN()
   ON_WM_KEYDOWN()
   ON_WM_LBUTTONDBLCLK()
   //}}AFX_MSG_MAP
END_MESSAGE_MAP()


//////////////////////////////////////////////////////////////////////
// Message/event functions.
//////////////////////////////////////////////////////////////////////

// Draws strings into listbox.
void CCatListBox::DrawItem( LPDRAWITEMSTRUCT lpDrawItemStruct )
{
   // Do not continue if draw flag is FALSE.
   // Works better than LockWindowUpdate() which prevents draws for all UI in app.
   if (!m_bDoDraw)
      return;

   // Validate argument.
   if (!lpDrawItemStruct || ((int)(lpDrawItemStruct->itemID) < 0))
      return;

   // Get list item's category info.
   CatListBoxCatInfo* pCatInfo = (CatListBoxCatInfo*)lpDrawItemStruct->itemData;
   if (!pCatInfo)
      return;

   // Setup device context.
   CDC* pDC = CDC::FromHandle( lpDrawItemStruct->hDC );

   // Determine if list item is highlighted.
   bool bHighlight = ((lpDrawItemStruct->itemState & ODS_SELECTED) &&
                      !(GetStyle() & LBS_NOSEL) && IsWindowEnabled());

   // Draw category's background.
   CRect    rcValue = lpDrawItemStruct->rcItem;
   COLORREF crNew   = GetSysColor( bHighlight ? COLOR_HIGHLIGHT : COLOR_WINDOW );
   COLORREF crOldBk = pDC->SetBkColor( crNew );
   CBrush   brWindow( crNew );
   pDC->FillRect( rcValue, &brWindow );

   // Determine position of category's button or item's checkbox.
   CRect rcButton( rcValue );
   rcButton.top    += Y_MARGIN;
   rcButton.left   += X_MARGIN;
   rcButton.bottom -= Y_MARGIN + 1;
   rcButton.right   = rcButton.left + rcButton.Height();

   // Draw category/item.
   if (lpDrawItemStruct->itemID == pCatInfo->iListIndex) {
      // Draw category's background.
      rcValue.bottom--;
      crNew = GetSysColor( COLOR_3DFACE );
      if (!bHighlight) {
         pDC->SetBkColor( crNew );
         CBrush brBackGround( crNew );
         pDC->FillRect( rcValue, &brBackGround );
      }

      // Draw category's button frame.
      pDC->DrawFrameControl( rcButton, DFC_BUTTON, DFCS_BUTTONPUSH );

      // Draw "-" in button.
      crNew = GetSysColor( IsWindowEnabled() ? COLOR_BTNTEXT : COLOR_GRAYTEXT );
      int iX = rcButton.left + X_MARGIN;
      int iY = rcButton.top + (rcButton.Height() / 2);
      for (; iX < (rcButton.right - X_MARGIN); iX++)
         pDC->SetPixel( iX, iY, crNew );

      // Draw "|" in button if category is open, therefore forming a "+".
      if (!pCatInfo->bIsOpen) {
         iX = rcButton.left + (rcButton.Width() / 2);
         for (iY = rcButton.top + X_MARGIN; iY < (rcButton.bottom - X_MARGIN); iY++)
            pDC->SetPixel( iX, iY, crNew );
      }
   }
   else if (m_bShowStates) {
      // Draw item's checkbox according to its current state.
      CatListBoxStlListIter   iter;
      int                     iCount = (lpDrawItemStruct->itemID - pCatInfo->iListIndex) - 1;
      for (iter = pCatInfo->lstItems.begin(); iter != pCatInfo->lstItems.end(); iter++) {
         if (iCount <= 0) {
            if (0 == (*iter).iState)         // Draw a checked checkbox.
               pDC->DrawFrameControl( rcButton, DFC_BUTTON, DFCS_BUTTONCHECK | DFCS_FLAT );
            else if (1 == (*iter).iState)    // Draw an unchecked checkbox.
               pDC->DrawFrameControl( rcButton, DFC_BUTTON, DFCS_BUTTONCHECK | DFCS_FLAT | DFCS_CHECKED );
            break;
         }
         iCount--;
      }
   }

   // Draw text.
   if (!IsWindowEnabled())
      crNew = GetSysColor( COLOR_GRAYTEXT );
   else if (bHighlight)
      crNew = GetSysColor( COLOR_HIGHLIGHTTEXT );
   else
      crNew = GetSysColor( COLOR_WINDOWTEXT );
   COLORREF crOldTxt = pDC->SetTextColor( crNew );
   CString  sText;
   GetText( lpDrawItemStruct->itemID, sText );
   int iTextPos = lpDrawItemStruct->rcItem.left;
   if (m_bShowStates || (lpDrawItemStruct->itemID == pCatInfo->iListIndex))
      iTextPos = rcButton.right;
   iTextPos += X_MARGIN;
   pDC->TextOut( iTextPos, lpDrawItemStruct->rcItem.top + Y_MARGIN, sText );

   // If this item has the focus, then draw a frame around it.
   if ((GetFocus() == this) && IsWindowEnabled()  &&
       (lpDrawItemStruct->itemState & ODS_FOCUS)) {
      pDC->DrawFocusRect( &(lpDrawItemStruct->rcItem) );
   }

   // Restore DC's old settings.
   pDC->SetBkColor( crOldBk );
   pDC->SetTextColor( crOldTxt );
}

// Opens/closes categories or checks/unchecks items.
void CCatListBox::OnLButtonDown( UINT nFlags, CPoint point )
{
   CatListBoxCatInfo*   pCatInfo;
   CString              sCategory;
   CRect                rcValue;
   int                  iHeight;
   int                  iListIndex;

   // Get listbox's height.
   GetWindowRect( rcValue );
   iHeight = rcValue.Height();

   // Determine if a category button has been clicked.
   for (iListIndex = GetTopIndex(); iListIndex < GetCount(); iListIndex++) {
      // Get item's category info.
      pCatInfo = (CatListBoxCatInfo*)GetItemData( iListIndex );
      if (!pCatInfo)
         continue;

      // Calculate button position.
      GetItemRect( iListIndex, rcValue );
      rcValue.top    += Y_MARGIN;
      rcValue.bottom -= Y_MARGIN + 1;
      rcValue.left   += X_MARGIN;
      rcValue.right   = rcValue.left + rcValue.Height();

      // Stop now if reached lower displayable bound of listbox.
      if (rcValue.top >= iHeight)
         break;

      // Determine if item's button was clicked.
      if (rcValue.PtInRect( point )) {
         GetText( pCatInfo->iListIndex, sCategory );
         SetCurSel( iListIndex );
         if (iListIndex == pCatInfo->iListIndex) {
            // Open/close category.
            SetCategoryState( (LPCTSTR)sCategory, !(pCatInfo->bIsOpen) );
         }
         else if (m_bShowStates) {
            // Check/uncheck item's checkbox if it has a checkbox.
            int iItemIndex = (iListIndex - pCatInfo->iListIndex) - 1;
            int iState = GetCategoryItemState( (LPCTSTR)sCategory, iItemIndex );
            if (0 == iState)
               SetCategoryItemState( (LPCTSTR)sCategory, iItemIndex, 1 );
            else if (1 == iState)
               SetCategoryItemState( (LPCTSTR)sCategory, iItemIndex, 0 );
         }
         break;      // Done. State has been updated.
      }
   }
   CListBox::OnLButtonDown( nFlags, point );
}

// Opens/closes categories.
void CCatListBox::OnLButtonDblClk( UINT nFlags, CPoint point )
{
   CatListBoxCatInfo*   pCatInfo;
   CString              sCategory;
   CRect                rcValue;
   int                  iHeight;
   int                  iListIndex;

   // Get listbox's height.
   GetWindowRect( rcValue );
   iHeight = rcValue.Height();

   // Determine if a category has been double clicked.
   for (iListIndex = GetTopIndex(); iListIndex < GetCount(); iListIndex++) {
      // Get listbox item's category info.
      pCatInfo = (CatListBoxCatInfo*)GetItemData( iListIndex );
      if (!pCatInfo)
         continue;

      // Skip item if it's not a category.
      if (iListIndex != pCatInfo->iListIndex)
         continue;

      // Determine if category has been double clicked.
      GetItemRect( iListIndex, rcValue );
      if (rcValue.top >= iHeight)
         break;         // Stop searching. Lower listbox bound has been reached.
      if (rcValue.PtInRect( point )) {
         GetText( iListIndex, sCategory );
         SetCurSel( iListIndex );
         SetCategoryState( (LPCTSTR)sCategory, !(pCatInfo->bIsOpen) );
         break;         // Done. Category has been opened/closed.
      }
   }
   CListBox::OnLButtonDblClk( nFlags, point );
}

// Opens/closes categories or checks/unchecks items when the space bar is pressed.
void CCatListBox::OnKeyDown( UINT nChar, UINT nRepCnt, UINT nFlags )
{
   if (VK_SPACE == nChar) {
      int iListIndex = GetCurSel();
      if (iListIndex != LB_ERR) {
         CatListBoxCatInfo* pInfo = (CatListBoxCatInfo*)GetItemData( iListIndex );
         if (pInfo && (LB_ERR != (int)pInfo)) {
            CString  sCategory;
            GetText( pInfo->iListIndex, sCategory );
            if (iListIndex == pInfo->iListIndex) {
               // Open/close category.
               SetCategoryState( (LPCTSTR)sCategory, !(pInfo->bIsOpen) );
            }
            else if (m_bShowStates) {
               // Check/uncheck item if it has a checkbox.
               int iItemIndex = (iListIndex - pInfo->iListIndex) - 1;
               int iState = GetCategoryItemState( (LPCTSTR)sCategory, iItemIndex );
               if (0 == iState)
                  SetCategoryItemState( (LPCTSTR)sCategory, iItemIndex, 1 );
               else if (1 == iState)
                  SetCategoryItemState( (LPCTSTR)sCategory, iItemIndex, 0 );
            }
         }
      }
   }
   CListBox::OnKeyDown( nChar, nRepCnt, nFlags );
}


//////////////////////////////////////////////////////////////////////
// Add functions.
//////////////////////////////////////////////////////////////////////

// Adds a new category to listbox. (Category name must be unique!)
HRESULT CCatListBox::AddCategory( LPCTSTR pCategory )
{
   CatListBoxStlMapIter    iter;
   CatListBoxCatInfo*      pCatInfo;
   CatListBoxCatInfo*      pTempInfo;

   // Validate argument.
   if (!pCategory)
      return E_POINTER;
   if (_tcslen( pCategory ) <= 0)
      return E_INVALIDARG;
   if (m_mapCat.end() != m_mapCat.find(CString(pCategory))) // Category name must be unique!
      return E_INVALIDARG;

   // Add category to STL map.
   try {
      pCatInfo = new CatListBoxCatInfo;
      if (!pCatInfo)
         return E_FAIL;
      pCatInfo->bIsOpen    = false;
      pCatInfo->iListIndex = -1;
      m_mapCat.insert( CatListBoxStlMap::value_type( CString(pCategory), pCatInfo ) );
   }
   catch (...) {
      ASSERT(0);
      return E_FAIL;
   }

   // Add category to listbox.
   if (LBS_SORT & GetStyle()) {
      for (iter = m_mapCat.begin(); iter != m_mapCat.end(); iter++) {
         pTempInfo = (*iter).second;
         if (!pTempInfo || (pTempInfo == pCatInfo))
            continue;

⌨️ 快捷键说明

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