Tuesday, August 29, 2006

TListView troubles

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;

Vienna again

It has been along time since I updated this blog. It seems that I have so many things to do, there is hardly any time left. Of course, it is always a matter of priorities, so you can figure how high this blog is on my list. Anyway, I was in Vienna in July, two times during the same month. Very hot weather. Vienna is a great city. For chocolates I recommend ‘Xokolat’, at Freyung 2 (Tel. 5354363). A large selection and not too expensive. I tried a 100% for the first time and I definitely do not recommend it; too bitter. I threw most of it away. However, the regular ones were excellent. The ‘Queen of Finland’ was kind enough to bring me some Fazer, which was very much appreciated. I guess we will see each other again in Berlin.