strange behaviour with Fl_Scroll

20 views
Skip to first unread message

Franck Barbenoire

unread,
Jun 20, 2025, 7:27:27 AMJun 20
to fltk.general
Hello all,

I noticed a strange behaviour involving a scroll area containing a list of check boxes in a pack. I've searched for hours, this why I ask for your help here. This happens with version 1.4.2 on a Linux system.

When I don't scroll, all visible check boxes can be checked.
When I scroll down to the bottom of the list and back to the head:
  • the second item to the last that were hidden can't be checked;
  • checking the first enables the second to be checked;
  • checking the second enables the third to be checked and so on;
  • checking any item that were stll visible enables any item that was hidden and now visible to be checked.
I made the program as short as possible to reproduce the issue.

Thanks for you attention.
main.cpp
Makefile

Greg Ercolano

unread,
Jun 20, 2025, 11:03:34 AMJun 20
to fltkg...@googlegroups.com

Interesting - I have a meeting to run to, but I tweaked your code a bit (attached here) so that clicking the first button invokes a callback that shows the xywh of the inner packs and the check buttons, as the behavior seems like some of the children are being moved outside the group, making them unclickable. This may help folks trying to figure out what the problem is - I'd do it but have time constraints today.

I think it's a bug in fltk's handling of Fl_Pack inside Fl_Pack - haven't looked, but the xywh values of the "unclickable" checkboxes (after a scroll down then back up) seems suspicious, and the scroll/pack mechanisms are supposed to be handling adjusting those properly. Might be a problem with a pack-in-a-pack, and how the inner pack deals with being moved around by the outer pack being moved around by the scroll (woo!).

I'm thinking this should probably be reported as a bug.

foo2.cxx

Greg Ercolano

unread,
Jun 20, 2025, 1:09:48 PMJun 20
to fltkg...@googlegroups.com

On 6/20/25 08:03, Greg Ercolano wrote:

[..] the xywh values of the "unclickable" checkboxes (after a scroll down then back up) seems suspicious [..]


    Specifically, highlighted in red, the 'y' positions of the "unclickable" check buttons seem to deviate (shown in red) from the norm (shown in green), almost like they suddenly start growing negative instead of positive. I'm guessing it's the resize() behavior of the Fl_Pack widget doing something wrong, perhaps to do with how the parent scrolling tells the children what to do, and in all that, some weird behavior is sneaking in.

So if I scroll down then back, then try to click #3~6 they won't click, so clicking #1 dumps the xywh values and shows the problem..
Specifically:

0000:
    point_pack(xywh)=30,80,150,30
     check_but(xywh)=30,80,150,30
0001:
    point_pack(xywh)=30,110,150,30
     check_but(xywh)=30,110,150,30
0002:
    point_pack(xywh)=30,140,450,30
     check_but(xywh)=30,106,150,30 <-- 106? should be 140
0003:
    point_pack(xywh)=30,170,450,30
     check_but(xywh)=30,102,150,30 <-- 102? should be 170
0004:
    point_pack(xywh)=30,200,450,30
     check_but(xywh)=30,101,150,30 <-- 101? should be 200
0005:
    point_pack(xywh)=30,230,450,30
     check_but(xywh)=30,100,150,30 <-- 100? should be 230
0006:
    point_pack(xywh)=30,260,450,30
     check_but(xywh)=30,96,150,30  <-- 96? should be 260
[..]



Greg Ercolano

unread,
Jun 20, 2025, 1:24:58 PMJun 20
to fltkg...@googlegroups.com

On 6/20/25 08:03, Greg Ercolano wrote:

[..] the xywh values of the "unclickable" checkboxes (after a scroll down then back up) seems suspicious [..]


    Hmm, this /might/ be "documented misbehavior"; according to the Fl_Pack docs, nesting Fl_Pack might behave weirdly.
    Quoting the special note in the docs:
Note
You can nest Fl_Pack widgets or put them inside Fl_Scroll widgets or inside other group widgets but their behavior can sometimes be "surprising". This is partly due to the fact that Fl_Pack widgets resize themselves during their draw() operation, trying to react on their child widgets resizing themselves during their draw() operations which can be confusing. If you want to achieve special resize behavior of nested group widgets it can sometimes be easier to derive your own specialized group widget than to try to make nested Fl_Pack widgets behave as expected.
    It's possible replacing Fl_Pack with one of Albrecht's newer widgets (Fl_Flex, Fl_Grid) might be better than Fl_Pack. (I know Fl_Pack often gives people trouble)

