Problem with redraw() / draw()

59 views
Skip to first unread message

geert karman

unread,
Aug 12, 2022, 2:23:46 PM8/12/22
to fltk.general
Hello,

I'm experiencing a problem when trying to redraw a widget. In the attached code I have tried to simplify the issue as much as I could.

When I push the red button, both scroll widgets move to the correct position and are redrawn accordingly. However, when I try to move the left scroll by using the right scroll it doesn't work. In fact, as the printed output indicates, the left scroll is moved, but not redrawn (i.e. Scroll_C::draw() is not called). 

How can I make the scroll method work? The only difference I see between  the two methods seems to be the calling stack when the Scroll::move() functions are called. Maybe it's some C++ issue?

Many thanks for any help.


scrolltest.cxx

geert karman

unread,
Aug 12, 2022, 2:45:12 PM8/12/22
to fltk.general
PS I'm working on MacOS with a clang compiler, fltk 1.4

lifeatt...@gmail.com

unread,
Aug 13, 2022, 10:09:40 PM8/13/22
to fltk.general
Trying your program on Linux / gcc / FLTK 1.4, I get the same behavior you describe.

As far as I can tell, the issue is tied to calling move_to() from inside the Scroll_B::draw() function. I don't understand _why_ it's a problem.  Every change
I tried to force Scroll_C to be redrawn failed.

I attach my modified version of ScrollB which provides the behavior I think you want.  I moved the invocation of move_to() outside the Scroll_B::draw()
method, into a callback function for ScrollB's vertical scrollbar.
modified_scrollb.cxx

Albrecht Schlosser

unread,
Aug 14, 2022, 8:05:56 AM8/14/22
to fltkg...@googlegroups.com
On 8/14/22 04:09 lifeatt...@gmail.com wrote:
> Trying your program on Linux / gcc / FLTK 1.4, I get the same behavior
> you describe.

Thanks, Kevin, for testing. I didn't find the time but your test results
are to the point.

> As far as I can tell, the issue is tied to calling move_to() from
> inside the Scroll_B::draw() function. I don't understand _why_ it's a
> problem.  Every change
> I tried to force Scroll_C to be redrawn failed.

The draw() method is meant to ... draw things, not to change the
widgets. [Side note: unfortunately we *have* widgets that change their
layout in draw(), namely Fl_Pack, which can lead to unexpected behavior.]

Calling redraw() on a widget means to set all damage() bits in the
widget's status. If you do this inside draw() of the widget these
damage() bits will be cleared after draw() which means that you can't
effectively call redraw() inside draw(). You *may* call it on other
widgets but you should not assume any drawing order to avoid undefined
behavior.

I'm not sure if this is exactly the effect in the original test program,
but users should always respect the rule not to change widgets inside
draw() to avoid unexpected / undefined behavior.

> I attach my modified version of ScrollB which provides the behavior I
> think you want.  I moved the invocation of move_to() outside the
> Scroll_B::draw()
> method, into a callback function for ScrollB's vertical scrollbar.

Excellent! Without checking the code in detail or testing it myself (I
only read your code quickly), this is generally how it should be done.
Thanks for investigating and helping!

geert karman

unread,
Aug 15, 2022, 3:56:16 AM8/15/22
to fltk.general

Calling redraw() on a widget means to set all damage() bits in the
widget's status. If you do this inside draw() of the widget these
damage() bits will be cleared after draw() which means that you can't
effectively call redraw() inside draw(). You *may* call it on other
widgets but you should not assume any drawing order to avoid undefined
behavior.

I was actually indeed calling it on another widget. I tricked myself out by adding a timeout that would call redraw().

> I attach my modified version of ScrollB which provides the behavior I
> think you want.  I moved the invocation of move_to() outside the
> Scroll_B::draw()
> method, into a callback function for ScrollB's vertical scrollbar.
 
Excellent! Without checking the code in detail or testing it myself (I
only read your code quickly), this is generally how it should be done.
Thanks for investigating and helping!
 
Great! works fine, many thanks. I was looking for a way to intercept the scrolling of the Fl_Scroll and only thought of the draw() function. It is of course much better to provide my own version of the callback() of the scrollbar.  

On a further note, I was also trying to get my own scrollbars into an Fl_Scroll widget, but that looks like it cannot be done?

