Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

How to eliminate flickering when swapping frames

85 views
Skip to first unread message

namn...@google.com

unread,
Mar 28, 2018, 7:49:17 PM3/28/18
to
Hi,

The below code demonstrates an annoying flickering on Debian Linux, especially when the mouse is hovering on the buttons.

Is there any trick to eliminate the flickering?

Thanks,
Nam


#!/usr/bin/env tclsh

package require Tk
bind . {<Escape>} {destroy .}
wm minsize . 1280 800

frame .f_1
button .f_1.b -text {Frame 1} -command {destroy .}
pack .f_1.b -expand true -fill both
frame .f_2
button .f_2.b -text {2 emarF} -command {destroy .}
pack .f_2.b -expand true -fill both

set current 1
set delay 500

proc flip {} {
global current
global delay
pack forget ".f_$current"
if {$current == 1} then {
set current 2
} else {
set current 1
}
pack ".f_$current" -expand true -fill both
after $delay {flip}
}

pack ".f_$current" -expand true -fill both
after $delay {flip}

Rich

unread,
Mar 28, 2018, 8:43:56 PM3/28/18
to
namn...@google.com wrote:
> Hi,
>
> The below code demonstrates an annoying flickering on Debian Linux,
> especially when the mouse is hovering on the buttons.
>
> Is there any trick to eliminate the flickering?

Yes, but since you've failed to tell us why you want to pack/unpack a
pair of buttons, the solution might not actually be what you are
looking for.

The solution is: don't pack/unpack buttons like this.

Instead just change the text on the button (and if the command should
change, change it as well):

Alternate, no flickering, flip proc:

proc flip {} {
global current
global delay
if {$current == 1} then {
.f_1.b configure -text "2 emarF"
set current 2
} else {
.f_1.b configure -text "Frame 1"
set current 1
}
after $delay {flip}
}

namn...@google.com

unread,
Mar 28, 2018, 9:35:20 PM3/28/18
to
On Wednesday, March 28, 2018 at 5:43:56 PM UTC-7, Rich wrote:
> namn...@google.com wrote:
> > Hi,
> >
> > The below code demonstrates an annoying flickering on Debian Linux,
> > especially when the mouse is hovering on the buttons.
> >
> > Is there any trick to eliminate the flickering?
>
> Yes, but since you've failed to tell us why you want to pack/unpack a
> pair of buttons, the solution might not actually be what you are
> looking for.
>
> The solution is: don't pack/unpack buttons like this.

Ah, right, totally my bad. Sorry for the lack of context. Basically I have several mega-widgets, each is a frame. I have them swapped in and out several times, depending on some external events. Since these mega widgets have nothing in common, it's not a simple "just change the text" on the buttons ;).
Nam

Rich

unread,
Mar 28, 2018, 11:11:04 PM3/28/18
to
Ok, now that there's more context, consider using the ttk::notebook as
a "page swapper". See the first suggestion under Tips and Tricks here:
http://wiki.tcl.tk/20057

namn...@google.com

unread,
Mar 29, 2018, 10:35:41 AM3/29/18
to
If the code below is sensible, I'm afraid to say that using notebook does not alleviate the flickering.


#!/usr/bin/env tclsh

package require Tk
bind . {<Escape>} {destroy .}
wm minsize . 1280 800

ttk::style layout Plain.TNotebook.Tab null
ttk::notebook .book -style Plain.TNotebook

frame .book.f_1
button .book.f_1.b -text {Frame 1} -command {destroy .}
pack .book.f_1.b -expand true -fill both

frame .book.f_2
button .book.f_2.b -text {2 emarF} -command {destroy .}
pack .book.f_2.b -expand true -fill both

.book add .book.f_1
.book add .book.f_2

set current 0
set delay 500

proc flip {} {
global current
global delay
if {$current == 0} then {
set current 1
} else {
set current 0
}
.book select $current
after $delay {flip}
}

.book select $current
pack .book -expand true -fill both
after $delay {flip}

Rich

unread,
Mar 29, 2018, 1:17:33 PM3/29/18
to
namn...@google.com wrote:
> On Wednesday, March 28, 2018 at 8:11:04 PM UTC-7, Rich wrote:
>> namn...@google.com wrote:
>> > On Wednesday, March 28, 2018 at 5:43:56 PM UTC-7, Rich wrote:
>> >> namn...@google.com wrote:
>> >> > Hi,
>> >> >
>> >> > The below code demonstrates an annoying flickering on Debian
>> >> > Linux, especially when the mouse is hovering on the buttons.
>> >> >
>> >> > Is there any trick to eliminate the flickering?
>> >>
>> >> Yes, but since you've failed to tell us why you want to pack/unpack
>> >> a pair of buttons, the solution might not actually be what you are
>> >> looking for.
>> >>
>> >> The solution is: don't pack/unpack buttons like this.
>> >
>> > Ah, right, totally my bad. Sorry for the lack of context.
>> > Basically I have several mega-widgets, each is a frame. I have
>> > them swapped in and out several times, depending on some external
>> > events. Since these mega widgets have nothing in common, it's not
>> > a simple "just change the text" on the buttons ;).
>>
>> Ok, now that there's more context, consider using the ttk::notebook
>> as a "page swapper". See the first suggestion under Tips and Tricks
>> here: http://wiki.tcl.tk/20057
>
> If the code below is sensible

Sensible that it demonstrates the issue, yes.

> , I'm afraid to say that using notebook does not alleviate the
> flickering.

