2008. június 17., kedd

How to indent the focus rectangle in an owner-drawn TListBox


Problem/Question/Abstract:

I have a TListBox with style lbOwnerDrawVariable. I want to draw some text indented 10 pixels from the left (this is no problem). However, I also want it so the highlighting color and focus rectangle are indented as well (so the 10 pixel margin is completely blank, no matter what items are selected). I can't seem to do this ... the focus rectangle always seems to extend all the way to the left. How do I get around this?

Answer:

The problem is that the control as coded draws the focus rectangle after your owner drawing code has completed. To override that you have to make a new control descending from TListbox (or TCustomlistbox) and give it a handler for the CN_DRAWITEM message. Here you need to duplicate what the TCustomlistbox.CNDrawItem method does:

procedure TMyListBox.CNDrawItem(var Message: TWMDrawItem);
var
  State: TOwnerDrawState;
begin
  with Message.DrawItemStruct^ do
  begin
    State := TOwnerDrawState(LongRec(itemState).Lo);
    Canvas.Handle := hDC;
    Canvas.Font := Font;
    Canvas.Brush := Brush;
    if (Integer(itemID) >= 0) and (odSelected in State) then
    begin
      Canvas.Brush.Color := clHighlight;
      Canvas.Font.Color := clHighlightText
    end;
    if Integer(itemID) >= 0 then
      DrawItem(itemID, rcItem, State)
    else
      Canvas.FillRect(rcItem);
    if odFocused in State then
    begin
      Inc(rcItem.left, 10); {this is the change}
      DrawFocusRect(hDC, rcItem);
    end;
    Canvas.Handle := 0;
  end;
end;

Nincsenek megjegyzések:

Megjegyzés küldése