Many thanks for all the help.
Geert 

Albrecht Schlosser

unread,
Aug 15, 2022, 1:16:03 PM8/15/22
to fltkg...@googlegroups.com
On 8/15/22 09:56 geert karman wrote:

> I attach my modified version of ScrollB which provides the behavior I
> think you want.  I moved the invocation of move_to() outside the
> Scroll_B::draw()
> method, into a callback function for ScrollB's vertical scrollbar.
 
Excellent! Without checking the code in detail or testing it myself (I
only read your code quickly), this is generally how it should be done.
Thanks for investigating and helping!
 
Great! works fine, many thanks. I was looking for a way to intercept the scrolling of the Fl_Scroll and only thought of the draw() function. It is of course much better to provide my own version of the callback() of the scrollbar.

I'm glad this works for you.


On a further note, I was also trying to get my own scrollbars into an Fl_Scroll widget, but that looks like it cannot be done?

No, this can't be done. Fl_Scroll has two embedded Fl_Scrollbar widgets and uses these exclusively. Unfortunately Fl_Scroll exposes the embedded scrollbars in its public interface which means there's no way to change this, hence you can't replace them with your own scrollbar class.

However, this is something I've been thinking about as well, just recently again, when I was working on some internal aspects of Fl_Scroll. In the future we *might* create another Fl_Scroll_xx class (take 'xx' as a placeholder) which would not embed the scrollbars but use external Fl_Scrollbar widgets which you could then *maybe* replace with your own scrollbars as long as those provide the same interface (which means they would likely need to be a subclass of Fl_Scrollbar).

What did you want to achieve by replacing the scrollbars with your own scrollbars? Was it only for a better look, or should your scrollbars have different features? I'm curious...


Many thanks for all the help.

Welcome.

geert karman

unread,
Aug 15, 2022, 2:16:41 PM8/15/22
to fltk.general

What did you want to achieve by replacing the scrollbars with your own scrollbars? Was it only for a better look, or should your scrollbars have different features? I'm curious...

