DeskTopListBox PaintCellBackground event fails

I’m populating a list box with List Items and Category Sections. I want the Category cell background to be filled using a CellTag as the trigger.

The code from the load method is:

If (data.Field("IsSection").StringValue)="Yes" Then
  
  Window1.TaskListBox.CellTypeAt(ref, 0) =DesktopListBox.CellTypes.CheckBox
  Window1.TaskListBox.CellTagAt(ref, 0)="Yes"
  'CellState(ref,0) =CheckBox.CheckedStates.Checked
  
End

The code in the PaintCellBackground event is as follows:

If Me.CellTagAt(row, Column) = "Yes" Then
  
  g.ForeColor = RGB(89,181,246)
  g.PenHeight = 1
  g.DrawRoundRect(0, 3, 220, 30, 15, 15)
  g.ForeColor = RGB(224,243,210)
  g.FillRoundRect(2,5, 220, 26, 15, 15)
  
End If

All works fine. The rows that are tagged have a checkbox and are painted with a rounded green rectangle until you attempt to scroll through the list which then throws an Out of Bounds exception. I substituted my code for code straight out of the documentation. Same result. Any ideas? I’m thinking it might be a bug in the PaintCellBackground event. Tried some workarounds with list index and so forth to no avail.

Where does the exception occur? What are the row/col values when it occurs? (on the assumption that it occurs inside the background paint event)

There’s a Screen shot. I neglected to mention that as soon as I comment all the code out of the PaintCellBackground event it all works just fine.

Hmmm. This is a test list I created a while back. I’m 72 and wonder why I put diapers on the list.

1 Like

You should maybe check, if the CellTagAt <> Nil, since the PaintCellBackground-Event handles all rows/cells, even empty ones.

1 Like

Thanks Martin, just tried it with the same result.

This, straight from the Xojo documentation produces the same Out of Bounds error.

This example paints the cell background red if the CellTag contains the string “Red”:

If Me.CellTagAt(row, column ) = "Red" Then
  g.DrawingColor =Color.RGB(255, 0, 0)
  g.FillRectangle(0, 0, g.Width, g.Height)
End If
If row > Me.LastRowIndex Then Return False

If Me.CellTagAt(row, column ) = "Red" Then
  g.DrawingColor =Color.RGB(255, 0, 0)
  g.FillRectangle(0, 0, g.Width, g.Height)
  Return True
End If
1 Like

PaintCellBackground gets called for every visible row, whether it contains data or not. I suspect you have a partial row at the bottom of the listbox and as soon as you scroll all the way down, it’s trying to paint that row. If so, you need to wrap your code in

if row <= me.LastRowIndex then
   ...
end if

That way you’re not trying to get the celltag for a row that doesn’t exist.

2 Likes

Tim and Martin

Thank you.
Both your solutions worked equally well.

Simple way to reproduce, Opening event:

for i as integer = 0 to 99
  me.AddRow(i.ToString)
  if i mod 2 = 0 then
    me.CellTagAt(me.LastAddedRowIndex, 0) = "Red"
  end if
next i

PaintCellBackground

If Me.CellTagAt(row, column ) = "Red" Then
  g.DrawingColor =Color.RGB(255, 0, 0)
  g.FillRectangle(0, 0, g.Width, g.Height)
End If

scroll down until you get the OutOfBoundsException.

Why is Xojo trying to paint Row 100?

Xojo should not try to paint a non-existent row or the docs/sample code should mention that we need to add code to avoid the OutOfBoundsException?

Agreed Alberto. The documentation should be amended to reflect that.

If your listbox height is such that any part of an additional row is visible when you have scrolled down, Xojo has to paint row 100. If you size the listbox exactly, you won’t run into the issue.

And yes, the docs should mention it. This keeps coming up over and over in the forum. But to be fair, there are many reasons to implement PaintCellBackground that have nothing to do with the contents. It’s only when you try to access the contents of the row that you have a problem.

1 Like

All very true Tim. Sizing the ListBox to the data is not always feasible. The solution was very simple although it took three hours of experimenting before I asked for help or searched the forum. Thanks again. I have another issue but that’s for a bit later and it’s only a “wouldn’t it be nice issue”.

Yes, and what were the row/col values?

Yes it should. Suppose you want to have a simple background in all rows, such as alternating colours (see their example). You would want this in all visible rows, whether or not you have added them yet.

You might also want to beware of what happens with MouseDown. IIRC, you will find you get a mousedown event even if you click in the listbox’s scrollbar or in one of the “rows” you haven’t added yet. The row/col are not supplied to MouseDown, but can be derived, and you better check for either of these being -1.

And yes, it is useful to get a MosueDown event even if it appears to make no sense. I use it to know the user has clicked in the ListBox but outside any row - so I can deselect any selected row.

1 Like

Thank you, that makes sense.

What I’m trying to illustrate (and I don’t know if there is an easy fix with docs or otherwise) is that a new Xojo user reads the docs, finds this code, creates a new project, adds a List box, adds the code to PaintCellBackground and now they get an OutOfBoundsException

If Me.CellTagAt(row, column ) = "Red" Then
  g.DrawingColor =Color.RGB(255, 0, 0)
  g.FillRectangle(0, 0, g.Width, g.Height)
End If

What the new user will think of Xojo and/or Xojo docs?
BTW the OutOfBoundsException has no message or reason. Hard for a new user to understand what is wrong and how to fix it.

Hi Tim,

The row value is set with Var ref as Integer and then iterates through an sqlite DB to get each record that should have a cell paint. The column is always at 0 since it’s only the first column that needs cell paint like this:

If data <> Nil Then
  While Not data.EOF
    
    
    Window1.TaskListBox.AddRow(data.Field("Name").StringValue), (data.Field("ID").IntegerValue.ToText)
    
    //(data.Field("ID").IntegerValue.ToText, data.Field("Name").StringValue)
    '//(data.Field("Name").StringValue)
    
    
    
    If (data.Field("IsSection").StringValue)="Yes" Then
      
      Window1.TaskListBox.CellTypeAt(ref, 0) =DesktopListBox.CellTypes.CheckBox
      Window1.TaskListBox.CellTagAt(ref, 0)="Yes"
      //CellState(ref,0) =CheckBox.CheckedStates.Checked
      
    End
```and the the CellTag triggers the paint event.

Perhaps the new user might wonder what a celltag is and how a cell gets to have one, and why his own listbox needs one. If you shove random code into a program you’ll most likely run into problems.

I do agree that the docs might contain more in the way of things to watch out for. The reason I was asking the OP whether he’d looked at what row/col values were at the point the exception happened, was that if the row value is greater than the number of rows, you might guess that PaintCellBackground doesn’t stop at just the rows added by the program, and that there’s a reason why this is so. And this would point at a way to avoid the exception.

This approach is reinforced by that the error is “Out of bounds”. Well now, what variable are in play in the statement that gets the error? There’s only row and column.

1 Like