1 怎樣隱藏ListCtrl列表頭的排序小三角形

在創(chuàng)建控件是加入|LVS_NOSORTHEADER風(fēng)格即可。

一下是用法總結(jié):

本文根據(jù)本人在項(xiàng)目中的應(yīng)用,來(lái)談?wù)凜ListCtrl的部分用法及技巧。當(dāng)初學(xué)習(xí)時(shí),查了很多資料,零零碎碎的作了些記錄,現(xiàn)在主要是來(lái)做個(gè)總結(jié),方便以后查閱。主要包括以下十三點(diǎn)內(nèi)容:基本操作、獲取選中行的行號(hào)、復(fù)選框操作、動(dòng)態(tài)設(shè)置選中行的字體顏色、設(shè)置選中行的背景顏色、禁止拖動(dòng)表頭、讓第一列居中顯示、設(shè)置行高與字體、虛擬列表技術(shù)、點(diǎn)擊表頭時(shí)進(jìn)行歸類、向上與向下移動(dòng)、動(dòng)態(tài)調(diào)整大小問題、避免閃爍問題。

      分為兩篇來(lái)進(jìn)行總結(jié)。本篇重點(diǎn)總結(jié):基本操作獲取選中行的行號(hào)復(fù)選框操作、動(dòng)態(tài)設(shè)置選中行的字體顏色設(shè)置選中行的背景顏色

  1、基本操作

     分別從下面四點(diǎn)來(lái)介紹CListCtrl的基本操作:

     ①設(shè)置列表視圖顯示方式

      Ⅰ. CListCtrl有四種樣式:LVS_ICON、LVS_SMALLICON、LVS_LIST、LSV_REPORT,可通過控件屬性來(lái)設(shè)置。本文所述均為L(zhǎng)SV_REPORT屬性。

      Ⅱ. 擴(kuò)展樣式:

      常用的擴(kuò)展樣式有三種:LVS_EX_FULLROWSELECT、LVS_EX_GRIDLINES、LVS_EX_CHECKBOXES,分別對(duì)應(yīng)作用 選中某行時(shí)使正行高亮、設(shè)置網(wǎng)格線、item前生成Ckeckbox控件。

      使用SetExtendedStyle(style)函數(shù)設(shè)置擴(kuò)展樣式,使用GetExtendedStyle()函數(shù)獲取樣式,如:               

1
2
3
4
5
// Set list extend style
    DWORD dwStyle = GetExtendedStyle();
    dwStyle |= LVS_EX_FULLROWSELECT;
    dwStyle |= LVS_EX_GRIDLINES;
    SetExtendedStyle(dwStyle);

       Ⅲ. 使用CListView時(shí),需要在PreCreateWindow()函數(shù)中添加  cs.style | =  LVS_REPORT;

來(lái)將其設(shè)置為L(zhǎng)VS_REPORT風(fēng)格,否則插入無(wú)效。還用另一種方法來(lái)設(shè)置風(fēng)格,即在OnInitialUpate()中獲取CListCtrl控制權(quán),然后修改風(fēng)格,如下所示:

                      CListCtrl &theCtrl =GetListCtrl();

                      theCtrl.ModifyStyle(0, LVS_REPORT);

     ②插入操作

        先插入列:

                       int InsertColumn( int nCol, LPCTSTR lpszColumnHeading, int nFormat, int nWidth, int nSubItem)

插入列時(shí),可指明列號(hào)、列名稱、列名稱顯示樣式,列寬等信息。對(duì)于列號(hào)為0的那一列,始終是靠左顯示,后面會(huì)有修改使其劇中顯示的方法,其他列通過設(shè)置nFormat屬性可以居中顯示。

1
2
3
4
5
6
7
// Init column
    CString strColumn;
    strColumn.LoadString(strName);
    CRect listCtrlRect;
    GetWindowRect(&listCtrlRect);
    ScreenToClient(&listCtrlRect);
    InsertColumn(0, strColumn, 0, listCtrlRect.Width());

        插入行:

                       int InsertItem( int nItem, LPCTSTR lpszItem )

直接插入一行,nItem指明行號(hào),lpszItem指明該行第0列的信息。

       設(shè)置信息:

                       BOOL SetItemText(int nItem,  int nSubItem, LPCTSTR lpszText )

設(shè)置第nItem行nSubItem列的信息(nItem:0,1,2,3……; nSubItem:1,2,3……)

     ③刪除操作

       有三個(gè)操作函數(shù):

                       BOOL DeleteAllItems()  -------刪除所有的行

                       BOOL DeleteItem(nItem) --------刪除某一行

                       BOOL DeleteColumn(nCol) -----刪除某一列

     ④獲取/設(shè)置屬性函數(shù)

      有很多函數(shù)了,就不一一介紹了。常用的有

                      int GetItemCount() -------- 獲取已插入信息的行數(shù)

                      BOOL SetItemState(int iLink, UINTstate, UINTstateMask ) ---------設(shè)置行狀態(tài),如高亮顯示等

等等

 2、獲取選中行的行號(hào)

       獲取選中行的行號(hào),然后對(duì)該行進(jìn)行相關(guān)處理,這點(diǎn)在編程中用的非常多。 

       當(dāng)鼠標(biāo)單擊item時(shí),控件向父窗口發(fā)送NM_CLICK消息,其響應(yīng)函數(shù)為OnNMClickXXXX(NMHDR *pNMHDR, LRESULT *pResult),在該函數(shù)下來(lái)編寫代碼獲取鼠標(biāo)點(diǎn)擊的行號(hào)。

       有兩種方法來(lái)獲取行號(hào):第一種是使用GetFirstSelectedItemPositionGetNextSelectedItem配合來(lái)獲??;第二種是先獲取鼠標(biāo)位置信息,然后調(diào)用HitTest函數(shù)來(lái)找出行號(hào)。示例分別如下:

 

        第一種方法,該示例截自MSDN,可作修改后使用。

1
2
3
4
5
6
7
8
9
10
11
12
POSITION pos = pList->GetFirstSelectedItemPosition(); 
if (pos == NULL) 
   TRACE0("No items were selected!\n"); 
else 
   while (pos) 
   
      int nItem = pList->GetNextSelectedItem(pos); 
      TRACE1("Item %d was selected!\n", nItem); 
      // you could do your own processing on nItem here  
   

   第二種方法,該示例來(lái)自我的項(xiàng)目,可作修改后使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//獲取單擊所在的行號(hào)  
//找出鼠標(biāo)位置  
DWORD dwPos = GetMessagePos(); 
CPoint point( LOWORD(dwPos), HIWORD(dwPos) ); 
m_listCtrl.ScreenToClient(&point); 
   
 //定義結(jié)構(gòu)體  
LVHITTESTINFO lvinfo; 
lvinfo.pt = point; 
   
 //獲取行號(hào)信息  
int nItem = m_listCtrl.HitTest(&lvinfo); 
if(nItem != -1) 
    m_itemSel = lvinfo.iItem;   //當(dāng)前行號(hào) 

  GetMessagePos函數(shù)原型是DWORD GetMessagePos(VOID),該函數(shù)返回表示屏幕坐標(biāo)下光標(biāo)位置的長(zhǎng)整數(shù)值。此位置表示當(dāng)上一消息由GetMessage取得時(shí)鼠標(biāo)占用的點(diǎn)。

  返回值:返回值給出光標(biāo)位置的X,y坐標(biāo)。X坐標(biāo)在低位整數(shù),y坐標(biāo)在高位整數(shù)。

   HitTest():得到當(dāng)前鼠標(biāo)位置的Item
  其實(shí)關(guān)鍵是要有ScreenToClient這個(gè)函數(shù)的使用,我先前沒有用這個(gè)函數(shù),HitTest老是返回-1,搞得我都頭大了。不過這個(gè)不能用于SubItem,那應(yīng)該要用SubItemHitTest

     對(duì)于LVHITTESTINFO 結(jié)構(gòu)體,其有四個(gè)成員,在上述HitTest調(diào)用中,其第一個(gè)成員作為輸入,另外三個(gè)作為輸出。具體變量含義可查看MSDN。

1
2
3
4
5
6
typedef struct _LVHITTESTINFO { 
    POINT pt; 
    UINT flags; 
    int iItem; 
    int iSubItem; 
} LVHITTESTINFO, *LPLVHITTESTINFO; 

  

 3、復(fù)選框操作

       有時(shí)需要在item前面添加一個(gè)CheckBox,供用戶選擇,然后對(duì)所有選中項(xiàng)進(jìn)行處理。

       這里涉及到兩個(gè)問題:第一個(gè),如何添加CheckBox風(fēng)格;第二個(gè),如何判斷某一行的CheckBox狀態(tài)是否發(fā)生改變。

       對(duì)于第一個(gè)問題,在基本操作里已經(jīng)有所闡述了,即通過SetExtendedStyle函數(shù)添加LVS_EX_CHECKBOXES擴(kuò)展風(fēng)格。

      這里重點(diǎn)探討第二個(gè)問題,首先,操作復(fù)選框狀態(tài)的有兩個(gè)函數(shù):

                      BOOL GetCheck(int nItem)-------獲取復(fù)選框狀態(tài)

                      BOOL SetCheck( int nItem, BOOL fCheck = TRUE )-------設(shè)置復(fù)選框狀態(tài)

