DesktopListbox: repainting when not really necessary

I have a DesktopListbox inside a DesktopContainer, with an instance of the container on a PagePanel. I can resize the PagePanel, and even though the listbox is not resized by this action, every cell is repainted many times as the resizing takes place, leading to a poor user experience due to jerkiness.

Is anyone aware of any tricks to mitigate this sort of behaviour? At the moment I’ve taken the listbox off the pagepanel and just let it be another control in the window, and while that avoids the repainting hassle, it introduces the need for a lot of extra code to manage what the pagepanel was doing.

The usual questions: Which OS? Which version of the OS? Which version of Xojo? These days it’s hard to do any flickering on macOS.

How does your code look like? Do you have anything which forces a refresh? How do you get small icons in a listbox to make problems at all?

Any OS, really, although it’s best on macOS; using 2023r4 just now. Symptoms are that the splitter bar tends to move much more smoothly if I take the listbox off the pagepanel. Yesterday I tried having the paint event just return (i.e. do nothing) 90% of the time. But it seems that, internally, the cell is cleared before the Paint event is called, so that ended up looking very bad, although it did show that the Paint event gets called continuously.

I need to look and check if your fifth question may hold a clue.

On Windows there is a setting for whether a window is repainted during a resize event. (‘Live’)
I wonder if that is affecting a pagepanel - treating it like a full on window?

The windows listbox is a terrible flicker merchant.

Over the years, Ive tried

  • replacing the listbox with a picture ‘taken’ of the listbox while such things are happening,
  • keeping pictures of what the cell looked like last time it was actively drawn, and just painting the static picture
  • turning off the scrollbars

More recently, I combined some cells that had custom drawing - where I might have had 3 columns each with a drawing thing, now I have 1 cell that shows all 3 things.
It made quite a difference to speed, since it reduced the paint calls by 2 * rowcount during every refresh.

What splitter do you use? And yes, the splitter should move smoothly.

IMSplitter. I’ve modified it for DesktopXxxx containers and controls.

I’m using that one, too, all over my software. But I have never seen it run other than smooth. And I have really complicated windows with lots of containers.

Edit: But I’m still on Desktop API 1 controls.

1 Like

I’m not at my desk just now so can’t check things until I get home, later.

I need to check that I’ve not inadvertently got anything that might refresh a listbox, buried in there. I’m also restructuring the pagepanel so that each panel has just the one DesktopContainer on it, and nothing else.

Moving the bottom splitter was causing the panel to be resized. The listbox is on the panel, and is being repainted even though its visible size does not, in fact, change. On macOS that is slightly jerky but not too bad. It’s in Win/Lin (each in a VM) that I have issues with smoothness. I’m running Sonoma 14.4.1 in a 2018 Mini.

In the distant past I never got this idea to work quite right , but I have not tried it in a long time.

When you are starting to resize, use DrawInto to draw the listbox into a picture, make the listbox invisible and paint the picture in it’s place.

-Karen

2 Likes

The problem is the fundamental design of the Xojo Listbox, which was great for the 1990s, but things have advanced since then.

Each cell is drawn directly to the List’s view buffer, so when the view is resized or a refresh on the view is called, every single visible cell must be redrawn.

In other development tools, their list views actually contain sub views for the cells and are typically fixed type views “text”, “Image” etc. These allow for view caching per cell element, which reduces the draw time of the list control and improves smoothness. This also allows for lazy view rendering and element recycling.

One way I worked around this back in the day was to use an array of labels atop a canvas inside a NSScrollView.

2 Likes

Sam’s approach definitely works, and can actually simplify things greatly. The Listbox offers lots of functionality, but sometimes you only need a subset of that for your applications.

We used Sam’s approach for a Xojo Web 1 application, where we needed a “pseudo” Listbox that contained a label and a checkbox on each Row. This was primarily needed to facilitate touch interfaces. Rather than using a Listbox, we constructed some simple nested container controls and populated a canvas. Then we added a very limited number of Event Definitions to the Containers.

While we were developing a Web Application, a similar approach should work on the Desktop as well.

Be mindful that this approach is geared around dynamically instantiating containers and assigning Event Handlers on the fly. There is a bit of a learning curve for that, but it is well worth it.

1 Like

Can you post what you changed in IMsplitter so it works with Desktop Containers and controls? I’m currently converting a project to API2 that has three imSplitters.

Looks like I changed AddControl/NoResize, RemoveControl, and all the AdjustControl methods. I’ve copied the class into an empty project, saved as xojo_project, zipped it, and put it here:

https://www.iletter.org.uk/tempus/IMSplitter.zip

Note the case of the filename. If you go to that URL, it should just download.

2 Likes

Thank you!

I forgot to mention that, during my transition from API1 to API2 controls, I had the code from both the original IMSplitter, and my mods, in all those methods I mentioned. That meant that everything continued to work during the transition. I took out the original API1 code at the end.

The code is only the IMSplitter. Where can I have a look at the problem with the listbox?

Last few days, I’ve been focussing on a number of issues with little success. I’ll have to dig out the test app and see what state I left it in.

I found I could not make a good (small) example for this. But it has caused me to re-examine what I am doing in the PaintCellText event handler. I suspect I could move some code out of there.