If you are targeting Vista and later, obvious answer is TLama's. If not, parent the check box in the header control, not in the list box (again as TLama commented to the question). The check box will send notifications to its parent - the header control, so you need to subclass it. Working sample:
type
TForm1 = class(TForm)
ListView1: TListView;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
FListHeaderWnd: HWND;
FListHeaderChk: TCheckBox;
FSaveListHeaderWndProc, FListHeaderWndProc: Pointer;
procedure ListHeaderWndProc(var Msg: TMessage);
end;
var
Form1: TForm1;
implementation
uses
commctrl;
{$R *.dfm}
function GetCheckSize: TPoint; // from checklst.pas
begin
with TBitmap.Create do
try
Handle := LoadBitmap(0, PChar(OBM_CHECKBOXES));
Result.X := Width div 4;
Result.Y := Height div 3;
finally
Free;
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
var
CheckSize: TPoint;
HeaderSize: TRect;
begin
ListView1.HandleNeeded;
FListHeaderWnd := ListView_GetHeader(ListView1.Handle);
FListHeaderChk := TCheckBox.Create(nil);
CheckSize := GetCheckSize;
FListHeaderChk.Height := CheckSize.X;
FListHeaderChk.Width := CheckSize.Y;
// the below won't show anything since the form is not visible yet
ShowWindow(ListView1.Handle, SW_SHOWNORMAL); // otherwise header is not sized
windows.GetClientRect(FListHeaderWnd, HeaderSize);
FListHeaderChk.Top := (HeaderSize.Bottom - FListHeaderChk.Height) div 2;
FListHeaderChk.Left := FListHeaderChk.Top;
FListHeaderChk.Parent := Self;
windows.SetParent(FListHeaderChk.Handle, FListHeaderWnd);
FListHeaderWndProc := classes.MakeObjectInstance(ListHeaderWndProc);
FSaveListHeaderWndProc := Pointer(GetWindowLong(FListHeaderWnd, GWL_WNDPROC));
SetWindowLong(FListHeaderWnd, GWL_WNDPROC, NativeInt(FListHeaderWndProc));
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
SetWindowLong(FListHeaderWnd, GWL_WNDPROC, NativeInt(FSaveListHeaderWndProc));
classes.FreeObjectInstance(FListHeaderWndProc);
FListHeaderChk.Free;
end;
procedure TForm1.ListHeaderWndProc(var Msg: TMessage);
begin
if (Msg.Msg = WM_COMMAND) and (HWND(Msg.LParam) = FListHeaderChk.Handle)
and (Msg.WParamHi = BN_CLICKED) then begin
FListHeaderChk.Checked := not FListHeaderChk.Checked;
// code that checks/clears all items
end;
Msg.Result := CallWindowProc(FSaveListHeaderWndProc, FListHeaderWnd,
Msg.Msg, Msg.WParam, Msg.LParam);
end;
Note that if you've 'ColumnClick' set, it looks ugly that the check box does not 'push' with the header button when you click on it.
Parent:=ListView1;
thisWindows.SetParent(Handle, ListView_GetHeader(ListView1.Handle));
but then the check box stops to respond to the clicks. – Lueticlittle buggy
mean ? – Luetic