其次,我們要搞清楚以下四點(diǎn):

① 當(dāng)列表的項(xiàng)item改變時(shí),控件會(huì)向父窗口發(fā)送LVN_ITEMCHANGED消息,因此可以在LVN_ITEMCHANGED消息的響應(yīng)函數(shù)中對(duì)復(fù)選框的狀態(tài)進(jìn)行處理(查詢或設(shè)置)。

② 鼠標(biāo)點(diǎn)擊CheckBox時(shí),消息的順序是 NM_CLICK —> LVN_ITEMCHANGED,即CheckBox的狀態(tài)是在 NM_CLICK消息函數(shù)結(jié)束后才會(huì)發(fā)生變化,在NM_CLICK中使用GetCheck無(wú)效。

③ 鼠標(biāo)點(diǎn)擊Item(非CheckBox區(qū)域)時(shí),消息的順序是 LVN_ITEMCHANGED —> NM_CLICK。

 調(diào)用InsertItem 函數(shù)時(shí),也會(huì)產(chǎn)生LVN_ITEMCHANGED消息。鑒于此,通常會(huì)自定義一個(gè)BOOL型變量m_bHit 來(lái)判斷是點(diǎn)擊操作還是插入操作,該變量初始賦FALSE,當(dāng)有鼠標(biāo)點(diǎn)擊item時(shí)賦TRUE, 檢測(cè)完是否有CheckBox被點(diǎn)擊后重新復(fù)位為FALSE。

        示例如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
void CXXXX::OnNMClickXXXX(NMHDR *pNMHDR, LRESULT *pResult) 
    //獲取單擊所在的行號(hào)  
    //找出鼠標(biāo)位置  
    DWORD dwPos = GetMessagePos(); 
    CPoint point( LOWORD(dwPos), HIWORD(dwPos) ); 
    m_listCtrl.ScreenToClient(&point); 
    //定義結(jié)構(gòu)體  
    LVHITTESTINFO lvinfo; 
    lvinfo.pt = point; 
    //獲取行號(hào)信息  
    int nItem = m_listCtrl.HitTest(&lvinfo); 
    if(nItem != -1) 
    m_itemSel = lvinfo.iItem;   //當(dāng)前行號(hào)  
   
     //判斷是否點(diǎn)擊在CheckBox上  
     if(lvinfo.flags == LVHT_ONITEMSTATEICON) 
          m_bHit = TRUE; 
   
     *pResult = 0; 
   
void CXXXX::OnLvnItemchangedXXXX(NMHDR *pNMHDR, LRESULT *pResult) 
    LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR); 
    //判斷m_bHit,即是否點(diǎn)擊了CheckBox  
    if(m_bHit) 
    
            m_bHit = FALSE;     //復(fù)位  
   
        if(m_listCtrl.GetCheck(m_itemSel)) 
        {       //CheckBox被選中  
            //do your own processing   
        
        else 
        {      //CheckBox取消選擇  
            //do your own processing   
        
    
   
    *pResult = 0; 

  

  4、動(dòng)態(tài)設(shè)置選中行的字體顏色

         有時(shí)可能需要設(shè)置某行的文字為特殊顏色,以表示某種特殊含義,比如正在下載的信息用綠色,暫停下載的用灰色。

 

         首先,給出一個(gè)CodeProject的鏈接,這篇文章講的非常好,主要是利用Custom Draw。http://www.codeproject.com/Articles/79/Neat-Stuff-to-Do-in-List-Controls-Using-Custom-Dra    

         然后,來(lái)談?wù)勎业姆椒ǎ@里主要談對(duì)選中行的字體顏色進(jìn)行動(dòng)態(tài)修改,當(dāng)然也是我通過上面文章和自己實(shí)踐結(jié)合得出的。

        我們需要搞清楚以下幾點(diǎn)(可以結(jié)合下面修改某一行的字體顏色的方法來(lái)看):

① 當(dāng)控件繪制時(shí),會(huì)發(fā)送NM_CUSTOMDRAW 消息,該消息的消息響應(yīng)函數(shù)為

1
2
3
4
5
6
7
void CXXXX::OnNMCustomdrawXXXX(NMHDR *pNMHDR, LRESULT *pResult) 
    LPNMLVCUSTOMDRAW pLVCD = reinterpret_cast<LPNMLVCUSTOMDRAW>(pNMHDR); 
    // TODO: Add your control notification handler code here  
    *pResult = CDRF_DODEFAULT; 
       //………………  
 

 ?、谄渲?,pNMHDR為輸入?yún)?shù),其指向NMLVCUSTOMDRAW結(jié)構(gòu)體,該結(jié)構(gòu)包含了很多信息,包括字體顏色、背景等等,特別是第一個(gè)成員,為NMCUSTOMDRAW結(jié)構(gòu)體變量,其包含了Current drawing stage(不知道怎么編譯比較好),其可能的值如下圖(截自MSDN)所示

