ListView 的報表檢視 (vsReport) 常用於顯示多欄資料。Windows 檔案總管支援點擊欄標標題排序,但 BCB 預設 SortType 僅支援依首欄排序。本文實作完整的多欄點擊排序功能:奇數次點擊降序、偶數次升序,支援主欄與子欄排序。
TListView,命名 ListView1。ViewStyle = vsReport,SortType = stNone(關閉內建排序)。ListView1 建立 OnColumnClick 事件處理函式。
void __fastcall TForm1::ListView1ColumnClick(TObject *Sender, TListColumn *Column) {
static bool descending = true; // 靜態變數記錄排序方向
descending = !descending; // 每次點擊切換
int colIndex = Column->Index; // 點擊的欄索引
int itemCount = ListView1->Items->Count;
// 新增臨時項目作為交換緩衝
ListView1->Items->Add();
int tempIndex = itemCount; // 臨時項目索引
// 比較函式:依欄索引取得比較字串
auto GetCompareText = [&](int itemIdx) -> AnsiString {
if (colIndex == 0)
return ListView1->Items->Item[itemIdx]->Caption;
else
return ListView1->Items->Item[itemIdx]->SubItems->Strings[colIndex - 1];
};
// 簡單氣泡排序(示範用,大量資料建議改用 std::sort + 索引陣列)
for (int i = 0; i < itemCount - 1; i++) {
for (int j = i + 1; j < itemCount; j++) {
AnsiString textI = GetCompareText(i);
AnsiString textJ = GetCompareText(j);
bool needSwap = descending ? (textI > textJ) : (textI < textJ);
if (needSwap) {
// 利用臨時項目交換
TListItem *temp = ListView1->Items->Item[tempIndex];
temp->Assign(ListView1->Items->Item[i]);
ListView1->Items->Item[i]->Assign(ListView1->Items->Item[j]);
ListView1->Items->Item[j]->Assign(temp);
}
}
}
ListView1->Items->Delete(tempIndex); // 移除臨時項目
}
descending 保持排序方向在點擊間持久。Caption 為第 0 欄,SubItems->Strings[n] 為第 n+1 欄。TListItem 做緩衝,利用 Assign 複製整列資料(含圖示、子欄等),避免手動逐欄交換。std::vector idx ,配合 std::sort 自訂比較函式,最後按排序後索引重建 ListView 項目順序,效能大幅提升。字串比較無法正確排序數值(如 "100" < "20")。解決方案:
StrToInt/StrToFloat/StrToDateTime 轉換,成功則數值/日期比較,失敗退回字串比較。TListItem->Data 指標指向的結構中,排序時直接比較型別化資料。WM_NOTIFY / HDN_ITEMCLICK 並設定 HDF_SORTUP/DOWN 標誌。ListView1->Items->BeginUpdate()/EndUpdate() 防止閃爍。