Listbox: Know when Sorting is done?

I have situation in a hierarchical listbox where i am using alternating background colors for the top level items, but when I expand a row I want the child rows to take the color of the parent so simply doing Row Mod 2 in cellBackgroundpaint does not cut it…

It is easy to do if the list is not sortable(Assign row color to rowtag of top-level items… But that breaks down if one allows sorting by column (which I need to do). I am pretty sure I solved this is the past but I don’t remember how and can’t find the code.

The obvious thing would be to reassign the row colors after a sort…but how to tell the sorting is finished? The best thing I could think of is fire a timer with a period of 1 that gets reset in CompareRows so the action event does not fire until sorting is complete… but that would fire for non visible rows sop potentially lot of unneeded overheard.

Any other way to do this? I wish there was a SortEnd event!

-Karen

One way is to not use stored color at all, but backtrack to the ExpandableRow to get the color from it. You can do this on column 0, store it in the row, then use that color for the next column (assuming the columns are drawn in order).

All the columns are the same color… I’m taking about the rows…

Say I was using White and green rows using row Mod 2 in cell background paint to color the rows

Unopened:
White
Green
White
Green

If I understand what you are saying doing what you said if I open a node with one child I could wind up with

White
Green
— Green
Green
White

When what I want is:
White
Green
— Green
White
Green

-Karen

I got what you meant, but I see the problem with my solution. The ExpandableRow doesn’t know if it’s even or odd either.

What about starting a Timer in the SortColumn event before returning False? The Timer will go through and assign colors to each of the ExpandableRows, then call Invalidate… The child rows will get its color from the first ExpandableRow above it, or the Timer can assign those too.

That was what I was thinking but could not the timer fire between compare row event (if it is implemented) calls?

That is why I was thinking I would need to reset a timer on each comparerows event call so it would only fire after the sorting is done, not during…And this needs to be Xplatform so I need to be careful about platform differences in how events are fired.

But I think compare rows likely fires for non visible rows, so if a listbox has a lot of rows that could be a lot of overhead.

-Karen

The Timer is going to fire on the main Thread, and the sorting takes place on the main Thread, so by definition (unless it does something unexpected in the background), the Timer will fire after the sort.

I was afraid of depending on that X-Platform. I assume the sort happens in a loop, and I was nervous that the timer might be able to run on loop boundaries in some cases as can happen with xojo code without disable backgroundtasks.

If it’s safe to assume the timer can’t fire before the sort if finished on all platforms (even if the CompareRows event is Implemented) then it’s simple.

thanks,
-Karen

Timers are not Threads so they will not preempt code on the main Thread (unless you do something ill-advised like call DoEvents). The only possibility is that the Sort code runs in a Thread and will finish after the Timer fires, but a sufficient long Timer.Period should mitigate even that possibility.

Another thought: set a flag IsSorting in SortColumn, then check it in CellBackgroundPaint. If it’s true, update all the colors, set it to False, then proceed with drawing.

I have use that trick to create all sort of listbox "events’ in the past.
I tried that first and it did not seem to work, but maybe I messed up the code… (whole listbox turned the same color!) I try it again.

-Karen

I did alternating row colors where children rows were their parent color in ARGen. You might like my idea or you might think it’s trash - but I’ve solved this problem before :slight_smile:

1 Like

Hi Tim,

I was looking through your code on that container (from when I downloaded it when it was fits open sourced), but to looks likes the HeaderPressed event is coded to prevent sorting, which is what complicates this.

Function HeaderPressed(column as Integer) Handles HeaderPressed as Boolean
  #pragma unused column
  
  me.HasHeading = false
  me.ColumnSortDirection(column) = Listbox.SortNone
  me.SortedColumn = -1
  me.HasHeading = true
  
  return true
End Function

Am i missing something?

Thanks
-Karen

That entire method in Argen can also be eliminated with something similar to

me.HeaderType(0)=Listbox.HeaderTypes.NotSortable

Eliminating sort completely with no headerpress needed

***Digging up some code this evening - have a custom listbox that does what you’re looking for. :slight_smile:

Oh no, I suppose I forgot I had done that. The way the control is used the categories aren’t supposed to be sortable. I think your timer reset method should work out though because it will recalculate the row colors after the sort has finished.

When I tried that the first time I messed it up (i was modifying code I wrote 10 years ago that i did not recall all the nuances of) I went back and special cased it for my current application and it worked… at least in a Mac.

I’m depending on the Xojo listbox not repainting rows until the sort is done on all platforms… of course for optimal performance, that is how it SHOULD be coded, so I’ll use it until testing on another platform shows it is not.

Thanks Kem and all for your suggestions.

-Karen

1 Like