seo優(yōu)化培訓(xùn),網(wǎng)絡(luò)推廣培訓(xùn),網(wǎng)絡(luò)營(yíng)銷培訓(xùn),SEM培訓(xùn),網(wǎng)絡(luò)優(yōu)化,在線營(yíng)銷培訓(xùn)

③ pResult為輸出參數(shù),該參數(shù)決定了接下來(lái)向windows發(fā)送什么消息(與繪制有關(guān)的),通過發(fā)送該消息我們可以進(jìn)入下一步需要的處理階段。具體輸出哪個(gè)值取決于Current drawing stage,其可能的值如下圖(截自MSDN)所示

seo優(yōu)化培訓(xùn),網(wǎng)絡(luò)推廣培訓(xùn),網(wǎng)絡(luò)營(yíng)銷培訓(xùn),SEM培訓(xùn),網(wǎng)絡(luò)優(yōu)化,在線營(yíng)銷培訓(xùn)

④ 有一點(diǎn)必須注意(英文的,我覺得看起來(lái)比翻譯過來(lái)更精確):

     One thing to keep in mind is you must always check the draw stage before doing anything else, because your handler will receive many messages, and the draw stage determines what action your code takes.

        下面我們來(lái)看看如何修改某一行的字體顏色:

①  首先,我們應(yīng)該明白要修改字體顏色,應(yīng)該在pre-paint 階段來(lái)完成

② 因此,在消息響應(yīng)函數(shù)中,我們首先判斷是否處于pre-paint stage(即pLVCD->nmcd.dwDrawStage == CDDS_PREPAINT),然后通過修改輸出值pResult 的值來(lái)通知windows我們需要處理每個(gè)item的消息(即設(shè)置 *pResult = CDRF_NOTIFYITEMDRAW)。

③ 再次進(jìn)入消息響應(yīng)函數(shù)時(shí),我們判斷是否處于Item的pre-paint stage(即pLVCD->nmcd.dwDrawStage == CDDS_ITEMPREPAINT),如果是則進(jìn)行相關(guān)處理,即修改字體顏色等等。

④ 處理完了后重新設(shè)置 *pResult = CDRF_DODEFAULT,表示我們不再需要其他特殊的消息了,默認(rèn)執(zhí)行即可。 

         示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void CXXXX::OnNMCustomdrawXXXX(NMHDR *pNMHDR, LRESULT *pResult) 
    LPNMLVCUSTOMDRAW pLVCD = reinterpret_cast<LPNMLVCUSTOMDRAW>(pNMHDR); 
    *pResult = CDRF_DODEFAULT; 
   
    // First thing - check the draw stage. If it's the control's pre-paint stage,   
    // then tell Windows we want messages for every item.  
    if ( CDDS_PREPAINT == pLVCD->nmcd.dwDrawStage ) 
    
        *pResult = CDRF_NOTIFYITEMDRAW; 
    
    else if ( CDDS_ITEMPREPAINT == pLVCD->nmcd.dwDrawStage ) 
    
        // This is the notification message for an item.   
    //處理,將item改變背景顏色  
        if/*符合條件*/ 
        pLVCD->clrText = RGB(255,0,255); 
           
           *pResult = CDRF_DODEFAULT; 
    

  

 上面談的方法主要用于設(shè)置靜態(tài)字體顏色,當(dāng)然,如果你的列表的信息在不斷變化(即用SetItemText不斷修改),那么也就實(shí)現(xiàn)了動(dòng)態(tài)改變了,否則需要在合適的地方調(diào)用重繪函數(shù):

                         BOOL RedrawItems( int nFirst, int nLast )

