Bug in Listbox for 2014r2

The listbox in 2014r2 has some buggy behavior. I’ve found a workaround but want to report.

OK. So first off, the idea is that the listbox is going to present data contained in a multidimensional array on the backend. I’m using a version of this in another program. The backend array has 2 extra columns, 1 specifies folder versus not, the other specifies expanded vs. not. (in practice this can be condensed into 1 extra column because only folders can be expanded or not, but for ease of following the program i broke it into two in the example below).

There is a routine, updateFrontEnd, that brings the listbox into alignment with the settings stored in the backend array. Unfortunately, when the .expanded property is set programmatically in this routine, it also triggers the ExpandRow and/or CollapseRow events of the listbox. I consider this to be the first bug - the documentation says these events are triggered when the user CLICKS the disclosure triangle, NOT when the property is set/changed.

Second, you’ll notice that I add my folders and rows in 1 of 2 ways.

Listbox1.AddFolder(mydata(i,0)) //Listbox1.InsertFolder(row, mydata(i,0), 0)

Listbox1.AddRow(mydata(i,0)) //Listbox1.InsertRow(row, mydata(i,0), 0)

So, when using addrow/addfolder, the folders and rows populate as expected BUT the indentation is all messed up. Some of the top level folders have indentation, as if they were regular rows. (That is, the disclosure triangle is inline with the beginning of the text for a regular row)

The indentation property only seems to be accessible when ‘inserting’ a folder or row, so I switched to using the ‘insert’ property for the folder only (at first) because this was where the indentation was wrong. WOW that caused problems. If using ‘insertfolder’ and ‘addrow’, then when users click expand or collapse the program completely goes awry, adding disclosure triangles where they shouldn’t exist, etc.

The crazy thing here is that this only is a problem when the ‘updateFrontEnd’ routine is called from the collapseRow or expandRow event. When I use the pushbutton to call the routine (after changes have been made) it works fine.

Finally, if using insertfolder AND insertrow, everything works as expected. No harm, no foul - as all is working - but this seems like buggy behavior and not sure if it has been addressed in later versions, as 2014r2 is the latest to which I have access.

Set up the following simple program to replicate this (again, done on 2014r2).

  1. The following properties for window1:

mydata(-1,-1) as string userClick as boolean = false

  1. The following methods for window1.
    Constructor:

[code] // Calling the overridden superclass constructor.
Super.Constructor

redim mydata(25,2)

dim i as integer

mydata(0,0)=“folder1”
mydata(3,0)=“folder2”
mydata(7,0)=“folder3”
mydata(10,0)=“folder4”
mydata(16,0)=“folder5”
mydata(21,0)=“folder6”

mydata(0,1)=“folder”
mydata(3,1)=“folder”
mydata(7,1)=“folder”
mydata(10,1)=“folder”
mydata(16,1)=“folder”
mydata(21,1)=“folder”

mydata(0,2)=“true”
mydata(3,2)=“true”
mydata(7,2)=“true”
mydata(10,2)=“true”
mydata(16,2)=“true”
mydata(21,2)=“true”

dim parentF as integer=0
dim childnum as integer =0

for i=0 to 25
if mydata(i,1)=“folder” then
parentF=i
childnum=1
end if

if mydata(i,1)<>"folder" then 
  mydata(i,0) = "child"+str(childnum)
  mydata(i,1) = "child"
  mydata(i,2) = str(parentF)
  childnum=childnum+1
end if

next

updateFrontend[/code]

UpdateFrontEnd

[code] listbox1.DeleteAllRows

dim row as integer =0
dim i as integer
for i=0 to 25
//MsgBox “i=”+str(i)+": “+mydata(i,0)+”, “+mydata(i,1)+”, "+mydata(i,2)
if mydata(i,1)=“folder” then

  Listbox1.AddFolder(mydata(i,0))
  //listbox1.InsertFolder(row, mydata(i,0), 0)
  
  if mydata(i,2)="true" then listbox1.Expanded(listbox1.LastIndex)=true
  if mydata(i,2)="false" then listbox1.Expanded(listbox1.LastIndex)=false
  
  listbox1.RowTag(row)=i
  row=row+1
else
  
  dim myParent as integer = val(mydata(i,2))
  if mydata(myParent,2)="true" then
    
    listbox1.AddRow(mydata(i,0))
    //listbox1.InsertRow(row, mydata(i,0), 0)
    
    listbox1.RowTag(row)=i
    row=row+1
  end if
end if

next[/code]

  1. On the front end, listbox1 and pushbutton1 objects.
    Listbox1 has the following events:

collapserow

[code] if userClick=false then return
userClick=false

dim backend_index as integer = listbox1.RowTag(row)
mydata(backend_index,2)=“false”
updateFrontend
[/code]

