www.gusucode.com > VC+Access工程信息管理系统 > VC+Access工程信息管理系统/gusucode/IMS/lbctrl.cpp

    //Download by http://www.NewXing.com
// lbctrl.cpp

#include "stdafx.h"
#include "lbctrl.h"

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

///////////////////////////////////////////////////////////////////
// CListBoxCtrl

// Constructor.
CListBoxCtrl::CListBoxCtrl() :
   m_bModeFirstColumn(FALSE), m_bModeAnyColumn(FALSE),
   m_nColumnSort(-1), m_bSortAscending(TRUE),
   m_bModeGridLineHorz(FALSE), m_bModeGridLineVert(FALSE)
{
}

// Destructor.
/* virtual */ CListBoxCtrl::~CListBoxCtrl()
{
}

BEGIN_MESSAGE_MAP(CListBoxCtrl, CListCtrl)
   //{{AFX_MSG_MAP(CListBoxCtrl)
   ON_WM_DESTROY()
   //}}AFX_MSG_MAP

#ifdef CLISTBOXCTRL_SORTMODE
   ON_NOTIFY_REFLECT(LVN_COLUMNCLICK, OnColumnclick)
#endif

END_MESSAGE_MAP()

///////////////////////////////////////////////////////////////////
// CListBoxCtrl helper functions

// Does the sent item exist?
BOOL CListBoxCtrl::IsItem(int nItem) const
{
   return GetItemCount() > nItem;
}

// Does the sent column exist?
BOOL CListBoxCtrl::IsColumn(int nCol) const
{
   LV_COLUMN lvc;
   memset(&lvc, 0, sizeof(lvc));
   lvc.mask = LVCF_WIDTH;
   return GetColumn(nCol, &lvc);
}

// Returns the first item that is selected by default.
int CListBoxCtrl::GetSelectedItem(int nStartItem /* = -1 */ ) const
{
   return GetNextItem(nStartItem, LVNI_SELECTED);
}

// Selects the sent item.
BOOL CListBoxCtrl::SelectItem(int nItem) 
{
   return SetItemState(nItem, LVIS_SELECTED, LVIS_SELECTED);
}

// Selects all the items in the control.
BOOL CListBoxCtrl::SelectAll()
{
   BOOL bReturn(TRUE);

   for (int nItem = 0; IsItem(nItem); nItem++) 
      if (! SetItemState(nItem, LVIS_SELECTED, LVIS_SELECTED)) {
         bReturn = FALSE;
         break;
      }

   return bReturn;
}

///////////////////////////////////////////////////////////////////
// CListBoxCtrl mode functions

#if defined CLISTBOXCTRL_FIRSTCOLUMNMODE
void CListBoxCtrl::SetModeFirstColumn(BOOL b /* = TRUE */ )
{
   m_bModeFirstColumn = b;
}
#endif

#if defined CLISTBOXCTRL_ANYCOLUMNMODE
void CListBoxCtrl::SetModeAnyColumn(BOOL b /* = TRUE */ )
{
   m_bModeAnyColumn = b;
}
#endif


#if defined CLISTBOXCTRL_SORTMODE
// handle column clicks.
void CListBoxCtrl::OnColumnclick(NMHDR* pNMHDR, LRESULT* pResult)
{
   NM_LISTVIEW* pNMListView = (NM_LISTVIEW*) pNMHDR;

   // If a different column is being sorted from the last time we
   // sorted, we always start off ascending.
   if (pNMListView->iSubItem != m_nColumnSort)
      m_bSortAscending = TRUE;
   else
      m_bSortAscending = ! m_bSortAscending;

   m_nColumnSort = pNMListView->iSubItem;

   // Now, the only way the CListCtrl can know how to sort is by
   // each item's LPARAM, so we give it the item number.
   for (int nItem = 0; IsItem(nItem); nItem++)
      SetItemData(nItem, nItem);

   // Call the sort routine.
   SortItems(CompareFunc, reinterpret_cast <DWORD> (this));
   *pResult = 0;
}
#endif

#if defined CLISTBOXCTRL_SORTMODE
// This is the function that the base CListCtrl code calls whenever
// it needs to compare two items.
/* static */ int CALLBACK CListBoxCtrl::CompareFunc(LPARAM lParam1,
                                             LPARAM lParam2,
                                             LPARAM lParamSort)
{
   CListBoxCtrl* pListCtrl =
      reinterpret_cast <CListBoxCtrl*> (lParamSort);

   LV_FINDINFO lvi;
   memset(&lvi, 0, sizeof(lvi));
   lvi.flags = LVFI_PARAM;

   lvi.lParam = lParam1;
   int nItem1(pListCtrl->FindItem(&lvi));

   lvi.lParam = lParam2;
   int nItem2(pListCtrl->FindItem(&lvi));

   CString s1(pListCtrl->GetItemText(nItem1,
      pListCtrl->m_nColumnSort));

   CString s2(pListCtrl->GetItemText(nItem2,
      pListCtrl->m_nColumnSort));

   int nReturn(s1.CompareNoCase(s2));

   if (! pListCtrl->m_bSortAscending)
      nReturn = -nReturn;

   return nReturn;
}
#endif

