5

I am using ListBox.Style := lbOwnerDrawFixed with OnDrawItem:

procedure TForm1.ListBox1DrawItem(Control: TWinControl; Index: Integer;
  ARect: TRect; State: TOwnerDrawState);
begin
  with ListBox1.Canvas do begin
    Brush.Color := clWhite;
    Pen.Color := clWhite;
    FillRect(ARect);
  end;
end;

It should give an empty space to draw anything I want, but it doesn't. When the item is focued I still can see a dotted rectangle around it.

How to remove the rectangle?

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
Tom
  • 2,962
  • 3
  • 39
  • 69
  • What about `Brush.Style := bsSolid;` and `Pen.Style := psSolid;`? – Jerry Dodge Feb 21 '15 at 18:05
  • @JerryDodge No change :( – Tom Feb 21 '15 at 18:07
  • Only other guess, are you sure `ListBox1` is the same control that's calling this event handler? Typically you should do `TListBox(Control).Canvas` instead of directly referencing the control. Does it show colors when you use another color? – Jerry Dodge Feb 21 '15 at 18:09
  • @Jerry Yes, it's the right control. I added some drawing there to draw text, rectangles and it all works. But after my drawing a default rectangle that indicates the item is selected is being drawn. Looks like the system drawing is happening after my drawing. I just moved my code to DrawGrid and it does only my drawing, no default focus indicators there. Seems like a bug in TListBox to me. – Tom Feb 21 '15 at 18:17
  • It doesn't sound like a bug. This is a system control. This is normal behaviour. Owner draw has you draw some part of the control, not all. – David Heffernan Feb 21 '15 at 18:31
  • @DavidHeffernan Then I would say this control was badly designed because it makes no sense to custom draw on it in some situations. – Tom Feb 21 '15 at 18:38
  • It's not custom draw. It's owner draw. – David Heffernan Feb 21 '15 at 18:38
  • 1
    http://bcbjournal.org/articles/vol3/9909/Owner-drawn_list_boxes.htm – David Heffernan Feb 21 '15 at 18:39

1 Answers1

12

The focus rectangle is drawn by the VCL (*) in TCustomListBox.CNDrawItem after the OnDrawItem event handler returns.

procedure TCustomListBox.CNDrawItem(var Message: TWMDrawItem); 

...

  ..
    if Integer(itemID) >= 0 then
      DrawItem(itemID, rcItem, State)      //-> calls message handler
    else
      FCanvas.FillRect(rcItem);
    if (odFocused in State) and not TStyleManager.IsCustomStyleActive then
      DrawFocusRect(hDC, rcItem);          //-> draws focus rectangle
  ..
..

Whatever you draw in the event handler will later get focused by the VCL.


But notice that VCL use DrawFocusRect to draw the focus rectangle:

Because DrawFocusRect is an XOR function, calling it a second time with the same rectangle removes the rectangle from the screen.

So just call DrawFocusRect yourself and let VCL's call erase it:

procedure TForm1.ListBox1DrawItem(Control: TWinControl; Index: Integer;
  ARect: TRect; State: TOwnerDrawState);
begin
  with ListBox1.Canvas do begin
    Brush.Color := clWhite;
    Pen.Color := clWhite;
    FillRect(ARect);
    if odFocused in State then  // also check for styles if there's a possibility of using ..
      DrawFocusRect(ARect);
  end;
end;


(*) Normally default window procedure draws the focus rectangle for an owner drawn list box item in response to a WM_DRAWITEM message. But the default window procedure is not called for a list box in VCL's handling of the message.
Sertac Akyuz
  • 54,131
  • 4
  • 102
  • 169