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.
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
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.
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.
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 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.
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.
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.