Recent

Author Topic: Drawing empty items in a TListBox.  (Read 236 times)

Bazzao

  • Full Member
  • ***
  • Posts: 145
  • Pies are squared.
Drawing empty items in a TListBox.
« on: July 25, 2019, 12:08:40 am »
Searching around for a means of alternating background colour in a TListBox gave me lots of examples, and I ended up with this modification ...

Code: Pascal  [Select]
  1. procedure TForm1.ListBox1DrawItem(Control: TWinControl; Index: Integer;
  2.   ARect: TRect; State: TOwnerDrawState);
  3. begin
  4.   with (Control as TListBox).Canvas do begin
  5.     Brush.Style:=bsSolid;
  6.     if odSelected in State then
  7.       begin
  8.         Brush.Color:=clBlue;
  9.         Font.Color:=clWhite;
  10.       end
  11.     else
  12.     if Index=0 then
  13.       begin
  14.         Brush.Color:=clRed;
  15.         Font.Color:=clYellow;
  16.         Font.Style:=[fsbold,fsItalic];
  17.       end
  18.     else
  19.     if Index mod 2=1 then
  20.       begin
  21.         Brush.Color:=clSkyBlue;
  22.       end
  23.     else
  24.       begin
  25.         Brush.Color:=clMoneyGreen;
  26.       end;
  27.     FillRect(ARect);
  28.     Brush.Style:=bsClear;
  29.     TextOut(ARect.Left, ARect.Top, (Control as TListBox).Items[Index]);
  30.   end;
  31. end;

But the above only draws active items.

The problem is that my ListBox starts off empty and gradually fills from the top down, hence the Red background for item 0.

How do I draw empty items, taking into account that the bottom display item may not be fully visible (ie cut off half height).

Also I need to take into account that the list box will have a scroll bar and the last few items may only be visible.
Bazza

Lazarus 1.6.4 r54278 FPC 3.0.2 x86_64-win64-win32/win64
Windows 10.

winni

  • Full Member
  • ***
  • Posts: 170
Re: Drawing empty items in a TListBox.
« Reply #1 on: July 25, 2019, 12:52:18 am »
There is no other way then to do a little swindle:

Fill your listbox.items with spaces. If you got the next item for the box, than replace the space row with the new item.

DrawItem takes only the existing items in account, so the loop goes from 0 to items.count - 1. So theres is no other way - I think -  than this.

Winni

Bazzao

  • Full Member
  • ***
  • Posts: 145
  • Pies are squared.
Re: Drawing empty items in a TListBox.
« Reply #2 on: July 25, 2019, 01:16:27 am »
Yes, I actually thought something similar as a possible solution. I do like your term "swindle"  :D

My thoughts were along the line of:
1) An initial fill of spaced items;
2) On FormShow, drawing then clearing the ListBox.

... But was thinking that any future redraw would undo what I have done. Your last paragraph has given me much information.

Might give it a go.
Bazza

Lazarus 1.6.4 r54278 FPC 3.0.2 x86_64-win64-win32/win64
Windows 10.

Bazzao

  • Full Member
  • ***
  • Posts: 145
  • Pies are squared.
Re: Drawing empty items in a TListBox.
« Reply #3 on: July 25, 2019, 01:26:59 am »
Nope  :(

I tried adding 100 spaced items in FormShow, then
* Clearing;
* Deleting item 0, 100 times.

After each, the listbox went blank.

However retaining the 100 spaced items worked.

My next step is to determine how many items are in view and any spaced items out of view are deleted.
Bazza

Lazarus 1.6.4 r54278 FPC 3.0.2 x86_64-win64-win32/win64
Windows 10.

Bazzao

  • Full Member
  • ***
  • Posts: 145
  • Pies are squared.
Re: Drawing empty items in a TListBox.
« Reply #4 on: July 25, 2019, 02:04:34 am »
I am getting a division by zero error:

Code: Pascal  [Select]
  1. procedure TForm1.FormShow(Sender: TObject);
  2. var I,J:integer;
  3. begin
  4.   for I:=1 to 99 do
  5.     ListBox1.Items.Add(' ');
  6.   ListBox1.Items.Add('GgIiJjKkLlMPpQqTtWYy');
  7.   ListBox1.Repaint;
  8.   J:=ListBox1.Height div ListBox1.ItemHeight;
  9.   for I:=J+1 to 100 do
  10.     ListBox1.Items.Delete(J);
  11. end;
  12.  

The last item added 'GgIiJjKkLlMPpQqTtWYy' should give me a height including descenders.
Bazza

Lazarus 1.6.4 r54278 FPC 3.0.2 x86_64-win64-win32/win64
Windows 10.

Bazzao

  • Full Member
  • ***
  • Posts: 145
  • Pies are squared.
Re: Drawing empty items in a TListBox.
« Reply #5 on: July 25, 2019, 03:30:04 am »
I found the cause of ItemHeight being 0.

It is not set when Style is lbOwnerDrawFixed.

So here is the solution.

Code: Pascal  [Select]
  1. procedure TForm1.FormShow(Sender: TObject);
  2. var I,J:integer;
  3. begin
  4.   ListBox1.Style:=lbStandard;
  5.   ListBox1.Items.Add('GgIiJjKkLlMPpQqTtWYy');
  6.   ListBox1.Repaint;
  7.   gItemHeight:=ListBox1.ItemHeight;
  8.   if gItemHeight=0 then
  9.     gItemHeight:=15; // Just in case.
  10.   ListBox1.Style:=lbOwnerDrawFixed;
  11.   ListBox1.Clear;
  12.   for I:=1 to 100 do
  13.     ListBox1.Items.Add(' ');
  14.   ListBox1.Repaint;
  15.   J:=ListBox1.Height div gItemHeight;
  16.   for I:=J+1 to 100 do
  17.     ListBox1.Items.Delete(J);
  18.   ListBox1.Repaint;
  19. end;

gItemHeight is a global variable, in case I need to use the ItemHeight elsewhere.



Bazza

Lazarus 1.6.4 r54278 FPC 3.0.2 x86_64-win64-win32/win64
Windows 10.