核心 API
BOOL CListCtrl::SortItems(PFNLVCOMPARE pfnCompare, DWORD dwData);
pfnCompare:全域回調函數指標,簽章 int CALLBACK Compare(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)。
dwData:使用者自定義資料,傳遞給比較函數第三參數 lParamSort。
- 回傳值:-1 (項目1 < 項目2)、0 (相等)、1 (項目1 > 項目2)。
比較函數設計要點
- 每個 List 項目的
ItemData (透過 SetItemData/GetItemData) 應能唯一映射到資料源索引或指標。
- 比較函數中透過
lParamSort 取得排序上下文 (如目前排序欄位、升冪/降冪旗標)。
觸發排序:處理 LVN_COLUMNCLICK
// 對話框/視圖類訊息對應
ON_NOTIFY(LVN_COLUMNCLICK, IDC_MY_LIST, OnColumnClick)
// 處理函數
void CMyDialog::OnColumnClick(NMHDR* pNMHDR, LRESULT* pResult) {
NM_LISTVIEW* pNM = (NM_LISTVIEW*)pNMHDR;
int col = pNM->iSubItem;
// 切換升冪/降冪
if (col == m_listCtrl.m_nSortedCol)
m_listCtrl.m_bAscending = !m_listCtrl.m_bAscending;
else {
m_listCtrl.m_nSortedCol = col;
m_listCtrl.m_bAscending = TRUE;
}
// 呼叫排序,傳遞 this 指標作為上下文
m_listCtrl.SortItems(CompareFunc, (DWORD)&m_listCtrl);
*pResult = 0;
}
完整可執行範例 (對話框專案)
資料結構與全域測試資料
struct DEMO_DATA { char szName[20]; int iAge; };
DEMO_DATA g_data[5] = {
{"王某", 30}, {"張某", 40}, {"武某", 32}, {"陳某", 20}, {"李某", 36}
};
衍生列表控制類別
class CSortList : public CListCtrl {
public:
CSortList() : m_bAscending(TRUE), m_nSortedCol(-1) {}
BOOL m_bAscending; // 升冪旗標
int m_nSortedCol; // 目前排序欄位
};
對話框初始化與資料填充
BOOL CMyDialog::OnInitDialog() {
CDialog::OnInitDialog();
m_listCtrl.InsertColumn(0, _T("姓名"), LVCFMT_LEFT, 80);
m_listCtrl.InsertColumn(1, _T("年齡"), LVCFMT_RIGHT, 80);
for (int i = 0; i < 5; i++) {
m_listCtrl.InsertItem(i, g_data[i].szName);
CString strAge; strAge.Format(_T("%d"), g_data[i].iAge);
m_listCtrl.SetItemText(i, 1, strAge);
m_listCtrl.SetItemData(i, i); // ItemData = 陣列索引
}
return TRUE;
}
全域比較回調函數
int CALLBACK CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) {
CSortList* pList = (CSortList*)lParamSort;
DEMO_DATA* p1 = &g_data[lParam1];
DEMO_DATA* p2 = &g_data[lParam2];
int result = 0;
switch (pList->m_nSortedCol) {
case 0: // 姓名 (字串比較)
result = strcmp(p1->szName, p2->szName);
break;
case 1: // 年齡 (數值比較)
if (p1->iAge == p2->iAge) result = 0;
else result = (p1->iAge < p2->iAge) ? -1 : 1;
break;
default: ASSERT(0); break;
}
return pList->m_bAscending ? result : -result;
}
進階擴展建議
- 多資料源支援:
lParamSort 傳遞結構體指標,包含資料源指標、型別資訊,實現通用比較器。
- 排序指示器:
SetColumnImage 或 Owner Draw 繪製欄標標題箭頭 (▲/▼)。
- 效能優化:大量資料 (萬筆以上) 建議使用虛擬清單 (
LVS_OWNERDATA) 配合記憶體內排序,避免頻繁回調開銷。
- 多欄位複合排序:
lParamSort 擴展為排序規則陣列,比較函數依序應用。