Recent

Author Topic: TListBox ownerdraw problem.  (Read 7334 times)

knuckles

  • Full Member
  • ***
  • Posts: 127
TListBox ownerdraw problem.
« on: May 22, 2016, 01:37:09 am »
I am trying to ownerdraw a TListbox control but I cannot seem to get it to work or look right, maybe I am missing something obvious I don't know.

Please see the quick example below:

Code: Pascal  [Select][+][-]
  1. procedure TForm1.ListBox1DrawItem(Control: TWinControl; Index: Integer;
  2.   ARect: TRect; State: TOwnerDrawState);
  3. begin
  4.   with ListBox1.Canvas do
  5.   begin
  6.     if (odSelected in State) then
  7.     begin
  8.       Brush.Color := clCream;
  9.       Pen.Color := clGreen;
  10.       FillRect(ARect);
  11.       Rectangle(ARect);
  12.       DrawFocusRect(ARect);
  13.     end
  14.     else
  15.     begin
  16.       Brush.Color := ListBox1.Color;
  17.       Pen.Color := ListBox1.Color;
  18.       FillRect(ARect);
  19.     end;
  20.  
  21.     Font.Color := clWindowText;
  22.     TextOut(ARect.Left, ARect.Top, ListBox1.Items[Index]);
  23.   end;
  24. end;

The problem is the rectangle around the selected item shows a partially dotted focus instead of a solid pen line. If I remove the DrawFocusRect(ARect) line then this issue still occurs only now the pen color seems to become purple.

I am using Lazarus v1.6, Windows 10, I have also set the Style property of the listbox to lbOwnerDrawVariable.

What am I doing wrong? I just need to color selected items with a custom fill and border color but couldnt figure out why I keep running into various graphical problems with how the items are drawn.

Thanks.
« Last Edit: May 22, 2016, 12:51:36 pm by knuckles »

engkin

  • Hero Member
  • *****
  • Posts: 3112
Re: TListBox ownerdraw problem.
« Reply #1 on: May 22, 2016, 02:51:20 am »
DrawFocusRect is called twice: once by your code, and again by LCL:
Code: Pascal  [Select][+][-]
  1. procedure TCustomListBox.LMDrawListItem(var TheMessage: TLMDrawListItem);
  2. begin
  3. ...
  4.     DrawItem(ItemID, Area, ItemState); <--- this calls your OnDrawItem
  5.     if odFocused in ItemState then
  6.       DrawFocusRect(DC, Area);   <--- the second time
  7. ...
  8.  

The way DrawFocusRect works is by reversing colors and TextOut is using the same ARect which fills the background around the text (and deletes part of your DrawFocusRect) which shows part of the second DrawFocusRect call.

Simple solution:
1-Don't call DrawFocusRect.
2-Shift the coordinates in TextOut a bit so it does not delete your FillRect and to leave some margin away from the rect.

knuckles

  • Full Member
  • ***
  • Posts: 127
Re: TListBox ownerdraw problem.
« Reply #2 on: May 22, 2016, 12:48:25 pm »
I'm actually moving over some code from Delphi and I don't remember running into too many problems with this kind of thing, in Lazarus it seems a little more problematic.

So I commented out the TextOut line and sure enough I can see the selected item and border is drawn correctly now. It seems in Lazarus it is a little bit more picky as I now have to define the correct item heights and change the rect slightly for the item text.

Now I cannot seem to get the text to display centered without interrupting the rectangle around the selected item?

Thanks.
« Last Edit: May 22, 2016, 12:52:22 pm by knuckles »

tk

  • Sr. Member
  • ****
  • Posts: 368
Re: TListBox ownerdraw problem.
« Reply #3 on: May 22, 2016, 01:09:14 pm »
I'm actually moving over some code from Delphi and I don't remember running into too many problems with this kind of thing, in Lazarus it seems a little more problematic.

Lazarus is great project but moving from Delphi is still more or less painful (but is definitely better now than some 5 years ago, though). That's why I also made my KControls both Delphi and Lazarus compatible, to be able to port our projects more quickly.

List boxes: Some time ago we've replaced all TListBoxes with KGrids in our bigger project we plan to port to Lazarus. Not just because of problems you are reporting now.

knuckles

  • Full Member
  • ***
  • Posts: 127
Re: TListBox ownerdraw problem.
« Reply #4 on: May 22, 2016, 02:37:46 pm »
Lazarus is great project but moving from Delphi is still more or less painful (but is definitely better now than some 5 years ago, though). That's why I also made my KControls both Delphi and Lazarus compatible, to be able to port our projects more quickly.

List boxes: Some time ago we've replaced all TListBoxes with KGrids in our bigger project we plan to port to Lazarus. Not just because of problems you are reporting now.

Yes it is a little frustrating trying to move code from Delphi to Lazarus when things dont seem to work, the ARect parameter for example in the ListBox DrawItem method should not need inflating or offsetting etc to fit the text, it should just work.

I think I am going to reinstall my Delphi and work with both IDE's, I know the code in the first post is a quick example but I am certain it worked in Delphi.

engkin

  • Hero Member
  • *****
  • Posts: 3112
Re: TListBox ownerdraw problem.
« Reply #5 on: May 22, 2016, 05:41:07 pm »
the ARect parameter for example in the ListBox DrawItem method should not need inflating or offsetting etc to fit the text, it should just work.

That's not true. I don't think you want the text to touch the focus rectangle. But maybe you don't want to use TextOut as it paints the background again. Use TextRect which gives more flexibility including leaving the background intact, centering the text vertically, and adding two pixels as a margin:
Code: Pascal  [Select][+][-]
  1.     tmpStyle := TextStyle;
  2.     tmpStyle.Layout := tlCenter; { Center the text vertically }
  3.     tmpStyle.Opaque := False;  { Leave the background intact }
  4.     TextRect(ARect, ARect.Left+2 {margin} ,ARect.Top, ListBox1.Items[Index], tmpStyle);

I think I am going to reinstall my Delphi and work with both IDE's, I know the code in the first post is a quick example but I am certain it worked in Delphi.

I doubt it.

 

TinyPortal © 2005-2018