Delphi 7下的ListView其中有个ViewStyle风格是vsReport,我们大多也是使用这个风格。在此风格下可以设置首列前面有个CheckBox复选框,但是我们更多时候,需要的是在最后一列显示CheckBox复选框。于是,我们得自己重画子项为CheckBox,然而画完之后,在调整列宽时,不会触发ListView刷新,导致影像残留,于是接着禁止用户调整列宽。
示例源码如下:
001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047 048 049 050 051 052 053 054 055 056 057 058 059 060 061 062 063 064 065 066 067 068 069 070 071 072 073 074 075 076 077 078 079 080 081 082 083 084 085 086 087 088 089 090 091 092 093 094 095 096 097 098 099 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 |
unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, Grids, ValEdit, StdCtrls, CheckLst, ComCtrls, CommCtrl, Math, XPMan; type TForm1 = class(TForm) lv1: TListView; xpmnfst1: TXPManifest; procedure lv1CustomDrawSubItem(Sender: TCustomListView; Item: TListItem; SubItem: Integer; State: TCustomDrawState; var DefaultDraw: Boolean); procedure lv1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); private FListViewOldWndProc: TWndMethod; procedure ListViewNewWndProc(var Msg: TMessage); public { Public declarations } end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.FormCreate(Sender: TObject); begin FListViewOldWndProc := lv1.WindowProc; lv1.WindowProc := ListViewNewWndProc; with lv1 do begin RowSelect := True; ReadOnly := True; end; end; procedure TForm1.FormDestroy(Sender: TObject); begin lv1.WindowProc := FlistViewOldWndProc; FListViewOldWndProc := nil; end; {------------------------------------------------------------------------------- Description: 禁止ListView调整列宽 -------------------------------------------------------------------------------} procedure TForm1.ListViewNewWndProc(var Msg: TMessage); var hdn: ^THDNotify; begin if Msg.Msg = WM_NOTIFY then begin hdn := Pointer(Msg.lParam); if (hdn.hdr.code = HDN_BeginTrackW) or (hdn.hdr.code = HDN_BeginTrackA) then Msg.Result := 1 else FListViewOldWndProc(Msg); end else FListViewOldWndProc(Msg); end; {------------------------------------------------------------------------------- Description: 定义第几个子项为复选框,True值为选中 -------------------------------------------------------------------------------} const SubItemCheck = 2; {------------------------------------------------------------------------------- Description: TListView中画出复选框事件 -------------------------------------------------------------------------------} procedure TForm1.lv1CustomDrawSubItem(Sender: TCustomListView; Item: TListItem; SubItem: Integer; State: TCustomDrawState; var DefaultDraw: Boolean); var s : TSize; r : TRect; rc : TRect; i : Integer; Dx : Integer; cr : TColor; begin if (SubItem = SubItemCheck) then begin DefaultDraw := False; rc := Item.DisplayRect(drBounds); Dx := 0; for i := 0 to SubItem - 1 do Inc(Dx,Sender.Column[i].Width); rc.Left := rc.Left + Dx; rc.Right := rc.Left + Sender.Column[SubItem].Width; cr := Sender.Canvas.Brush.Color; if Item.Selected and Sender.RowSelect and Sender.Focused then Sender.Canvas.Brush.Color := clHighlight else Sender.Canvas.Brush.Color := clWindow; Sender.Canvas.FillRect(rc); if cdsFocused in State then begin DrawFocusRect(Sender.Canvas.Handle,rc); Sender.Canvas.FillRect(Rect(rc.Left,rc.Top + 1,rc.Left + 1,rc.Bottom - 1)); end; Sender.Canvas.Brush.Color := cr; s.cx := GetSystemMetrics(SM_CXMENUCHECK); s.cy := GetSystemMetrics(SM_CYMENUCHECK); Dx := (Sender.Column[SubItem].Width-GetSystemMetrics(SM_CXMENUCHECK)) div 2; r.Top := rc.Top + (rc.Bottom - rc.Top - s.cy) div 2; r.Bottom := r.Top + s.cy; r.Left := rc.Left + Dx; r.Right := r.Left + s.cx; DrawFrameControl(Sender.Canvas.Handle, r, DFC_BUTTON, IfThen( CompareText(Item.SubItems[SubItem-1],'True')=0, DFCS_CHECKED, DFCS_BUTTONCHECK)); end; end; {------------------------------------------------------------------------------- Description: TListView中子项复选框单击选中事件 -------------------------------------------------------------------------------} procedure TForm1.lv1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var s : TSize; r : TRect; Rect : TRect; i : Integer; Dx : Integer; begin if (lv1.ItemIndex > -1) and (Shift = [ssleft]) then //左键点击时 begin Rect :=lv1.Items[lv1.ItemIndex].DisplayRect(drBounds); Dx := 0; for i := 0 to SubItemCheck - 1 do Inc(Dx,lv1.Column[i].Width); Rect.Left :=Rect.Left + Dx; Rect.Right :=Rect.Left + lv1.Column[SubItemCheck].Width; s.cx := GetSystemMetrics(SM_CXMENUCHECK); s.cy := GetSystemMetrics(SM_CYMENUCHECK); Dx := (lv1.Column[SubItemCheck].Width - GetSystemMetrics(SM_CXMENUCHECK)) div 2; r.Top := Rect.Top + (Rect.Bottom - Rect.Top - s.cy) div 2; r.Bottom := r.Top + s.cy; r.Left := Rect.Left + Dx; r.Right := r.Left + s.cx; if (x >= r.Left) and (y >= r.Top) and (x <= r.Right) and (y <= r.Bottom)then begin //判断是否点中复选框 if lv1.Items[lv1.ItemIndex].SubItems.Strings[SubItemCheck - 1] = 'true' then lv1.Items[lv1.ItemIndex].SubItems.Strings[SubItemCheck - 1] := 'false' else lv1.Items[lv1.ItemIndex].SubItems.Strings[SubItemCheck - 1] := 'true'; end; end; end; end. |
运行结果如下所示: