views:

391

answers:

2

I have a descendant of TListView that offers some additional features, such as sorting and ability to load itself from a TDataset. I now wish to extend this component further so that certain aspects of the drawing can be specified at the time items are added to the list view.

I'm having trouble figuring out which procedure or procedures to override to take control of the drawing. I have overridden DrawItem to change the font style to include strikethrough and then call the inherited DrawItem. If I also specify the style LVS_OWNERDRAWFIXED (in an overriden CreateParams()) my function is called and works as I want except that only the item, and not the subitems, is drawn.

Does anyone know how I can tell the list view to draw the subitems also? I've found one example of a substantially enhanced list view, but this one isn't sufficiently well documented for me to follow exactly what's going on, and I'm hoping not to have to hook quite as many events and windows messages as this one does — it seems to me that simply setting the canvas pen, brush, and font and then having the item draw itself should not be quite so involved.

Here's what I have so far:

protected
    procedure CreateParams(var Params: TCreateParams); override;
    procedure DrawItem(Item: TListItem; Rect: TRect; State: TOwnerDrawState); override;

procedure TLookupListView.CreateParams(var Params: TCreateParams);
begin

  inherited CreateParams(Params);

  Params.Style := Params.Style or lvs_OwnerDrawFixed;

end;

procedure TLookupListView.DrawItem(Item: TListItem; Rect: TRect; State: TOwnerDrawState);
var I: Integer;
    Left: Integer;
begin

   Canvas.Font.Style := Canvas.Font.Style + [fsStrikeOut];
   inherited DrawItem(Item, Rect, State);
   //I know the canvas must be restored here, this is just for proof-of-concept.

end;

PLEASE NOTE: I'm not interested in doing custom drawing in a particular instance of TListView using the supplied events. I know how to do that. I'm trying to "bake in" this functionality to my custom TListview descendant component.

+1  A: 

The component has a virtual method IsCustomDrawn() which is called to determine which code paths need to be executed. In the base class implementation it checks whether any of the event handlers to paint the subitems is assigned, but you can override the method to return True for all those paint stages you want handled, even when there is no event handler assigned.

If you want to handle everything in code you should probably override CustomDrawItem() and CustomDrawSubItem() and do everything there. To get everything working I would build the app with debug DCUs, step into from event handlers and look around what the minimum amount of code you can get away with is. The important method to check out is TCustomListView.CNNotify() - here the Windows messages for owner drawing are handled.

Edit:

I forgot to add that you should try to not owner draw the text in the control, but just to set canvas properties in the various paint stages - the reason being that otherwise you will have to make sure that text output is pixel-perfect in all Windows versions, something that the VCL doesn't achieve. You can see this by adding a few columns and rows to a list view and toggling the OwnerDraw property at design time, the text jumps around.

mghie
Thanks mghie. I am, in fact, trying to avoid drawing the text myself, either for the caption or the subitems. CustomDrawItem and CustomDrawSubItem look like what I want. I'm investigating further. . .
Larry Lustig
Right, so maybe you could even remove the `LVS_OWNERDRAWFIXED` style flag, as the paint stage notifications are not (all) dependent on it.
mghie
Yes, I don't need the LVS_OWNERDRAWFIXED. Right now I have it (apparently) working having made no other changes except overriding IsCustomDrawn and CustomDrawItem (canvas changes in CustomDrawItem stay in effect through the drawing of sub items). I think all I have left is to ensure that any of the user events for custom drawing don't get ignored.
Larry Lustig
+1  A: 

Which version of Delphi are you using? In Delphi 2007 TListView has support for custom-drawing by handling NM_CUSTOMDRAW messages, as described here. TListView already has events defined for custom-drawing subitems, as well as virtual methods you can override in your descendant.

TOndrej
D2007, and I'll want to move this to D2010 soon. I'll check out the link, many thanks.
Larry Lustig