Albrecht Schlosser

unread,
Jun 22, 2025, 5:57:34 AMJun 22
to fltkg...@googlegroups.com
Sorry for being late ...


On 6/20/25 19:24 Greg Ercolano wrote:

On 6/20/25 08:03, Greg Ercolano wrote:

[..] the xywh values of the "unclickable" checkboxes (after a scroll down then back up) seems suspicious [..]


    Hmm, this /might/ be "documented misbehavior"; according to the Fl_Pack docs, nesting Fl_Pack might behave weirdly.
    Quoting the special note in the docs:
Note
You can nest Fl_Pack widgets or put them inside Fl_Scroll widgets or inside other group widgets but their behavior can sometimes be "surprising". This is partly due to the fact that Fl_Pack widgets resize themselves during their draw() operation, trying to react on their child widgets resizing themselves during their draw() operations which can be confusing. If you want to achieve special resize behavior of nested group widgets it can sometimes be easier to derive your own specialized group widget than to try to make nested Fl_Pack widgets behave as expected.

Honestly, I don't know exactly what's happening when using Fl_Pack in this constellation. I believe the misbehavior is caused by "resizing itself in its draw() method". Combining Fl_Scroll with nested Fl_Pack's causes weird things.

Looking at the docs "
You can nest Fl_Pack widgets or put them inside Fl_Scroll widgets ..." I'd interpret these or's as exclusive or's.  ;-)

In my test I saw too large (nested) group sizes overlapping each other, like this:
```
[ 0] Window    (0x56510b0b9330) [  0,  0,289,427] -tt-                Window 
  [ 0] Widget    (0x56510b0a54f0) [  8,  6, 15, 62] -tt-                Debug 
  [ 1] Group     (0x56510b0bd610) [ 16, 47,231,388] -tt-                Scroll 
    [ 0] Group     (0x56510b0bd890) [ 26, 47,600,450] -tt-                NULL 
      [ 0] Group     (0x56510b0bd980) [ 26, 47, 30,160] -tt-                NULL 
        [ 0] Widget    (0x56510b0a1eb0) [ 26, 47, 30, 80] -tt-                Point 1 
        [ 1] Widget    (0x56510b0a5190) [106, 47, 30, 80] -tt-                abc 
      [ 1] Group     (0x56510b0bda40) [ 26, 77, 30,160] -tt-                NULL 
        [ 0] Widget    (0x56510b0a1a80) [ 26, 77, 30, 80] -tt-                Point 2 
        [ 1] Widget    (0x56510b0a3280) [106, 77, 30, 80] -tt-                abc 
      [ 2] Group     (0x56510b0bdb40) [ 26,107, 30,450] -tt-                NULL 
        [ 0] Widget    (0x56510b0a18e0) [ 26, 48, 30, 80] -tt-                Point 3 
        [ 1] Widget    (0x56510b0a3200) [106, 48, 30, 80] -tt-                abc 
      ...
```
The above log is from my own widget (nesting) test tool (not yet ready for publishing). The overlapping groups are problematic and can cause event delivery to not make it to "the right" group, i.e. the one intended by the programmer.

    It's possible replacing Fl_Pack with one of Albrecht's newer widgets (Fl_Flex, Fl_Grid) might be better than Fl_Pack. (I know Fl_Pack often gives people trouble)

Indeed, and to be correct: Fl_Flex was contributed by another user (and modified for FLTK mostly by me). Only Fl_Grid has been developed by me from scratch.

In our test case Fl_Flex can be used as drop-in replacement for Fl_Pack and ... it just works!

In a first attempt I used Greg's latest demo program (foo2.cxx) and globally replaced Fl_Pack with Fl_Flex, and that was it. I made a few adjustments of sizes and added the callback that outputs widget sizes to *all* check buttons rather than only the first (so we can also click on "Point 20" if scrolled all the way down).

