I have been trying to write some owner-draw procedures for a TListView in Delphi. Specifically, I need to draw some small bitmaps in the vsReport style. I thought this would be easy. So I used the OnCustomDrawSubItem event and all seemed fine until I started changing the width of the columns during run-time. The problem was that ‘column.width’ was not being updated during the dragging and the result was a mess. After looking into the source code of the ComCtrls unit I decided to write a custom control that would update the column widths properly. Again, I thought this would be easy. I spent almost all day trying to figure out why things were not working. Finally I discovered this blog entry: http://thomasfreudenberg.com/blog/comments/352.aspx.
It seems that Microsoft has changed the notification for TListView and HDN_TRACK may not work. So, if you are having the same problems, here is my complete solution. It emulates a OnColumnTrack event (similar to the OnSectionTrack event of THeaderControl) and uses both HDN_TRACK and HDN_ITEMCHANGING to detect column changes.
This goes in the interface section of your unit:
type
TdhColumnTrackEvent = procedure(Sender: TCustomListview; Column: TListColumn; Width: Integer; State: TSectionTrackState) of object;
TdhListView = class(TListview)
private
FColumnTrackEvent: TdhColumnTrackEvent;
protected
procedure WMNotify(var Msg: TWMNotify); message WM_NOTIFY;
published
property OnColumnTrack: TdhColumnTrackEvent read FColumnTrackEvent write FColumnTrackEvent;
end;
This goes in the implementation section:
procedure TdhListView.WMNotify(var Msg: TWMNotify);
var
TrackState: TSectionTrackState;
aColumn: TListColumn;
begin
inherited;
with Msg do
case NMHdr^.code of
HDN_BEGINTRACK, HDN_ENDTRACK, HDN_TRACK, HDN_ITEMCHANGING:
begin
case NMHdr^.code of
HDN_BEGINTRACK: TrackState := tsTrackBegin;
HDN_ENDTRACK: TrackState := tsTrackEnd;
else
TrackState := tsTrackMove;
end;
with PHDNotify(Pointer(NMHdr))^, PItem^ do
if ((Mask and HDI_WIDTH) <> 0) then
begin
aColumn := Columns[Item];
if Assigned(FColumnTrackEvent) then FColumnTrackEvent(self, aColumn, cxy, TrackState);
end;
end;
end;
end;
Dude, all you need to do is remove the HDS_FULLDRAG from the list's header control's style (1 line of code) instead of this solution.
ReplyDeleteSUMMARY from the relevan Microsoft article:
Starting with version 4.70 of ComCtl32.dll, the header control of a list view control in report view (LVS_REPORT) automatically receives the HDS_FULLDRAG style. When this style is set, the parent of a list view control receives HDN_ITEMCHANGING notifications, rather than HDN_TRACK notifications, when the column divider of the header control is dragged. To receive HDN_TRACK notifications, the header control of the list view control must not have the HDS_FULLDRAG style set. Note that the HDS_FULLDRAG style is ignored in versions of ComCtl32.dll prior to 4.70.