開發的過程中,經常要使用到 TListview,爲了界面美觀,需要自繪 TListview,下面就 TListview 自繪的三個方面,總結一下。
1、顯示千萬條數據記錄;
2、表格自繪;
3、表頭自繪;
1、顯示千萬條數據記錄;
A:OwnerData 設爲 True, OwnerDraw 暫時設爲 False, 不進行自繪,由系統來完成繪製。
我們的重點放在顯示千萬條記錄上面;
B:數據來源,數據庫查詢:
ADOQuery1.SQL.Clear;
ADOQuery1.Close;
ADOQuery1.SQL.Text := 'select ROW_NUMBER() over(order by ID) as RowNum, * from TableName';
ADOQuery1.Open;
這裏:
ID :數據庫表中自增長字段(換成你要查詢的數據庫表中的自增長字段);
TableName :數據庫表名;
* :數據庫中所有字段名稱;
實際使用中,最好不要用 * ,需要顯示哪些字段就填入字段名稱 ,效率會大大提高。
注:
ID 是必須的,爲最後一列,不顯示的一列,用於記錄標識;當選中/雙擊時,根據此列值,可找到數據庫對應記錄。
無論你的查詢語句如何寫,select ROW_NUMBER() over(order by ID) as RowNum 是必不可少的。
ADOQuery1 查詢結束後,添加代碼:
lvData.Items.Count := ADOQuery1.RecordCount;
將觸發 OnData 事件:
C:雙擊 OnData 事件,進入代碼界面:
假設 ADOQuery1 查詢結果中包含千萬條記錄
顯示數據前,列名先準備好。動態創建也可以。
注:
列名一般使用字段名,但字段名一般爲英文。實際使用肯定是需要中文的。
我們可以使用字段的說明屬性,來當作列名。
建立字段時,順手給字段的列屬性中的說明屬性加個中文說明,
程序中獲取字段對應的說明屬性來當作列名,就OK了。
procedure TfrmListViewData.lvDataData(Sender: TObject; Item: TListItem);
var
I: Integer;
begin
ADOQuery1.RecNo := Item.Index + 1;
Item.Caption := ADOQuery1.Fields[1].AsString;
for I := 2 to ADOQuery1.Fields.Count - 1 do
begin
if ADOQuery1.Fields[I].DataType = ftBlob then
Item.SubItems.Add('')
else
Item.SubItems.Add(ADOQuery1.Fields[I].AsString);
end;
end;
OK,大功告成。上面代碼只是示例,細節根據自己需要,自己把控。
2、表格自繪;
這一步比較容易;
A:設置 OwnerDraw 爲 True ,就會觸發自繪事件;
B:雙擊 OnCustomDrawItem 事件,在事件中輸入自繪代碼。
有畫布 Canvas,TListview(Sender).Canvas,有 Item ,想繪製成啥樣,就繪製成啥樣。
劃過/選中/動態,等等效果都可以在這裏實現。
3、表頭自繪;
想繪製表頭,就需要知道表頭句柄。
想得到表頭句柄,就需要攔截 ListView 的 WMParentNotify 消息,因爲表頭的創建是由它完成的。
類定義:
type
TListView = Class(ComCtrls.TListView)
private
FHeaderHandle: Integer;
{ 表頭的回調過程 }
FOldHeaderProc, FHeaderInstance: Pointer;
protected
procedure WMParentNotify(var Message: TWMParentNotify); message WM_PARENTNOTIFY;
procedure HeaderWndProc(var Message: TMessage);
end;
實現:
procedure TListView.WMParentNotify(var Message: TWMParentNotify);
begin
if (Message.Event = WM_CREATE) then
begin
FHeaderHandle := message.ChildWnd; // 獲取到表頭句柄
FOldHeaderProc := Pointer(GetWindowLong(FHeaderHandle, GWL_WNDPROC)); // 保存好表頭原有的回調過程
SetWindowLong(FHeaderHandle, GWL_WNDPROC, Integer(FHeaderInstance)); // 指向表頭新的回調過程,用於自繪
end;
inherited;
end;
注:
這裏還有一些細節,比如:
WINXP、WIN7、WIN10下創建表頭句柄是有點差別的;
創建時,需要經過幾次纔會真正得到句柄;
上面的代碼只是核心代碼,細化沒有寫出,自己動手試試,也就能理解了。
事前要設置一下表頭新的回調過程:
FHeaderInstance := MakeObjectInstance(HeaderWndProc);
{ 自繪表頭 }
procedure TListView.HeaderWndProc(var Message: TMessage);
begin
with Message do
begin
{ 自繪表頭 }
if msg = WM_PAINT then
begin
{ 有句柄 FHeaderHandle,就可以得到畫布 Canvas ,有畫布就可以自繪了 }
end;
end;
end;
注:
還有其它消息可以處理:
WM_SETCURSOR :當鼠標移動到表頭分割線時;
WM_NCHITTEST :調整表頭寬度;
HDM_LAYOUT :調整表頭高度;
等等,繪製表頭悉數掌控。
OK,繪製完畢。
效果圖:
滾動條的繪製比較好玩。以後在寫吧。不在 TListview 的自繪範圍內。
它是一個通用的繪製類,可以給任意控件來用(除了IE控件)。