表示在nFirst和nLast之間的行需要進(jìn)行重繪。

  5、設(shè)置選中行的背景顏色

         設(shè)置選中行的背景顏色,可以將選中行以特殊顏色顯示,容易明白當(dāng)前處理的是哪一行。盡管有高亮,但是高亮是基于焦點(diǎn)的,如果你選中了某一行,然后焦點(diǎn)轉(zhuǎn)移了,這是就無(wú)法判斷你選的是哪一行了。

        設(shè)置選中行的背景顏色的方法和第四節(jié)中講的修改字體顏色的方法是相似的,都是利用Custom Draw。這里涉及到設(shè)置當(dāng)前選中行為特殊顏色,同時(shí)要恢復(fù)前一次選中行的顏色,否則就亂了。因此需要記錄前一次選中行、當(dāng)前選中行的行號(hào),相信通過前面的總結(jié),這點(diǎn)并不難實(shí)現(xiàn)。然后在當(dāng)前選中行和前一次選中行之間進(jìn)行重繪即可。

       示例如下:

seo優(yōu)化培訓(xùn),網(wǎng)絡(luò)推廣培訓(xùn),網(wǎng)絡(luò)營(yíng)銷培訓(xùn),SEM培訓(xùn),網(wǎng)絡(luò)優(yōu)化,在線營(yíng)銷培訓(xùn)

void CXXXX::OnNMClickXXXX(NMHDR *pNMHDR, LRESULT *pResult)  
{  
    //…………   
  
    //重繪item,更改背景顏色   
    int nFirst = min(m_itemSel,m_itemForeSel);  
    int nLast = max(m_itemSel,m_itemForeSel);  
    m_listCtrl.RedrawItems(nFirst, nLast);  //在前一次選中的item和當(dāng)前選中的Item之間進(jìn)行重繪   
  
    *pResult = 0;  
}  
void CXXXX::OnNMCustomdrawXXXX(NMHDR *pNMHDR, LRESULT *pResult)  
{  
    LPNMLVCUSTOMDRAW pLVCD = reinterpret_cast<LPNMLVCUSTOMDRAW>(pNMHDR);  
    *pResult = CDRF_DODEFAULT;  
  
    // First thing - check the draw stage. If it's the control's prepaint   
        // stage, then tell Windows we want messages for every item.   
    if ( CDDS_PREPAINT == pLVCD->nmcd.dwDrawStage )  
    {  
             *pResult = CDRF_NOTIFYITEMDRAW;  
    }  
        else if ( CDDS_ITEMPREPAINT == pLVCD->nmcd.dwDrawStage )  
    {  
                // This is the notification message for an item.    
        //處理,將item改變背景顏色   
        if(m_itemSel == pLVCD->nmcd.dwItemSpec)        
        {   //當(dāng)前選中的item   
            pLVCD->clrTextBk = RGB(255,0,0);  
        }  
        else if(m_itemForeSel == pLVCD->nmcd.dwItemSpec)  
        {   //前一次選中的item,恢復(fù)為白色   
            pLVCD->clrTextBk = RGB(255,255,255);  
        }  
  
                *pResult = CDRF_DODEFAULT;  
    }  
}

seo優(yōu)化培訓(xùn),網(wǎng)絡(luò)推廣培訓(xùn),網(wǎng)絡(luò)營(yíng)銷培訓(xùn),SEM培訓(xùn),網(wǎng)絡(luò)優(yōu)化,在線營(yíng)銷培訓(xùn)

from:http://blog.csdn.net/zwgdft/article/details/7560592

感謝您的閱讀,若有不足之處,歡迎指教,共同學(xué)習(xí)、共同進(jìn)步。 博主網(wǎng)址:http://www.cnblogs.com/majianchao/ 如您喜歡,麻煩推薦一下;如您有新想法,歡迎提出,郵箱:1145356699@qq.com。 本博客為博主原創(chuàng),歡迎轉(zhuǎn)載,但必須注明博客來(lái)源。 更多關(guān)于游戲開發(fā)的內(nèi)容也可關(guān)注微信公眾號(hào):微浪游戲

標(biāo)簽: BUG總結(jié)

http://www.cnblogs.com/majianchao/p/7068893.html