在 MFC 應用程式中使用 CListView 時,當欄位總寬度超過視圖寬度,預設會自動顯示水平捲軸。許多開發者嘗試在 PreCreateWindow 中移除 WS_HSCROLL 樣式卻發現無效,本文說明正確的解決方案。
CListView 內部封裝了 List View 控制項(SysListView32),其捲軸行為由通用控制項自行管理,而非單純依賴視窗樣式 WS_HSCROLL。在 PreCreateWindow 移除該樣式無法影響已建立的控制項行為。
SetWindowLong 修改控制項樣式(建議)void CMyListView::OnInitialUpdate()
{
CListView::OnInitialUpdate();
// 取得 List Control 的 HWND
HWND hList = GetListCtrl().m_hWnd;
// 移除水平捲軸樣式
LONG style = GetWindowLong(hList, GWL_STYLE);
style &= ~WS_HSCROLL;
SetWindowLong(hList, GWL_STYLE, style);
// 強制重繪
SetWindowPos(hList, NULL, 0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
}
若不想硬性禁用捲軸,可在初始化時根據客戶區寬度自動調整最後一欄寬度:
void CMyListView::OnSize(UINT nType, int cx, int cy)
{
CListView::OnSize(nType, cx, cy);
CListCtrl& listCtrl = GetListCtrl();
if (listCtrl.GetHeaderCtrl()->GetItemCount() > 0) {
CRect rect;
listCtrl.GetClientRect(&rect);
int totalWidth = 0;
for (int i = 0; i < listCtrl.GetHeaderCtrl()->GetItemCount() - 1; ++i) {
totalWidth += listCtrl.GetColumnWidth(i);
}
// 最後一欄填滿剩餘空間
listCtrl.SetColumnWidth(listCtrl.GetHeaderCtrl()->GetItemCount() - 1,
max(50, rect.Width() - totalWidth));
}
}
LVS_EX_FLATSB 擴展樣式自定義捲軸若需保留捲軸功能但想自定義外觀,可啟用扁平捲軸並繼承 CScrollBar 繪製:
listCtrl.SetExtendedStyle(listCtrl.GetExtendedStyle() | LVS_EX_FLATSB);
FlatSB_EnableScrollBar(hList, SB_HORZ, ESB_DISABLE_BOTH); // 禁用水平捲軸
SetWindowPos 並帶入 SWP_FRAMECHANGED 才會生效。OnInitialUpdate 執行時控制項尚未建立完成,可改用 PostMessage 延遲執行。透過上述方法,即可有效控制 CListView 的水平捲軸顯示行為,解決欄位過寬導致的介面問題。