delphiwinapitlistviewdelphi-11-alexandria

How to repaint a TListView column while resizing the column?


In a 32-bit VCL Application in Windows 10 in Delphi 11 Alexandria, I need to repaint a whole TListView column while resizing the column. The ListView items and subitems are being displayed with ListView.OwnerDraw.

So I subclassed the ListView to be notified when the column resizes:

TListView = class(Vcl.ComCtrls.TListView)
  private
    FHeaderHandle: HWND;
    procedure WMNotify(var AMessage: TWMNotify); message WM_NOTIFY;
  protected
    procedure CreateWnd; override;
...

procedure TListView.CreateWnd;
begin
  inherited;
  FHeaderHandle := ListView_GetHeader(Handle);
end;

procedure TListView.WMNotify(var AMessage: TWMNotify);
begin
  if (AMessage.NMHdr.hwndFrom = FHeaderHandle) and ((AMessage.NMHdr.code = HDN_ENDTRACK) or (AMessage.NMHdr.code = HDN_TRACK)) then
  begin
    TMessage(AMessage).Result := 0;
    InvalidateRect(FHeaderHandle, nil, true);
    CodeSite.Send('TListView.WMNotify: HDN_ENDTRACK');
  end
  else  
    inherited;
end;

Unfortunately, it reacts only at the END of column resizing, and not WHILE resizing the column! Also, the column is not repainted!


Solution

  • The issue with HDN_TRACK not being delivered is well known. A solution is to look for HDN_ITEMCHANGING instead.

    Regarding the repainting issue, notice that you do

    InvalidateRect(FHeaderHandle, nil, true);
    

    This requests a repaint of the list view header. The header is a separate window, a header control, which occupies the top row of your list view and contains only the column captions.

    You want to invalidate not the header, but the actual column in the list view.

    Just invalidate the entire list view.