// Override that draws the entire row as selected, instead of just
//the text in the zeroth column.
#if defined CLISTBOXCTRL_ROWMODE
/* virtual */ void CListBoxCtrl::DrawItem(LPDRAWITEMSTRUCT 
                                        lpDrawItemStruct)
{
   // Get the display context for the control.
   CDC* pCDC = CDC::FromHandle(lpDrawItemStruct->hDC);

   // Use mask if there is one.
   UINT uiFlags(ILD_TRANSPARENT);

   // Check to see if this item is selected.
   if (lpDrawItemStruct->itemState & ODS_SELECTED) {
      pCDC->SetTextColor(::GetSysColor(COLOR_HIGHLIGHTTEXT));
      pCDC->SetBkColor(::GetSysColor(COLOR_HIGHLIGHT));
      uiFlags |= ILD_BLEND50;
   }
   else {
      pCDC->SetTextColor(::GetSysColor(COLOR_WINDOWTEXT));
      pCDC->SetBkColor(::GetSysColor(COLOR_WINDOW));
   }

   // Get the image list and draw.
   CImageList* plistImages = GetImageList(LVSIL_SMALL);

   // Get the item image to be displayed.
   LV_ITEM lvi;
   memset(&lvi, 0, sizeof(&lvi));
   lvi.mask = LVIF_IMAGE | LVIF_STATE;
   lvi.iItem = lpDrawItemStruct->itemID;
   GetItem(&lvi);

   // If valid, draw.
   if (plistImages) {
      CPoint ptAt(lpDrawItemStruct->rcItem.left,
         lpDrawItemStruct->rcItem.top);
	  if ( ! plistImages->Draw(pCDC, 0/*lvi.iImage*/, ptAt, uiFlags) ) {
		  int x = 0;
		  x++;
	  }
   }

   #if defined CLISTBOXCTRL_GRIDLINEMODE
   // Create the pen used to draw the gridlines.
   CPen pen(PS_SOLID, 0, ::GetSysColor(COLOR_WINDOWTEXT));
   CPen* penOld = pCDC->SelectObject(&pen);
   #endif

   // Now walk through columns and draw text.
   char szText[256];     // Increase this if you have longer text.
   LV_COLUMN lvc;
   memset(&lvc, 0, sizeof(lvc));
   lvc.mask = LVCF_WIDTH;

   for (int nColumn = 0; GetColumn(nColumn, &lvc); nColumn++) {
      CRect rTextClip;

      // First time.
      if (0 == nColumn) {
         rTextClip.left   = lpDrawItemStruct->rcItem.left +
            (plistImages ? 16 : 0);
         rTextClip.top    = lpDrawItemStruct->rcItem.top;
         rTextClip.right  = lpDrawItemStruct->rcItem.left + lvc.cx;
         rTextClip.bottom = lpDrawItemStruct->rcItem.bottom;
      }
      else {
         // Just "move" the rect to the right.
         rTextClip.left  = rTextClip.right;
         rTextClip.right = rTextClip.left + lvc.cx;
      }

      // Get the text.
      lvi.iItem = lpDrawItemStruct->itemID;
      lvi.mask = LVIF_TEXT;
      lvi.iSubItem = nColumn;
      lvi.pszText = szText;
      lvi.cchTextMax = sizeof(szText);
      GetItem(&lvi);

      // Add ellipses if necessary.
      int nTextCount(lstrlen(lvi.pszText));

      CSize sizText(pCDC->GetOutputTextExtent(lvi.pszText,
         nTextCount));

      // Make the clipping rectangle a little smaller for a gap
      // effect between columns.
      rTextClip.right -= 4;

      if (sizText.cx >= rTextClip.Width()) {

         // Make a shorter string, including "..." that fits.
         CSize sizEllipse = pCDC->GetOutputTextExtent("...", 3);

         // Now start dropping characters at the tail until width
         // is correct.
         while (sizText.cx+sizEllipse.cx > (rTextClip.Width())  &&
           nTextCount > 1) {
            lvi.pszText[--nTextCount] = 0;
            sizText = pCDC->GetOutputTextExtent(lvi.pszText,
               nTextCount);
         }

         // Ok, append "...".
         lvi.pszText[nTextCount] = '.';
         lvi.pszText[nTextCount + 1] = '.';
         lvi.pszText[nTextCount + 2] = '.';
         lvi.pszText[nTextCount + 3] = 0;
      }

      // Restore full rect.
      rTextClip.right += 4;

      // Print the text.
      pCDC->ExtTextOut(rTextClip.left + 2, rTextClip.top + 1,
         ETO_CLIPPED | ETO_OPAQUE, &rTextClip, lvi.pszText,
         lstrlen(lvi.pszText), NULL);

      #if defined CLISTBOXCTRL_GRIDLINEMODE
      // Draw the gridlines.
      if (GetModeGridLineHorz()) {
         pCDC->MoveTo(rTextClip.left + 1, rTextClip.bottom - 1);
         pCDC->LineTo(rTextClip.right - 1, rTextClip.bottom - 1);
      }

      if (GetModeGridLineVert()) {
         pCDC->MoveTo(rTextClip.right - 1, rTextClip.bottom - 1);
         pCDC->LineTo(rTextClip.right - 1, rTextClip.top);
      }
      #endif
   }

   // Reset colors if necessary.
   if (lpDrawItemStruct->itemState & ODS_SELECTED) {
      pCDC->SetTextColor(::GetSysColor(COLOR_WINDOWTEXT));
      pCDC->SetBkColor(::GetSysColor(COLOR_WINDOW));
   }

   // If focused draw focus rect.
   if (lpDrawItemStruct->itemState & ODS_FOCUS) {
      CRect rTextClip(lpDrawItemStruct->rcItem);
      rTextClip.left += (plistImages ? 16 : 0);
      pCDC->DrawFocusRect(&rTextClip);
   }

   // We must leave the display context as we found it.
   #if defined CLISTBOXCTRL_GRIDLINEMODE
   pCDC->SelectObject(penOld);
   #endif
}
#endif

