Flicker/Refresh Problem

OK, I’d like to see if some more experienced Windows programmers can help me out here…

I have a Listbox where I have a number of embedded pop-up menus in the listbox. Basically when I create the listbox row, there’s up to 2 columns that get a pop-up menu placed in the column. I have the pop-up menu set as the cell tag of those particular cells. I separately create the pop-up menu and then set its parent to be the listbox and set it’s coordinates properly to the coordinates of the cell where I want to place it.

This has worked fine for me for several years in various spots in my app. It makes a nice looking list of items with proper looking pop-up menus for selections. However, in the past all my list boxes have been static - meaning once I draw them, nothing changes or not very often.

Now I am developing a listbox where content in that listbox is potentially dynamic. So I periodically make changes to the listbox contents, etc. This looks terrific in MacOS but whenever I re-draw anything with the listbox in Windows it causes problems. First, when I make refresh or invalidate the listbox, the pop-up menus get blanked out - they get moved underneath the listbox (even though they should be on top). So then I have to redraw the pop-up menus. I get them back after doing this but it results in them flickering every time I do anything to touch the listbox.

Anyone know how to do this properly so that I don’t get this flickering? It’s somewhat frustrating as like I said, in MacOS, the whole thing looks terrific. In Windows it looks like garbage.

Unfortunately, there’s no DoubleBuffer or EraseBackground properties for controls other than Canvases.

Thanks.

Try the following, call Freeze just before you make your first change, then call unfreeze after your last change. It tells the window not to repaint while you do things. You may need to either invalidate or refresh to get the final paint to show your changes but as I’ve not use this in a while I can’t remember. Have a play around with it. Also, turn it with EraseBackground set to false.

Can’t remember where I got the code from or if I wrote it, its standard enough though.

Hope it helps.

[code]Private Function SendMessage(hwnd as Integer, msg as Integer, wParam as Integer, lParam as Integer) as Integer
#if TargetWin32

Soft Declare Function SendMessageA Lib "User32" ( hwnd as Integer, msg as Integer, wParam as Integer, lParam as Integer ) as Integer
Soft Declare Function SendMessageW Lib "User32" ( hwnd as Integer, msg as Integer, wParam as Integer, lParam as Integer ) as Integer

if System.IsFunctionAvailable( "SendMessageW", "User32" ) then
  return SendMessageW( hwnd, msg, wParam, lParam )
else
  return SendMessageA( hwnd, msg, wParam, lParam )
end if

#else

#pragma unused hwnd
#pragma unused msg
#pragma unused wParam
#pragma unused lParam

#endif
End Function
[/code]

[code]Public Sub Freeze(w as window)
Const WM_SETREDRAW = &hB
call SendMessage( w.Handle, WM_SETREDRAW, 0, 0 )

End Sub
[/code]

Public Sub UnFreeze(w as window) Const WM_SETREDRAW = &hB call SendMessage( w.Handle, WM_SETREDRAW, 1, 0 ) End Sub

example will work well.

Here is another workaround to prevent/limit flickering:

Tip removing flicker on windows

Edit: Its just another way to do what Julian recommended.

Thanks guys. I REALLY hate how Windows graphics ends up working in Xojo but it is what it is. Hopefully this will work. I will try it out.

If you got em… throw some points on this feedback <https://xojo.com/issue/47001>

Julian or Eugene (or anyone else for that matter…),

I’m having a hard time understanding how I can make this freezing work. It definitely reduces the update flicker, but I still have to redraw my pop-up menus any time that I update the listbox. So if I update any cell in the listbox, it gets moved to the front, my pop-up menus get hidden and I have to redraw them. That causes the flicker. If I redraw them this is when the flicker happens as the control is hidden and then redrawn. I have one field on the listbox that is updated every second (it’s a “time up” field for a device) and so I get this flicker every second.

If I attempt to redraw the pop-up menus while the window is frozen, they don’t get drawn to the front. They stay hidden. If i wait until after I unfreeze, then I get the flicker.

Refreshing or invalidating the window just causes more jumpiness…

So maybe i’m not doing something right? I don’t know. It seems to be a serious z-order problem with how the controls are layered.

In the report, William Yu mentions, WS_CLIPCHILDREN - What is this and where is it used?

Hmmm maybe the freeze/unfreeze system is the right thing for this situation., it was worth a try.

If you want to see how I fixed the z-order have a look in the project on the original post of <https://xojo.com/issue/47001>. It’ll work unless you’re using transparency in a certain way. However, to get it working you’ll need to order your control in reverse order on the IDE. Have a read of the original post and run the demo project to see whats happening.

If you don’t have any luck with the above, if you can send me a simple demo of what you’re experiencing I can have a play and try to fix it or at least make it smoother/better.

Julian,

Thanks for the reply. I’ll take a look at what you are doing. And I can send you a demo of what I am trying to do. In the mean time, I have decided to not use these pop-up menus in Windows just so I can keep development going. But if your project or any help you give would help me keep them in, that would be great.

Thanks,

Jon

No probs, I’m about to go zzz, I’ll have a look in the morning.

OK. Here’s an example of what I am trying to do.

https://www.dropbox.com/s/icvgbf46k13ktix/ListboxTest.zip?dl=0

The flickering in my actual app is far worse (probably 3 to 5 times worse) as I’ve got so many more updates going on. But note how the list boxes flicker just about every second when columns 2 and 4 get updated.

Here you go Jon, https://www.dropbox.com/s/84s75gzagyngqnv/ListboxTest.zip?dl=1

First off, I changed the timer to 10ms to increase the flicker so it was more evident.

I moved PopupMenu1 outside the Form to make sure it wasnt a child of Listbox1 (red box around the Listbox when moving it inside). This ensures that I can move it around without Xojo taking control of when to render it etc.

I then made a few changes in Window1.Open, I have commented them and implemented a Boolean at the top so you can revert it and see what difference it makes.

Not really part of the fix but:

I also made a change in Timer1.Action. Your mileage may vary, not fully tested, from an initial test it looks like a bug.

You can put these mods inside #If TargetWindows Then #Endif if you want to use the same code on macos and windows. I’ve not tested any of this code on macos so my #If’s might bork.

I hope it works for you.

Wow! Amazing. Thanks so much. I thought that I WANTED to have the control be inside the listbox (i.e.: make it a child). So I had that backwards.

Looks like the Z-order fix made a big difference.

This is all a HUGE difference! Wow. I’m going to try it out now in my project…

As for the Listbox.InvalidateCell, that’s interesting. Using a specific cell coordinate SHOULD invalidate just that item. But as you point out - it looks like it’s invalidating the whole column. I’ll look into that and file a bug report if necessary.

The InvalidateCell thing is definitely a bug. I used the following code in the timer:

For i As Integer = 0 To Listbox1.ListCount-1
  Listbox1.cell(i,3) = Str(Xojo.Core.Date.Now.Hour)+":"+Str(Xojo.Core.Date.Now.Minute)+":"+Str(Xojo.Core.Date.Now.Second)
 
  Listbox1.InvalidateCell(1,1)
Next

It should just change the dot in cell(1,1) from red to green and back. Instead, it’s changing the whole column like you pointed out. In OS X, it behaves correctly changing just the cell. I’ll file the report tonight or tomorrow.

Julian -

Your fixes work absolutely wonderfully in my app! THANK YOU SO MUCH!!!

Could you post the feedback case number on the InvalidateCell issue when its up so people can see it if they end up in here from a search?

No problem, you’re welcome, I’m glad it worked out for you. What you are seeing will be standard functionality if/when Xojo implements a fix for the z-order issue which will be amazing not only for windows developers but for their cross compatibility ethos.

When that fix is in, it will be more than adequate to place the Popup as a child of Listbox, as it is just now, it’s better out so the “fixes” work.

I will once I submit it. I’ll try to do that today.

I’m assuming I should run ZOrderFix on every window - yes? I have another window with a number of canvases and I’ve tried your methods on them and it’s reduced the flicker with those a lot. I can’t use the DoubleBuffer/EraseBackground trick on those as I need them transparent. But your methods have helped.

And it’s amazing how it helps. I have another window I just tried it on which has a 50% transparent image drawn in the background. Previously when I had tabbed between text fields on this window, my labels for those text fields would be redrawn and the image transparency would get lost around the labels.

Should SetWindowPos be called on every dynamically created control? Or just save that for when you are layering controls?

Your mileage may vary when dealing with transparency, give it a try, if it works for you then that is a bonus, if not it needs another method. I’ve not tried implementing that method yet as I’m working on something else at the moment but I have made someone at Xojo aware of where they should be looking for the implementation.

Yes ZOrderFix should be run at the end of Window.Open if you plan on moving controls forwards to reduce flicker for either original controls or dynamically created ones. You only need to do this if you have them sitting in front of another control. You can move the controls one of two ways:

Position them in reverse order in the IDE using the buttons at the top of the screen so that the text box that will sit in front of your canvas is actually behind it in the IDE.

This will then ensure that they draw in the correct order for windows when they are drawn.

The drawback of this method is that its not very cross platform (as things will be the wrong way around in macos), can make it difficult when working on the interface in the IDE and it doesn’t work for dynamically added controls.

Before the initial display, move the controls you want to the top (front) using SetWindowPos and make sure they are not children of the controls you are trying to move them in front of. If you need to place a control at a certain position inside a control but not have it as a child of that control, move it to where you want it, note its coordinates then move it off the form and enter those coordinates into the X Y position in the inspector. This will move it back and not make it the child of the controls its sitting over, unlike when you position it with the mouse.

This is a known bug where labels are being redrawn when tab is used <https://xojo.com/issue/46398> and <https://xojo.com/issue/46975> but its not been fixed in over 7 months :frowning:

When the current z-order issue is resolved by Xojo I’ll be rallying feedback points in the Windows channel to ensure that certain critical things like this are resolved more quickly.

Thanks. Using the ZOrder fix method fixed the label redraw bug.

Seems like some of this is so simple - why doesn’t Xojo implement the fixes! :expressionless:

Here is the bug report Julian on the Listbox.InvalidateCell issue:

<https://xojo.com/issue/48708>