expandrow

[code] if userClick=false then return
userClick=false

dim backend_index as integer = listbox1.RowTag(row)
mydata(backend_index,2)=“true”
updateFrontend[/code]

mousedown

userClick=true

pushbutton1 has action event

//refresh the frontend updateFrontend

This would be a documentation bug

secondly try a newer version as there may already be fixes that affect this in newer versions

Confirmed that this is not a bug in the listbox but “by design”
The docs are wrong (which happens from time to time)
They should say “The user has clicked the disclosure OR the rows expanded property was set”
Collapserow is similar

I’ll fix that

I do not have access to a newer version, based on my current license, and would likely have to jump through some hoops to get funding approval.

[quote=270925:@Norman Palardy]Confirmed that this is not a bug in the listbox but “by design”
The docs are wrong (which happens from time to time)
They should say “The user has clicked the disclosure OR the rows expanded property was set”
Collapserow is similar

I’ll fix that[/quote]

Thanks on this - it certainly addresses my first concern.

However, if you look at the example program (takes ~10 min to build) there are two additional issues:

  1. The insertfolder function claims to default to indent 0 but it does not always do so. You can test this when using addfolder/addrow to build the listbox. Some addfolders have non-zero indentation when ‘updateFrontEnd’ is called from the ExpandRow or CollapseRow event. This doesn’t seem to happen when the method is called from a pushbutton.

  2. When using insertfolder for folders and addrow for non-folders, the listbox goes completely haywire on my end when the updateFrontEnd routine is called from ExpandRow or CollapseRow. If I add an app.doevents() to the loop in updateFrontEnd, it is a little better. If I add add.doEvents(25), almost resolved - add.doEvents(100) seems to resolve it but is very slow. It seems like the ‘insertfolder’ method hasn’t finished its job by the time the ‘addrow’ method from the next loop iteration is called. Again, if the ‘updateFrontEnd’ routine is called from the pushbutton, everything works without app.doevents. This odd behavior only occurs when called from ExpandRow / CollapseRow.

I can be available to demonstrate this by WebEx, etc., if you like.

EDIT: This does seem to happen in both debug and build versions but I have not tested it on multiple machines.

You can try the very latest version for free by downloading it from xojo.com. You can run your project in there. The only thing you may not do with the evaluation is to build without a license.

AddRow and AddFolder behave differently when called during the ExpandRows event. From the docs

What that means is calling AddRow during ExpandRow doesn’t add the item at the end of all rows, it adds the items directly after the row being expanded. It also applies the correct indentation. This way, in the ExpandRows event you only have to AddRow and don’t need to care about the row indices or indentation.

You are calling UpdateFrontend in the window’s constructor. You should move that code to the window’s Open event.

[quote=271164:@Will Shank]AddRow and AddFolder behave differently when called during the ExpandRows event. From the docs
[/quote]

My sincere apologies. This answers everything. I don’t see this:

in the docs. I’m looking at http://documentation.xojo.com/index.php/ListBox.ExpandRow and I see This code adds children to the expanded row: and the example now makes sense … but if addrow added rows the end of the listbox, the same code would work - so it isn’t that clear and could use a bit more description.

Thanks all!

Actually it wouldn’t. If you had three folders and the user expanded the middle one, adding to the end of the listbox wouldn’t get you what you wanted.

[quote=271159:@Judy Esau]I do not have access to a newer version, based on my current license, and would likely have to jump through some hoops to get funding approval.
[/quote]
You can try many versions without having to buy them.
You can download the latest & just run your project.
Dont use it to make changes as you can only save in binary & you cant build an executable - but you can try everything else.

[quote=271228:@Judy Esau]My sincere apologies. This answers everything. I don’t see this:
[/quote]
http://documentation.xojo.com/index.php/ListBox.AddRow in Notes

I wrote a small app to test this out & I cannot make insertrow or insertfolder insert at anything other than 0 IF I do not use the indent parameter
FWIW you CAN get the “depth” of the row being expanded or collapsed in the ExpandRow or CollapseRow events with

    dim indent as integer = me.RowDepth( row )

Then you can add rows using insertrow or insertfolder at the right depth with

  me.InsertRow(row + 1, "non folder row") , indent + 1)
  me.InsertFolder(row + 2, "folder row") , indent + 1)

But as Will noted if you JUST use addrow or addfolder they’ll be added at the right indent level

Thanks again.

What I was observing was that when I blasted the listbox rows and re-added everything fresh, everything (folders and non-folders) was a child of the expanded/collapsed folder. This makes sense now but initially I wanted my folders all inline, at the top level, and the rows to be indented 1x.

Anyway, this was my misunderstanding. Thanks again.