// Fix color "bug".
/* virtual */ void CListBoxCtrl::PreSubclassWindow() 
{
   #if ! defined CLISTBOXCTRL_ROWMODE

   if ((GetTextBkColor() == CLR_NONE  ||
      GetTextBkColor() == CLR_DEFAULT)  &&
     ::GetSysColor(COLOR_WINDOW) == ::GetSysColor(COLOR_3DFACE)) {

      // If the current background is lighter than average, we use
      // white (unless it's already white - then use light gray).
      if (GetRValue(::GetSysColor(COLOR_3DFACE)) +
        GetGValue(::GetSysColor(COLOR_3DFACE)) +
        GetBValue(::GetSysColor(COLOR_3DFACE)) > (255 * 3 / 2)) {

         if (::GetSysColor(COLOR_3DFACE) == RGB(255,255,255))
            SetTextBkColor(RGB(192,192,192));
         else
            SetTextBkColor(RGB(255,255,255));
      }
      else {
         // Current background is darker than average.  Use dark
         // gray (unless it's already dark gray, then use black).
         if (::GetSysColor(COLOR_3DFACE) == RGB(83,83,83))
            SetTextBkColor(RGB(0,0,0));
         else
            SetTextBkColor(RGB(83,83,83));
      }
   }
   #endif

   // Call the base class member.
   CListCtrl::PreSubclassWindow();
}

#if defined CLISTBOXCTRL_COLUMNWIDTHS
// Call this from your view's OnInitialUpdate() method.  Pass it
// something like "Software\\MyCompany\\MyApp\\CustomerColWidths".
void CListBoxCtrl::SetModeColumnWidths(const CString& s)
{
   m_sColumnWidthsKey = s;
 
   // Be sure we really want to do this.
   if (! m_sColumnWidthsKey.IsEmpty()) {
      HKEY hKey(NULL);
      DWORD dwDisp(0L);

      // First open the key (if it's there).
      if (ERROR_SUCCESS == ::RegOpenKeyEx(HKEY_CURRENT_USER,
        m_sColumnWidthsKey, NULL, KEY_READ, &hKey)) {

         // If key must there, open columns until you run out.
         LONG lnReturn(ERROR_SUCCESS);

         for (int nCol = 0; ERROR_SUCCESS == lnReturn; nCol++) {
            CString sValueName;
            sValueName.Format("Column%d", nCol);
            DWORD dwType(0L);
            DWORD dwData(0L);
            DWORD dwDataSize(sizeof(DWORD));
            BYTE* pData = reinterpret_cast<BYTE*> (&dwData);
            
            if (ERROR_SUCCESS == (lnReturn = ::RegQueryValueEx(
              hKey, sValueName, NULL, &dwType, pData,
              &dwDataSize))) 

               SetColumnWidth(nCol, dwData);
         }

         ::RegCloseKey(hKey);
         hKey = NULL;
      }
   }
}
#endif

// When the control is about to be destroyed, we write the column
// widths to the Registry key specified by the client.
void CListBoxCtrl::OnDestroy() 
{
   CListCtrl::OnDestroy();
   
   #if defined CLISTBOXCTRL_COLUMNWIDTHS

   if (! m_sColumnWidthsKey.IsEmpty()) {
      HKEY hKey(NULL);
      DWORD dwDisp(0L);

      ::RegCreateKeyEx(HKEY_CURRENT_USER, m_sColumnWidthsKey,
        NULL, "MyListCtrlClass", 0L, KEY_WRITE, NULL, &hKey,
        &dwDisp);

      for (int nCol = 0; IsColumn(nCol); nCol++) {
         CString sValueName;
         sValueName.Format("Column%d", nCol);
         int nData(GetColumnWidth(nCol));
         
         const BYTE* pData = 
            reinterpret_cast<const BYTE*> (&nData);

         ::RegSetValueEx(hKey, sValueName, NULL, REG_DWORD, pData,
            sizeof(DWORD));
      }

      ::RegCloseKey(hKey);
      hKey = NULL;
   }
   #endif
}