Listbox Performance

Hi everyone,

I use a Listbox to draw the items of an array to the screen. The array can have different subclasses of fruits. Each fruit will have her own drawing procedure. So i add the fruits to the Listbox:
[h]FruitsListbox.Init[/h]

[code]Dim count As Integer = Fruits.Ubound

For I As Integer = o To count
Me.AddRow
Me.CellTag(Me.LastIndex, 0) = i

Select Case Fruits(i)
Case IsA Apple
Me.RowTag(Me.LastIndex) = FruitsListbox.RowType.Apple
Case IsA Banana
Me.RowTag(Me.LastIndex) = FruitsListbox.RowType.Banana
End Select
Next[/code]

[h]FruitsListbox.CellBackgroundPaint[/h]

[code]’ Background color
g.ForeColor = &cFFFFCC00
g.FillRect(0, 0, g.Width, g.Height)

If row < Me.ListCount Then

Select Case Me.RowTag(row)
Case FruitsListbox.RowType.Apple
DrawApple(g, Apple(Me.Fruits(Me.CellTag(row, 0))), row)
Case FruitsListbox.RowType.Banana
DrawBanana(g, Banana(Me.Fruits(Me.CellTag(row, 0))), row)
End Select

End If

Return True[/code]

The Listbox performance is really bad. The CPU climbs up more and more, by resizing the Window or scrolling the Listbox. Also the resizing by double clicking the Window’s Titlebar isn’t smooth. Is there any way to get it more soft and with less CPU performance? This is just a test, but after the Listbox will have e.g. 5000 rows and much more. I tried this also with @jim mckay s DataView, but this is even more performance-intensive.

Here is the sample project.

Thanks!

First off… .DO NOT redraw your fruit in the CellBackgroundPaint
Pre-process the graphics (after all the “Apple” is still going to look the same, right?) and use ROWPICTURE instead

The performance is “bad” because you was burning tons of CPU resources doing unnecessary things over and over

For I As Integer = o To count
  Me.AddRow
  Me.CellTag(Me.LastIndex, 0) = i

  Select Case Fruits(i)
  Case IsA Apple
    Me.RowTag(Me.LastIndex) = FruitsListbox.RowType.Apple
    Me.Rowpicture = DrawApple()
  Case IsA Banana
    Me.RowTag(Me.LastIndex) = FruitsListbox.RowType.Banana
    Me.RowPicture = DrawBanana()
  End Select
Next

It runs fine on mine.

Such a small amount of rendering shouldn’t be causing that noticeable of an issue, what you’re doing is fine, caching isn’t going to save you that much time.

Listbox size wont matter, the draw calls are only made for what actually fits on the screen.

What is the spec of your machine? CPU, graphics etc.

I only like to say it in rare occasions, have you tried a reboot?

I don’t see any Apple nor Banana … :frowning:

I’d think twice about doing it this way at all
This is very “procedural” approach and a more OO one can make our life a whole lot easier

With the way it is now every time you addd a new fruit you have to

  • add the fruit (most likely with all public properties so the drawing can access them)
  • add a method to the listbox to draw that fruit (which means that the listbox has to intimately know the innards which is a bad sign)
  • update the row type enumeration

It would be better if EVERY fruit knew how to draw itself into the graphics given (and its probably more reusable since the graphics could be from a printer, canvas, etc and each fruit could draw differently if there is enough room)

ie

Class Fruit
   Sub Draw(g as graphics)
End Class

Class Banana
   Sub Draw( g as graphics)
      // whatever a banana needs to do to draw itself
   end Sub
End Class

Class Apple
   Sub Draw( g as graphics)
      // whatever an apple needs to do to draw itself
   end Sub
End Class

Then to add a fruit you add a fruit and its specific drawing and your done except for adding instances to the listbox itself

And then your Fruitslitsbox CellBackgroundPaint turns into something simple like

' Background color
g.ForeColor = &cFFFFCC00
g.FillRect(0, 0, g.Width, g.Height)

If row < Me.ListCount Then
  
  Dim aFruit As Fruit = self.RowTag(row)
  if aFruit <> nil then aFruit.Draw(g, row = me.listindex)  // <<<<<< the magic of polymorphism makes this work !
  
End If

Return True

And initializing the fruits becomes simple too

Dim apple As Apple

apple = New Apple
apple.MyName = "Granny Smith"
apple.MyWeight = "150 g"
apple.MyColor = "green"
FruitsListbox1.AddRow ""
FruitsListbox1.rowtag(FruitsListbox1.LastIndex) = apple

Dim banana As Banana

banana = New Banana
banana.MyName = "Cavendish"
banana.MyColor = "yellow"
banana.Amount = 12
FruitsListbox1.AddRow ""
FruitsListbox1.rowtag(FruitsListbox1.LastIndex) = banana

apple = New Apple
apple.MyName = "Graham"
apple.MyWeight = "90 g"
apple.MyColor = "yellow/red"
FruitsListbox1.AddRow ""
FruitsListbox1.rowtag(FruitsListbox1.LastIndex) = apple

No need to store the fruits array and the cell tags

Like this http://great-white-software.com/miscellaneous/FruitsListbox.xojo_binary_project

Ok, but if I only draw Listboxs background color, it’s also very slow. Only these two lines making the performance also bad:

' Background color g.ForeColor = &cFFFFCC00 g.FillRect(0, 0, g.Width, g.Height)
Thank you all so much for your input.[quote=352455:@JulianS]What is the spec of your machine? CPU, graphics etc.[/quote]
Retina iMac 21,5, 2015, 8GB RAM

Everything you can imagine is possible :wink:

You are right! Thanks for your inout, I’ll check this.

Great community!