Both.  Many times I'd like to get rid of the arrow buttons at the ends as they're not always useful and have the slider button be just an oval box with no "grips".  Also, the slider button gets really small when there is a long scroll (it's difficult to grab it with the mouse). 

For a previous program I made a scrollbar that automatically disappears when you don't use it, and I will want to go there with the application I'm working on now. To get it done I had to implement my own Fl_Scroll ...

I can (for now) live with the fixed scrollbars, but I would certainly welcome an alternative version where I can put in my own.

Geert

Albrecht Schlosser

unread,
Aug 15, 2022, 3:36:41 PM8/15/22
to fltkg...@googlegroups.com
On 8/15/22 20:16 geert karman wrote:

What did you want to achieve by replacing the scrollbars with your own scrollbars? Was it only for a better look, or should your scrollbars have different features? I'm curious...

Both.  Many times I'd like to get rid of the arrow buttons at the ends as they're not always useful and have the slider button be just an oval box with no "grips".  Also, the slider button gets really small when there is a long scroll (it's difficult to grab it with the mouse).

Thanks for these insights.


For a previous program I made a scrollbar that automatically disappears when you don't use it, and I will want to go there with the application I'm working on now. To get it done I had to implement my own Fl_Scroll ...

Hmm, just a thought: when you figure that the scrollbars are not (no longer) needed you can switch them off. See test/scroll.cxx, change type() from BOTH to none (0).


I can (for now) live with the fixed scrollbars, but I would certainly welcome an alternative version where I can put in my own.

There's no guarantee that this will ever happen, but as I said before, I personally thought about it - for some other reasons though. If it ever happens I might remember your request. ;-)

Greg Ercolano

unread,
Aug 15, 2022, 3:44:49 PM8/15/22
to fltkg...@googlegroups.com

On 8/15/22 11:16, geert karman wrote:

Also, the slider button gets really small when there is a long scroll (it's difficult to grab it with the mouse).


    Hmm, this one interests me.

    The slider tab should not get any smaller than the width of the scrollbar itself.
    (In other words the tab should not get smaller than a "square").

    We could probably provide a minimum size for the scrollbar tab,
    e.g. as some fractional part of the scrollbar's size, e.g. 1.0 would
    be the current behavior.

    But if the scrollbar's tab is getting too small in your app as a square,
    perhaps the scrollbar_size() needs to be larger, so that the tab is easier to grab.
    This can be set universally throughout the app by setting Fl::scrollbar_size()
    just before calling Fl::run() IIRC.

Greg Ercolano

unread,
Aug 15, 2022, 3:58:31 PM8/15/22
to fltkg...@googlegroups.com


On 8/15/22 12:44, Greg Ercolano wrote:

On 8/15/22 11:16, geert karman wrote:

Also, the slider button gets really small when there is a long scroll (it's difficult to grab it with the mouse).

    [..]

    But if the scrollbar's tab is getting too small in your app as a square,
    perhaps the scrollbar_size() needs to be larger, so that the tab is easier to grab.
    This can be set universally throughout the app by setting Fl::scrollbar_size()
    just before calling Fl::run() IIRC.


    You might want to experiement with changing the global scrollbar size
    using the "unittests" program in the fltk test directory, and play with  the
    "Scrollbar size" test, sliding the "Global Scroll Size" around.



geert karman

unread,
Aug 15, 2022, 3:58:53 PM8/15/22
to fltk.general


Op maandag 15 augustus 2022 om 20:44:49 UTC+1 schreef er...@seriss.com:

On 8/15/22 11:16, geert karman wrote:

Also, the slider button gets really small when there is a long scroll (it's difficult to grab it with the mouse).


    Hmm, this one interests me.

    The slider tab should not get any smaller than the width of the scrollbar itself.
    (In other words the tab should not get smaller than a "square").

It seems it does ....Screenshot 2022-08-15 at 20.48.26.png 

    But if the scrollbar's tab is getting too small in your app as a square,
    perhaps the scrollbar_size() needs to be larger, so that the tab is easier to grab.
    This can be set universally throughout the app by setting Fl::scrollbar_size()
    just before calling Fl::run() IIRC.

 Fl::scrollbar_size() sets the width. I do not have /want to spend much space on the scrollbar, I set it at 10. To get a reasonable slider I'd like to have it at 20 minimum. Having my own scrollbar in there I would also not draw a box around it so the slider would be really 10 wide, not 8 or so as it is now. 

As for switching them off by setting the type to 0, I didn't want things popping in and out of existence in the window, so I did a little animation that made them slide away. But it would be option.

Geert

Greg Ercolano

unread,
Aug 15, 2022, 8:49:22 PM8/15/22
to fltkg...@googlegroups.com


On 8/15/22 12:58, geert karman wrote:
It seems it does ... [screenshot]

    Ah, that looks like it's a "feature" of one of the non-default schemes
    that FLTK provides, perhaps gtk+?

    I can see where such a problem could be solved by a new method that
    I mentioned, letting one control the minimum size of the tab.

    I suppose such a method could maybe default to 0.0 ('default' behavior),
    and allow non-zero numbers be a fractional size based on the width, so
    that if the scrollbar_size were 10, and the minimum size were 1.0, the tab
    would never get smaller than 10 pixels, regardless of the scheme().

    Or well, just a thought.

geert karman

unread,
Aug 16, 2022, 3:17:50 AM8/16/22
to fltk.general


    Ah, that looks like it's a "feature" of one of the non-default schemes
    that FLTK provides, perhaps gtk+?

Yes, I use gtk+. By the way I just tried the default scheme and the slider there is not square either. 
 
    I can see where such a problem could be solved by a new method that
    I mentioned, letting one control the minimum size of the tab.

    I suppose such a method could maybe default to 0.0 ('default' behavior),
    and allow non-zero numbers be a fractional size based on the width, so
    that if the scrollbar_size were 10, and the minimum size were 1.0, the tab
    would never get smaller than 10 pixels, regardless of the scheme().
 
At this moment it looks like the minimum is half the width of the scrollbar for both the default and gtk+ schemes. It would already be great if it would not get smaller than squared as you mentioned in your earlier post. Would the team feel for such an update in fltk 1.4? I haven't looked at the code yet, but it sounds like it should be easy to implement (like not divide by 2 or so, but maybe there's more to it, for example for very short scrollbars?)
Reply all
Reply to author
Forward
0 new messages