CListCtrl自繪


一:custom draw

自行繪制 ClistCtrl 的列表項,可以利用列表框的 NM_CUSTOMDRAW 消息,該消息由控件向它的父窗口發送,告訴父窗口它的繪圖操作。

    如果繪圖操作不需要父窗口參與,可以使用該控件的 ON_NOTIFY_REFLECT 宏處理它的 NM_CUSTOMDRAW 消息。

    它的處理函數的參數中包含 NMHDR,在 CUSTOMDRAW 的通知下 NMHDR 可以被轉換成為 NMLVCUSTOMDRAW 結構,該結構包含了列表控件中需要自繪區域的全部信息:

typedef struct tagNMLVCUSTOMDRAW  {      NMCUSTOMDRAW   nmcd;                // 包含客戶自繪控件信息的結構      COLORREF             clrText;              // 列表視圖顯示文字的顏色      COLORREF             clrTextBk;          // 列表視圖顯示文字的背景色  } NMLVCUSTOMDRAW, *LPNMLVCUSTOMDRAW;

NMCUSTOMDRAW 結構定義如下:

typedef struct tagNMCUSTOMDRAWINFO  {      NMHDR     hdr;                     // 含有通知信息的 NMHDR 結構      DWORD   dwDrawStage;       // 目前繪制的步驟      HDC         hdc;                     // 設備上下文句柄      RECT        rc;                       // 繪制的區域      DWORD    dwItemSpec;        // 繪制項的說明      UINT        uItemState;          // 當前項的狀態      LPARAM   lItemlParam           // 應用程序定義的數據  } NMCUSTOMDRAW, FAR * LPNMCUSTOMDRAW;

    NMLVCUSTOMDRAW.nmcd.dwDrawStage 字段,它主要包含以下幾個枚舉值:

  • CDDS_PREPAINT:表示在繪畫前階段。
  • CDDS_ITEMPREPAINT:表示在列表項的繪畫前階段。
  • CDDS_SUBITEM:表示繪制子項。
  • CDDS_ITEM:表示要繪制項的信息已經可用。

    自繪時,可以通過處理以上幾個繪畫階段的通知來實現。

 

例子詳細步驟:

  1. 利用 MFC AppWizard( exe ) 創建一個新工程 TestCListCtrl。在向導的第 ( 1 ) 步選擇單文檔模式,而后使用默認值來創建,最后獲得一個支持文檔視圖的應用程序。
  2. 在 ClassView 中添加新的類 CCoolListCtrl,類型為 MFC Class,基類為CListCtrl。獲得兩個新文件 CCoolListCtrl.cpp 和 CCoolListCtrl.h。
  3. 在類 CCoolListCtrl 中添加成員變量 m_imagelist 用於存儲圖像列表。
  4. 添加 NM_CUSTOMDRAW 消息的處理函數 OnCustomDraw。

    CCoolListCtrl.h 文件中:  afx_msg void OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult);//消息函數聲明

    CCoolListCtrl.cpp 文件中:  // 消息映射宏中添加:ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, OnCustomDraw)

    BEGIN_MESSAGE_MAP(CCoolListCtrl, CListCtrl)      //{{AFX_MSG_MAP(CCoolListCtrl)      ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, OnCustomDraw)      //}}AFX_MSG_MAP  END_MESSAGE_MAP()

    // 消息處理函數實現:

     

    /////////////////////////////////////////////////////////////////////////////  // CCoolListCtrl message handlers

    void CCoolListCtrl::OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult)  {      // TODO: Add your control notification handler code here      NMLVCUSTOMDRAW* pLVCD = reinterpret_cast <NMLVCUSTOMDRAW*> ( pNMHDR );

        *pResult = 0;      // Request item-specific notifications if this is the      // beginning of the paint cycle.

        if ( CDDS_PREPAINT  == pLVCD-> nmcd.dwDrawStage )      {          *pResult = CDRF_NOTIFYITEMDRAW;      }      else if ( CDDS_ITEMPREPAINT == pLVCD-> nmcd.dwDrawStage )      {          // This is the beginning of an item 's paint cycle.          LVITEM rItem;          int  nItem = static_cast <int> ( pLVCD-> nmcd.dwItemSpec );          CDC* pDC = CDC::FromHandle ( pLVCD-> nmcd.hdc );          COLORREF crBkgnd;          BOOL bListHasFocus;          CRect  rcItem;          CRect  rcText;          CString  sText;          UINT uFormat;

            bListHasFocus = ( this->GetSafeHwnd() == ::GetFocus() );

            // Get the image index and selected/focused state of the          // item being drawn.          ZeroMemory ( &rItem, sizeof(LVITEM) );          rItem.mask  = LVIF_IMAGE | LVIF_STATE;          rItem.iItem = nItem;          rItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;          this->GetItem ( &rItem );

            // Get the rect that holds the item 's icon.          this->GetItemRect ( nItem, &rcItem, LVIR_ICON );

            // Draw the icon.          uFormat = ILD_TRANSPARENT;

            if ( ( rItem.state & LVIS_SELECTED ) && bListHasFocus )              uFormat |= ILD_FOCUS;

            m_imagelist.Draw ( pDC, rItem.iImage, rcItem.TopLeft(), uFormat );

            // Get the rect that bounds the text label.          this->GetItemRect ( nItem, rcItem, LVIR_LABEL ); //把這行去掉就沒有文字.

            // Draw the background of the list item. Colors are selected          // according to the item 's state.

            if ( rItem.state & LVIS_SELECTED )          {              if ( bListHasFocus )              {                  crBkgnd = GetSysColor ( COLOR_HIGHLIGHT );                  pDC-> SetTextColor ( GetSysColor ( COLOR_HIGHLIGHTTEXT ));              }              else              {                  crBkgnd = GetSysColor ( COLOR_BTNFACE );                  pDC-> SetTextColor ( GetSysColor ( COLOR_BTNTEXT ));              }          }          else          {              crBkgnd = GetSysColor ( COLOR_WINDOW );              pDC-> SetTextColor ( GetSysColor ( COLOR_BTNTEXT ));          }

            // Draw the background & prep the DC for the text drawing. Note          // that the entire item RECT is filled in, so this emulates the full-          // row selection style of normal lists.          pDC-> FillSolidRect ( rcItem, crBkgnd );          pDC-> SetBkMode ( TRANSPARENT );

            // Tweak the rect a bit for nicer-looking text alignment.          rcText = rcItem;          // Draw the text.          sText = this->GetItemText ( nItem, 0 );

            pDC-> DrawText ( sText, CRect::CRect(rcText.left+3,rcText.top,rcText.right,rcText.bottom+60), DT_VCENTER );

            // Draw a focus rect around the item if necessary.          if ( bListHasFocus && ( rItem.state & LVIS_FOCUSED ))          {              pDC-> DrawFocusRect ( rcItem );          }

            *pResult = CDRF_SKIPDEFAULT; // We 've painted everything.      }  }

  5. 在視圖類 CTestCListCtrlView 中添加成員變量 m_ListCtrl,類型為 CCoolListCtrl。
  6. 定義 WM_CREATE 消息的處理函數 CTestCListCtrlView ::Create,用於創建 CCoolListCtrl 控件,代碼如下:

    //創建列表控件:自繪樣式、沒有列頭部、處理通知  m_ListCtrl.Create(LVS_OWNERDRAWFIXED | LVS_NOCOLUMNHEADER | LBS_NOTIFY, CRect(0,0,400,200), this, IDC_LISTCTRL );

    // 可以使用 m_ListCtrl.SetExtendedStyle 設置擴展樣式

    // 用自己編寫的函數設置圖像列表

    m_ListCtrl.SetImagelist(IDB_IMAGE);   

    // 用自己編寫的函數設置列表項的行高,方法見文章《CListCtrl行高的修改》  m_ListCtrl.SetItemHeight(36); 
    // 插入項

    m_ListCtrl.InsertItem(0, "Monroeville", 0);   m_ListCtrl.InsertItem(1, "Hartford", 1);   m_ListCtrl.InsertItem(2, "Redmond", 2);

  7. 設置圖像列表的函數:首先將作為圖像列表的bmp文件導入到工程資源中,uBitmap是其資源ID

    BOOL CCoolListCtrl::SetImagelist(UINT uBitmap)  {      m_imagelist.DeleteImageList();      m_imagelist.Create(32, 32, ILC_COLOR24|ILC_MASK, 8, 1);      CBitmap bitmap;      bitmap.LoadBitmap(uBitmap);      m_imagelist.Add(&bitmap, RGB(255,0,255));

        return TRUE;  }

二 ,Owner Draw
 
三,其它技巧:
1.禁用頭部移動
BOOL CHeaderCtrlEx::OnChildNotify(UINT msg,WPARAM wp,LPARAM lp,LRESULT* pRes)    {    NMHDR& nmh = *(NMHDR*)lp; if (nmh.code == HDN_BEGINTRACKA || nmh.code == HDN_BEGINTRACKW) { if (m_bLocked) return *pRes=TRUE; // eat message to disallow sizing } else if(nmh.code == HDN_DIVIDERDBLCLICKA || nmh.code == HDN_DIVIDERDBLCLICKW) { if (m_bLocked) return *pRes=TRUE; // eat message to disallow sizing } return   CHeaderCtrl::OnChildNotify(msg,wp,lp,pRes);    }
 
或者 :
BOOL CMyListCtrl::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult) { HD_NOTIFY *pHDN = (HD_NOTIFY*)lParam;  switch(((NMHDR*)lParam)->code)  {  case HDN_BEGINTRACKW: case HDN_BEGINTRACKA: //if (pHDN->iItem == 3)   //指定哪一列 { *pResult = TRUE;  return TRUE; } }
return CListCtrl::OnNotify(wParam, lParam, pResult); }
2.改變CHeaderCtrl高度
添加消息ON_MESSAGE(HDM_LAYOUT, OnLayout)
LRESULT CStkHeaderCtrl::OnLayout( WPARAM wParam, LPARAM lParam )   { LRESULT lResult = CHeaderCtrl::DefWindowProc(HDM_LAYOUT, 0, lParam); HD_LAYOUT &hdl = *(HD_LAYOUT*)lParam; RECT *prc = hdl.prc; WINDOWPOS *pwpos = hdl.pwpos;
//表頭高度為原來1.5倍,如果要動態修改表頭高度的話,將1.5設成一個全局變量 int nHeight = pwpos->cy * 1.5;   pwpos->cy = nHeight; prc->top = nHeight; return lResult; }
 

或者用下面的方法:

CHeaderCtrl* pHeaderCtrl =(CHeaderCtrl*)m_ListCtrl.GetHeaderCtrl();    pHeaderCtrl->EnableWindow( FALSE ) ; (#add 此法禁用了頭部,往往沒什么用,因為經常需要點擊頭部排序)

from:http://blog.csdn.net/weiqubo/article/details/7014882


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM