Problems using Fl_Widget->user_data()

44 views
Skip to first unread message

Will B

unread,
Sep 7, 2016, 8:14:56 PM9/7/16
to fltk.general

Greetings!

I'm attempting to use Fl_Widget->user_data() and it isn't working the way I expect.

I'm trying to process multiple buttons with one callback, so I I want to use user_data() to store the button's name / identifier, however when I do store a char* in user_data(), it comes out as garbage or is the wrong string.

When I run my test code (see below), when I click both buttons, they both output the same string (see the attached image), instead of the assigned string.

What am I missing here, or is user_data() not functioning correctly?

Here is my example code:
#include <FL/Fl.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Double_Window.H>
#include <FL/Fl_Button.H>

#include <stdio.h>
#include <iostream>


/* special struct */
typedef struct {
   
char s1[50];
   
char s2[50];
} sStruct;


char strTest1[] = "UserData string 1";
char strTest2[] = "UserData string 2";


/* callback for button clicks */
void buttonCallback (Fl_Widget* widget, void* data)
{
   
Fl_Button* btn = static_cast<Fl_Button*>(widget);
    sStruct
* s = static_cast<sStruct*>(data);

   
char* strUserData = static_cast<char*>(btn->user_data());

   
if (btn != NULL && s != NULL) {
        std
::cout << "UserData: " << strUserData << std::endl;
   
}
}


/* main program */
int main (int argc, char **argv)
{
    sStruct
* s = new sStruct;

    strcpy
(s->s1, "Struct string 1");
    strcpy
(s->s2, "Struct string 2");

   
Fl_Window* win = new Fl_Window(100, 100, 150, 100);
    win
->label("FLTK user_data test");

   
Fl_Button* btn1 = new Fl_Button(25, 25, 100, 28, "Button1");
    btn1
->user_data(strTest1);
    btn1
->callback(buttonCallback, s);

   
Fl_Button* btn2 = new Fl_Button(25, 53, 100, 28, "Button2");
    btn2
->user_data(strTest2);
    btn2
->callback(buttonCallback, s);

    win
->end();
    win
->show();

   
return Fl::run();
}


If the above didn't display correctly:

#include <FL/Fl.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Double_Window.H>
#include <FL/Fl_Button.H>

#include <stdio.h>
#include <iostream>


/* special struct */
typedef struct {
    char s1[50];
    char s2[50];
} sStruct;


char strTest1[] = "UserData string 1";
char strTest2[] = "UserData string 2";


/* callback for button clicks */
void buttonCallback (Fl_Widget* widget, void* data)
{
    Fl_Button* btn = static_cast<Fl_Button*>(widget);
    sStruct* s = static_cast<sStruct*>(data);

    char* strUserData = static_cast<char*>(btn->user_data());

    if (btn != NULL && s != NULL) {
        std::cout << "UserData: " << strUserData << std::endl;
    }
}


/* main program */
int main (int argc, char **argv)
{
    sStruct* s = new sStruct;

    strcpy(s->s1, "Struct string 1");
    strcpy(s->s2, "Struct string 2");

    Fl_Window* win = new Fl_Window(100, 100, 150, 100);
    win->label("FLTK user_data test");

    Fl_Button* btn1 = new Fl_Button(25, 25, 100, 28, "Button1");
    btn1->user_data(strTest1);
    btn1->callback(buttonCallback, s);

    Fl_Button* btn2 = new Fl_Button(25, 53, 100, 28, "Button2");
    btn2->user_data(strTest2);
    btn2->callback(buttonCallback, s);

    win->end();
    win->show();

    return Fl::run();
}


Thank you!

Will Brokenbourgh

fltk-user-data-example01.png

Greg Ercolano

unread,
Sep 7, 2016, 8:45:57 PM9/7/16
to fltkg...@googlegroups.com
Bug is here (see "<--")

On 09/07/16 17:14, Will B wrote:
> Fl_Button* btn1 = new Fl_Button(25, 25, 100, 28, "Button1");
> btn1->user_data(strTest1);
> btn1->callback(buttonCallback, s); <-- 's' is overwriting the user_data()



You probably want the above 3 lines to just be these two:

Fl_Button* btn1 = new Fl_Button(25, 25, 100, 28, "Button1");
btn1->callback(buttonCallback, strTest1);

Will B

unread,
Sep 7, 2016, 9:02:35 PM9/7/16
to fltk.general, erco_...@seriss.com

Thank you Greg,

So you're saying that passing an extra parameter to the callback overwrites a widget's user_data()?

Thanks,

Will Brokenbourgh

Will B

unread,
Sep 7, 2016, 10:38:10 PM9/7/16
to fltk.general, erco_...@seriss.com

After checking out the FLTK source, I see what you mean.  Thanks for your help! :-)

Will Brokenbourgh

Greg Ercolano

unread,
Sep 7, 2016, 10:39:19 PM9/7/16
to fltkg...@googlegroups.com
> > Fl_Button* btn1 = new Fl_Button(25, 25, 100, 28, "Button1");
> > btn1->user_data(strTest1);
> > btn1->callback(buttonCallback, s); <-- 's' is overwriting the user_data()
>
> You probably want the above 3 lines to just be these two:
>
> Fl_Button* btn1 = new Fl_Button(25, 25, 100, 28, "Button1");
> btn1->callback(buttonCallback, strTest1);
>
> Thank you Greg,
> So you're saying that passing an extra parameter to the callback overwrites
> a widget's user_data()?

Yes, they're one and the same.

Note the second argument to callback() is optional; if unspecified
only the callback is changed, so you could do the following if you
prefer to use user_data() for some reason:

Fl_Button* btn1 = new Fl_Button(25, 25, 100, 28, "Button1");
btn1->user_data(strTest1);
btn1->callback(buttonCallback);

..but I think using callback()'s 2nd argument is the clearer/shorter
way to go.

Edzard Egberts

unread,
Sep 8, 2016, 2:16:18 AM9/8/16
to 'ed' via fltk.general
> I'm trying to process multiple buttons with one callback, so I I want to
> use user_data() to store the button's name / identifier

This is one way to handle this, but there is another possibility:

> Here is my example code:
> |
> #include<FL/Fl.H>
> #include<FL/Fl_Window.H>
> #include<FL/Fl_Double_Window.H>
> #include<FL/Fl_Button.H>
>
> #include<stdio.h>
> #include<iostream>

< snipped >

Fl_Button*btn1; // Make button definitions visible for callback
Fl_Button*btn2;

> /* callback for button clicks */
> voidbuttonCallback (Fl_Widget*widget,void*data)
> {
> Fl_Button*btn =static_cast<Fl_Button*>(widget);
if (btn==btn1) cout << "Button 1" << endl;
else if (btn==btn2) cout << "Button 2" << endl;
// Identify Button by comparison with defined buttons
> }

> /* main program */
> intmain (intargc,char**argv)
> {
> sStruct*s =newsStruct;
>
> strcpy(s->s1,"Struct string 1");
> strcpy(s->s2,"Struct string 2");
>
> Fl_Window*win =newFl_Window(100,100,150,100);
> win->label("FLTK user_data test");
>
> Fl_Button*btn1 =newFl_Button(25,25,100,28,"Button1");

btn1 =newFl_Button(25,25,100,28,"Button1");
// Be aware not to lokal redefine name of button


Will B

unread,
Sep 8, 2016, 11:54:43 AM9/8/16
to fltk.general
 Thank you for that, however I want to avoid using too many global variables.

Will Brokenbourgh

Edzard Egberts

unread,
Sep 9, 2016, 2:05:34 AM9/9/16
to 'ed' via fltk.general
> > This is one way to handle this, but there is another possibility:
< snip >
>
> Thank you for that, however I want to avoid using too many global
> variables.

Of course I would use a class - this was an example, wasn't it?

Normally I use FLUID to design a GUI and I'm used to name the elements.

Reply all
Reply to author
Forward
0 new messages