You may be trying to get Tk to do something here that it was never
designed to do. High speed animation (esp. of nearly a whole window)
was never likely high in its design requirements (given that most
GUI's, once laid out, don't tend to jump/move/switch all around all
that often).

Other angles to try (although I suspect the same end result may occur
for all but the last, because invisible windows are 'unmapped' and
making them visible means 'mapping' them, which means redrawing their
contents):

1) Use the placer (or grid with two or more widgets in the same grid
cell) and then use raise/lower to make a specific frame visible.

2) Use the canvas, without scroll bars attached, then move the view
port around via script calls on the canvas to make a specific frame
visible.

3) Rethink your implimentation to work out a way to not need to do this
'swapping' (i.e., open new toplevel child windows instead). But this
may be your least preferred suggestion.

namn...@google.com

unread,
Mar 29, 2018, 8:41:26 PM3/29/18
to
I was hoping that you'd point out the inefficiencies in my code instead of confirming what I've suspected to be out of scope for Tk. The small delay here is only meant to quickly illustrate the issue. In my actual application, this swapping occurs at much lesser rate, but the flickering is still noticeable to keen eyes. Oh well.

Thanks!
Nam

>
> Other angles to try (although I suspect the same end result may occur
> for all but the last, because invisible windows are 'unmapped' and
> making them visible means 'mapping' them, which means redrawing their
> contents):
>
> 1) Use the placer (or grid with two or more widgets in the same grid
> cell) and then use raise/lower to make a specific frame visible.

Tried and failed.

>
> 2) Use the canvas, without scroll bars attached, then move the view
> port around via script calls on the canvas to make a specific frame
> visible.

This is gonna be a huge rework with manual paint and custom widget behaviors. And then, it's not even guaranteed to work.

>
> 3) Rethink your implimentation to work out a way to not need to do this
> 'swapping' (i.e., open new toplevel child windows instead). But this
> may be your least preferred suggestion.

I guess this is the best outcome. I'll think more about a new UX.

Rich

unread,
Mar 29, 2018, 10:33:47 PM3/29/18
to
The only real 'inefficiency' in your code is flipping on a half second
flip. But I very much doubt the speed of the exchange is the issue.
The speed with which the screen can be repainted, and whether the
repaint is synchronized with the display scan rate, is what is very
likely causing the flicker. I.e., the flicker is part of the old
display visible for one refresh period because the old bitmap was still
present in the frame buffer when that part of the screen was redrawn.

The classical way that games (and other apps that need such) avoid such
an issue is double buffering. The display is refreshed from one bitmap
while a second bitmap is drawn into. Then in sync with the screen
refresh the entire bitmaps are exchanged (actually the address the
video card begins reading the screen data from is swapped, but same
effect). So the old image is visible, then the new image appears, in
one single refresh interval.

Tk does not expose any ability out to Tcl to do synched updating,
although maybe a C extension could be written to do so. Nor does it
expose out any direct ability to do double buffering, so there is
likely no way to fully eliminate the flicker without writing some low
level C extensions.

> The small delay here is only meant to quickly illustrate the issue.
> In my actual application, this swapping occurs at much lesser rate,
> but the flickering is still noticeable to keen eyes. Oh well.

Very likely because it is just an inherent property of how modern video
screens are repainted.

>> Other angles to try (although I suspect the same end result may occur
>> for all but the last, because invisible windows are 'unmapped' and
>> making them visible means 'mapping' them, which means redrawing their
>> contents):
>>
>> 1) Use the placer (or grid with two or more widgets in the same grid
>> cell) and then use raise/lower to make a specific frame visible.
>
> Tried and failed.
>
>>
>> 2) Use the canvas, without scroll bars attached, then move the view
>> port around via script calls on the canvas to make a specific frame
>> visible.
>
> This is gonna be a huge rework with manual paint and custom widget
> behaviors. And then, it's not even guaranteed to work.

Testing with your big button example would be less work than reworking
your code first. Yes, still likely to exhibit the flicker, but much
less effort than refactoring your code without knowing if it will help
or not.

>> 3) Rethink your implimentation to work out a way to not need to do
>> this 'swapping' (i.e., open new toplevel child windows instead).
>> But this may be your least preferred suggestion.
>
> I guess this is the best outcome. I'll think more about a new UX.

Or, of course, the forth option: just live with the tiny bit of
flicker.

Donald Arseneau

unread,
Mar 30, 2018, 12:57:10 AM3/30/18
to
Well *I* couldn't see any flickering unless I tweaked something.

If one button has focus, then the perimeter will change with
the flips, due to the -border.

If I set -activebackground white for the buttons, there is
significant flicker with the flips when the mouse is over the
buttons. (Each gets activated after appearing.) Can you
compare the -activebackground and the -background colors?

If I set the frame color white, there is intermittent flicker,
especially if I press TAB to bring focus to a button (seems to make
the redraw slower).

I can get rid of the flicker caused by frames with different color
by using [grid] and [raise], instead of packing and unpacking:

grid rowconfigure . 0 -weight 1
grid columnconfigure . 0 -weight 1
grid .f_1 -row 0 -column 0 -sticky nsew
grid .f_2 -row 0 -column 0 -sticky nsew
proc flip {} {
global current
global delay
if {$current == 1} then {
set current 2
} else {
set current 1
}
raise .f_$current
after $delay {flip}
}

Does anybody know how to overlap widgets using [pack]? I only
know how with [grid] (or [place], of course).


--
Donald Arseneau as...@triumf.ca
0 new messages