6、禁止拖動表頭
重載OnNotify消息響應函數,屏蔽兩個消息通知碼:HDN_BEGINTRACKW 和HDN_DIVIDERDBLCLICKW。示例如下:- BOOL CXXXX::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
- {
- // TODO: Add your specialized code here and/or call the base class
- //屏蔽兩個消息通知碼,使得禁止拖動List表頭
- 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);
- }
7、讓第一列居中顯示
在插入列時,我們可以通過參數nFormat來設置文本居中顯示,但是這種設置對於第一列是沒有作用的。這時我們可以考慮將我們的內容從第二列開始插入(設置爲居中顯示)。先插入第一列,然後刪除第一列,這樣原先的第二列就充當了第一列。8、設置行高和字體
設置CListCtrl的行高沒有函數接口,可以通過自繪來實現,但是比較麻煩。有一個比較簡單的方法是通過使用一個空白的圖像將行撐起來,使其高度發生變化。示例如下:- CImageList m_image;
- m_image.Create(1,24,ILC_COLOR32,1,0);
- m_listInfo.SetImageList(&m_image, LVSIL_SMALL);
- //設置字體和大小
- void CMyListView::SetFontSelf(int nHeight, LPCTSTR lpszFacename)
- {
- //先刪除原有字體
- if(m_font != NULL)
- delete m_font;
- m_font = new CFont;
- //創建字體
- m_font->CreateFont(
- nHeight, // nHeight
- 0, // nWidth
- 0, // nEscapement
- 0, // nOrientation
- FW_NORMAL, // nWeight
- FALSE, // bItalic
- FALSE, // bUnderline
- 0, // cStrikeOut
- ANSI_CHARSET, // nCharSet
- OUT_DEFAULT_PRECIS, // nOutPrecision
- CLIP_DEFAULT_PRECIS, // nClipPrecision
- DEFAULT_QUALITY, // nQuality
- DEFAULT_PITCH | FF_SWISS, // nPitchAndFamily
- lpszFacename); // lpszFacename
- //設置字體
- CListCtrl &theCtrl = GetListCtrl(); //獲取控制權,引用變量
- theCtrl.SetFont(m_font, TRUE);
- }
9、虛擬列表技術
給一個鏈接,介紹的比較詳細:http://hi.baidu.com/qi_xian/blog/item/929b04ce27d02c0592457ef8.html當數據量大時,使用InsertItem插入數據的過程是很漫長的。這時我們有兩個方法來解決該問題:一是使用CListCtrl的虛擬列表技術,二是採用分頁顯示的方法。對於虛擬列表技術,上述鏈接中的文章講的很詳細,我用過它的比較簡單的方法,後來改用了分頁方法。
使用虛擬列表技術,有三點需要搞清楚:
① 使用虛擬技術時,需要將CListCtrl控件的Owner Data屬性設置爲ture。
② 給虛擬列表添加元素時,不需要使用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);
- // TODO: Add your control notification handler code here
- LV_ITEM* pItem= &(pDispInfo)->item;
- int iItemIndex= pItem->iItem;
- size_t converted = 0;
- wchar_t wStr[30]; //Unicode字符串
- if (pItem->mask & LVIF_TEXT) //字符串緩衝區有效
- {
- switch(pItem->iSubItem)
- {
- case 0: //填充數據項的名字,xxxxx表示要填充的字符
- mbstowcs_s(&converted, wStr, 30, xxxxxx, _TRUNCATE);
- lstrcpy(pItem->pszText,wStr);
- break;
- case 1: //填充子項1
- mbstowcs_s(&converted, wStr, 30, xxxxxx, _TRUNCATE);
- lstrcpy(pItem->pszText,wStr);
- break;
- case 2: //填充子項2
- mbstowcs_s(&converted, wStr, 30, xxxxxx, _TRUNCATE);
- lstrcpy(pItem->pszText,wStr);
- break;
- case 3: //填充子項3
- lstrcpy(pItem->pszText,xxxxxx);
- break;
- }
- }
- *pResult = 0;
- }
10、點擊表頭時進行歸類排序
系統通過發送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++)
- {
- //要將char*轉換爲wchar_t*
- 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); //ID
- 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);
- // TODO: Add your control notification handler code here
- //設置回調函數的參數和入口地址
- 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: //ID
- result = strcmp(pAnalysis1->ID, pAnalysis2->ID);
- break;
- case 3: //事件
- result = wcscmp(pAnalysis1->lpszEvent, pAnalysis2->lpszEvent);
- break;
- default:
- break;
- }
- return result;
- }
11、向上與向下移動
有時需要向上或向下移動表項內容,這裏給出向上移動的方法,向下移動的方法類似。
① 利用第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);
- // 在nItem-1位置處插入
- 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);
- // 在nItem+1位置處插入
- 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);
- }
12、避免閃爍問題
這個問題在我的前面一篇博文有提到。http://blog.csdn.net/zwgdft/article/details/7394318
13、動態調整大小
有時由於不確定軟件運行時的電腦屏幕大小,需要根據屏幕大小動態設置CListCtrl控件的大小。動態大小的設置時,需要注意不要將高度和寬度設置的超過區域限制,否則就沒有滾動條了,導致部分內容無法查看。以我遇到的一個例子來說,其情況見第12節提到的那篇博文所述:將View劃分爲三個窗格,在左上角View上有個CPropertySheet,其上有幾個CPropertyPage,每個屬性頁上有個CListCtrl,供用戶查看信息。那麼這時需要設置的CListCtrl的大小即爲:
寬度 = 左上角View寬度
高度 = 左上角View高度 - 屬性頁的Tab項高度
調用MoveWindow函數進行設置即可。
------------------全文完--------------------