Example output:
```
0000:
    point_pack(xywh)=30,-52,450,28
     check_but(xywh)=30,-52,450,28
0001:
    point_pack(xywh)=30,-24,450,28
     check_but(xywh)=30,-24,450,28
0002:
    point_pack(xywh)=30,4,450,28
     check_but(xywh)=30,4,450,28
0003:
    point_pack(xywh)=30,32,450,28
     check_but(xywh)=30,32,450,28
0004:
    point_pack(xywh)=30,60,450,28
     check_but(xywh)=30,60,450,28
...
```

Don't worry about negativ y() values: these are correct because the widgets are outside the Fl_Scroll widget's area *and* above the upper window border. All `point_pack` groups are correctly sized and don't overlap. Everything looks fine and all check buttons are always clickable (as far as I could test).

Conclusion: I really recommend not to nest Fl_Pack's and not to use them in combination with Fl_Scroll, although this *may* work in some cases (see test/pack.cxx). For new programs I suggest not to use Fl_Pack at all: use Fl_Flex instead, or maybe even Fl_Grid for complex layouts. Fl_Flex and Fl_Grid can be nested, and as far as I know there are no known issues when nesting them and putting them in Fl_Scroll widgets.

Albrecht Schlosser

unread,
Jun 22, 2025, 6:01:28 AMJun 22
to fltkg...@googlegroups.com
On 6/22/25 11:57 'Albrecht Schlosser' via fltk.general wrote:
In a first attempt I used Greg's latest demo program (foo2.cxx) and globally replaced Fl_Pack with Fl_Flex, and that was it. I made a few adjustments of sizes and added the callback that outputs widget sizes to *all* check buttons rather than only the first (so we can also click on "Point 20" if scrolled all the way down).

At this point I forgot to post my modified demo (foo3.cxx). Here it is:

#include <stdio.h>
#include <FL/Fl.H>
#include <FL/Fl_Check_Button.H>
#include <FL/Fl_Flex.H>
#include <FL/Fl_Scroll.H>
#include <FL/Fl_Widget.H>
#include <FL/Fl_Window.H>
// Show the xywh positions of all children of the outer_pack (the point packs and checkboxes)
void show_xywh_cb(Fl_Widget *, void *data)
{
Fl_Flex *outer_pack = (Fl_Flex *)data;
for (int i = 0; i < 20; i++)
{
Fl_Flex *point_pack = (Fl_Flex *)outer_pack->child(i);
Fl_Check_Button *vertex_btn = (Fl_Check_Button *)point_pack->child(0);
printf("%04d:\n", i);
printf(" point_pack(xywh)=%d,%d,%d,%d\n", point_pack->x(), point_pack->y(), point_pack->w(), point_pack->h());
printf(" check_but(xywh)=%d,%d,%d,%d\n", vertex_btn->x(), vertex_btn->y(), vertex_btn->w(), vertex_btn->h());
}
}
int main(int argc, char **argv)
{
Fl_Window *window = new Fl_Window(100, 100, 550, 500, "Define zone");
// Scroll
Fl_Scroll *scroll = new Fl_Scroll(20, 80, 500, 400, "Points");
scroll->type(Fl_Scroll::VERTICAL);
// Vertical pack
Fl_Flex *outer_pack = new Fl_Flex(30, 80, 450, 550);
outer_pack->begin();
char name[20];
// 20 checkboxes, each in its own horiz pack (for some reason)
for (int i = 0; i < 20; i++)
{
Fl_Flex *point_pack = new Fl_Flex(30, 0, 380, 50);
point_pack->type(Fl_Flex::HORIZONTAL);
point_pack->begin();
Fl_Check_Button *vertex_btn = new Fl_Check_Button(0, 0, 150, 0);
sprintf(name, "Point %d", i + 1); // unique label for each checkbox
vertex_btn->copy_label(name);
vertex_btn->box(FL_FLAT_BOX);
vertex_btn->color(72 + (i * 2)); // different color for each check button
/* if ( i == 0 ) */
vertex_btn->callback(show_xywh_cb, (void *)outer_pack);
point_pack->end();
// point_pack->add(vertex_btn);
// outer_pack->add(point_pack);
}
outer_pack->end();
scroll->end();
window->end();
window->resizable(window);
window->show(argc, argv);
return Fl::run();
}

    

Reply all
Reply to author
Forward
0 new messages