續第一篇:MFC總結之CListCtrl用法及技巧(一) http://blog.csdn.net/zwgdft/article/details/7560592html
本篇重點介紹:禁止拖動表頭、讓第一列居中顯示、設置行高與字體、虛擬列表技術、點擊表頭時進行歸類、向上與向下移動、動態調整大小問題、避免閃爍問題。數組
六、禁止拖動表頭
重載OnNotify消息響應函數,屏蔽兩個消息通知碼:HDN_BEGINTRACKW 和HDN_DIVIDERDBLCLICKW。示例以下:函數
- BOOL CXXXX::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
- {
-
-
- NMHEADER* pNMHeader = (NMHEADER*)lParam;
- if(((pNMHeader->hdr.code == HDN_BEGINTRACKW) |
- (pNMHeader->hdr.code == HDN_DIVIDERDBLCLICKW)))
- {
- *pResult = TRUE;
- return TRUE;
- }
-
- return CDialog::OnNotify(wParam, lParam, pResult);
- }
七、讓第一列居中顯示
在插入列時,咱們能夠經過參數nFormat來設置文本居中顯示,可是這種設置對於第一列是沒有做用的。這時咱們能夠考慮將咱們的內容從第二列開始插入(設置爲居中顯示)。先插入第一列,而後刪除第一列,這樣原先的第二列就充當了第一列。字體
八、設置行高和字體
設置CListCtrl的行高沒有函數接口,能夠經過自繪來實現,可是比較麻煩。有一個比較簡單的方法是經過使用一個空白的圖像將行撐起來,使其高度發生變化。示例以下:spa
- CImageList m_image;
- m_image.Create(1,24,ILC_COLOR32,1,0);
- m_listInfo.SetImageList(&m_image, LVSIL_SMALL);
對於字體的設置,咱們可使用SetFont函數來實現。以修改CListView的字體爲例,在OnInitialUpdate函數中插入列以前調用SetFontSelf函數(該函數自定義,以下示例所示)。首先建立一個字體,而後調用SetFont進行設置。須要注意的是,在退出時須要delete 掉建立的字體,避免內存泄露。.net
- void CMyListView::SetFontSelf(int nHeight, LPCTSTR lpszFacename)
- {
-
- if(m_font != NULL)
- delete m_font;
- m_font = new CFont;
-
- m_font->CreateFont(
- nHeight,
- 0,
- 0,
- 0,
- FW_NORMAL,
- FALSE,
- FALSE,
- 0,
- ANSI_CHARSET,
- OUT_DEFAULT_PRECIS,
- CLIP_DEFAULT_PRECIS,
- DEFAULT_QUALITY,
- DEFAULT_PITCH | FF_SWISS,
- lpszFacename);
-
-
- CListCtrl &theCtrl = GetListCtrl();
- theCtrl.SetFont(m_font, TRUE);
- }
九、虛擬列表技術
給一個連接,介紹的比較詳細:http://hi.baidu.com/qi_xian/blog/item/929b04ce27d02c0592457ef8.html設計
當數據量大時,使用InsertItem插入數據的過程是很漫長的。這時咱們有兩個方法來解決該問題:一是使用CListCtrl的虛擬列表技術,二是採用分頁顯示的方法。對於虛擬列表技術,上述連接中的文章講的很詳細,我用過它的比較簡單的方法,後來改用了分頁方法。code
使用虛擬列表技術,有三點須要搞清楚:orm
① 使用虛擬技術時,須要將CListCtrl控件的Owner Data屬性設置爲ture。htm
② 給虛擬列表添加元素時,不須要使用InserItem函數,經過調用SetItemCount設置數據總個數,而後由系統產生不一樣的消息,在相應的消息響應函數中完成插入工做。
③ 虛擬列表向父窗口發送的消息有三種: ⑴ 當它須要數據時,發送LVN_GETDISPINFO消息; ⑵ 當用戶試圖查找某個元素時,發送LVN_ODFINDITEM消息; ⑶當須要緩衝數據時,發送 LVN_ODCACHEHINT消息。
當咱們使用LVN_GETDISPINFO 的消息處理函數來插入元素時,必須首先檢查列表請求的是什麼數據(如LVIF_TEXT、LVIF_IMAGE等),而後插入不一樣的子項。示例以下:
- void CDataAnalysis::OnLvnGetdispinfoAnalysisList(NMHDR *pNMHDR, LRESULT *pResult)
- {
- NMLVDISPINFO *pDispInfo = reinterpret_cast<NMLVDISPINFO*>(pNMHDR);
-
- LV_ITEM* pItem= &(pDispInfo)->item;
- int iItemIndex= pItem->iItem;
- size_t converted = 0;
- wchar_t wStr[30];
- if (pItem->mask & LVIF_TEXT)
- {
- switch(pItem->iSubItem)
- {
- case 0:
- mbstowcs_s(&converted, wStr, 30, xxxxxx, _TRUNCATE);
- lstrcpy(pItem->pszText,wStr);
- break;
- case 1:
- mbstowcs_s(&converted, wStr, 30, xxxxxx, _TRUNCATE);
- lstrcpy(pItem->pszText,wStr);
- break;
- case 2:
- mbstowcs_s(&converted, wStr, 30, xxxxxx, _TRUNCATE);
- lstrcpy(pItem->pszText,wStr);
- break;
- case 3:
- lstrcpy(pItem->pszText,xxxxxx);
- break;
- }
- }
-
- *pResult = 0;
- }
十、點擊表頭時進行歸類排序
系統經過發送LVM_SORTITEMS消息來處理歸類問題,在該消息的處理函數中須要調用一個回調函數,這個回調函數須要咱們來設計,以完成不一樣的歸類方法。回調函數原型以下:
int CALLBACK CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
針對上述回調函數,有如下幾點須要搞清楚:
① 對於參數lparam1和lparam2,分別爲CListCtrl的兩行數據,是用於比較的對象。經過CListCtrl的成員函數SetItemData來設置,該函數原型:
int SetItemData(int nIndex, DWORD_PTR dwItemData )
其第一個參數爲行號,第二個參數指明瞭該行對應的參數。參數dwItemData 一般設爲一行參數的數組,如: pData[2][2] = {{1, 3},{2, 3}}; 每次使用pData[i]做爲dwItemData。
② 對於參數lParamSort,用於指明列項,即第幾列。該參數和回調函數一同經過CListCtrl的成員函數SortItems來設置,其函數原型爲:
BOOL SortItems( PFNLVCOMPARE pfnCompare,DWORD_PTR dwData )
參數 pfnCompare 爲回調函數入口地址, 參數dwData 爲列項。
③ SetItemData在初始插入數據時進行調用來設置,SortItems則在點擊列表頭時響應的消息處理函數中進行設置。
示例以下:
- BOOL CDataAnalysis::InitListCtl()
- {
-
-
- for(int i=0; i<LineNum; i++)
- {
-
- mbstowcs_s(&converted, wStr, 30, m_analysis[i].Date, _TRUNCATE);
- m_listAnalysis.InsertItem(i, wStr);
- mbstowcs_s(&converted, wStr, 30, m_analysis[i].Time, _TRUNCATE);
- m_listAnalysis.SetItemText(i, 1, wStr);
- mbstowcs_s(&converted, wStr, 30, m_analysis[i].ID, _TRUNCATE);
- m_listAnalysis.SetItemText(i, 2, wStr);
- m_listAnalysis.SetItemText(i, 3, m_analysis[i].lpszEvent);
-
-
- m_listAnalysis.SetItemData(i, (LPARAM)(m_analysis+i));
- }
-
- return TRUE;
- }
- void CDataAnalysis::OnHdnItemclickAnalysisList(NMHDR *pNMHDR, LRESULT *pResult)
- {
- LPNMHEADER phdr = reinterpret_cast<LPNMHEADER>(pNMHDR);
-
-
-
- m_listAnalysis.SortItems(SortFunc, phdr->iItem);
-
- *pResult = 0;
- }
- int CALLBACK SortFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
- {
- int result;
-
-
- ANALYSISFORMAT* pAnalysis1 = (ANALYSISFORMAT*)lParam1;
- ANALYSISFORMAT* pAnalysis2 = (ANALYSISFORMAT*)lParam2;
-
-
- switch(lParamSort)
- {
- case 0:
- result = strcmp(pAnalysis1->Date, pAnalysis2->Date);
- break;
- case 1:
- result = strcmp(pAnalysis1->Time, pAnalysis2->Time);
- break;
- case 2:
- result = strcmp(pAnalysis1->ID, pAnalysis2->ID);
- break;
- case 3:
- result = wcscmp(pAnalysis1->lpszEvent, pAnalysis2->lpszEvent);
- break;
- default:
- break;
- }
-
- return result;
- }
十一、向上與向下移動
有時須要向上或向下移動表項內容,這裏給出向上移動的方法,向下移動的方法相似。
① 利用第2節所述的內容獲取行號nItem,判斷行號是否爲行首,若是不是行首則進入②;
② 獲取第nItem行的全部子項內容;
③ 刪除第nItem行,並在nItem-1的位置從新插入原先的第nItem行的內容;
④ 使nItem-1的位置高亮顯示
示例以下:
- void CStudyTestDlg::OnPageup()
- {
- if (nItem == 0)
- {
- MessageBox("該子項已經位於第一行!");
- return;
- }
-
-
- CString temp[4];
- int i;
- for(i=0;i<4;i++)
- temp[i] = m_ListCtrl.GetItemText(nItem, i);
-
-
- m_ListCtrl.DeleteItem(nItem);
-
-
- for (i=0; i<4; i++)
- m_ListCtrl.SetItemText(nItem-1,i,temp[i]);
-
-
- UINT flag = LVIS_SELECTED|LVIS_FOCUSED;
- m_ListCtrl.SetItemState(--nItem, flag, flag);
- }
-
- void CStudyTestDlg::OnPagedown()
- {
- if (nItem == m_ListCtrl.GetItemCount()-1)
- {
- MessageBox("該子項已經位於最後一行!");
- return;
- }
-
-
- CString temp[4];
- int i;
- for (i=0; i<4; i++)
- temp[i] = m_ListCtrl.GetItemText(nItem, i);
-
-
- m_ListCtrl.DeleteItem(nItem);
-
-
- for (i=0; i<4; i++)
- m_ListCtrl.SetItemText(nItem+1, i,temp[i]);
-
-
- UINT flag = LVIS_SELECTED|LVIS_FOCUSED;
- m_ListCtrl.SetItemState(++nItem, flag, flag);
- }
十二、避免閃爍問題
這個問題在個人前面一篇博文有提到。
http://blog.csdn.net/zwgdft/article/details/7394318
1三、動態調整大小
有時因爲不肯定軟件運行時的電腦屏幕大小,須要根據屏幕大小動態設置CListCtrl控件的大小。動態大小的設置時,須要注意不要將高度和寬度設置的超過區域限制,不然就沒有滾動條了,致使部份內容沒法查看。以我遇到的一個例子來講,其狀況見第12節提到的那篇博文所述:將View劃分爲三個窗格,在左上角View上有個CPropertySheet,其上有幾個CPropertyPage,每一個屬性頁上有個CListCtrl,供用戶查看信息。那麼這時須要設置的CListCtrl的大小即爲:
寬度 = 左上角View寬度
高度 = 左上角View高度 - 屬性頁的Tab項高度
調用MoveWindow函數進行設置便可。