[ Return to Articles | Show Comments | Submit Comment ]
Article #379: How Can I Use a Class Method as a Callback?
Created at 07:59 Jan 29, 2005 by mike
Because of the way C++ and FLTK work, you can only use static methods for
callbacks, at least directly.
To get the this pointer for the class you can pass the
pointer as the user_data argument for your callback. Typically
this is then used to call a non-static method:
class MyClass {
static static_callback(Fl_Widget* w, void* data) {
((MyClass*)data)->real_callback(w);
}
void real_callback(Fl_Widget* w) {
... this is the real callback ...
}
public:
MyClass() {
...
// building the gui now:
button = new Fl_Button(...);
button->callback(static_callback, this);
}
};
If you need the user_data pointer for something else, you can
also set the user_data pointer in the top-most group/window in
your class, and then use the Fl_Widget pointer that is passed to
your callback to find the class pointer (this is the method used by FLUID):
class MyClass {
static static_callback(Fl_Widget *w, void *data) {
Fl_Widget *p = w->parent();
while (p->parent()) p = p->parent();
((MyClass*)p->user_data())->real_callback(w, data);
}
void real_callback(Fl_Widget *w, void *data) {
... this is the real callback ...
}
public:
MyClass() {
...
// building the gui now:
window = new Fl_Window(...);
window->user_data(this);
button = new Fl_Button(...);
button->callback(static_callback, ...);
}
};
[ Download | Home Page | Listing ]
[ Submit Comment ]From tonywhite1985, 09:03 Oct 18, 2023 (score=3)
After a long search for a clean code, finally I found this! Literally.
I make a little change to avoid to declare double callback method.
With a further modification, you can allow additional parameters to be passed, but I currently don't need to implement this.
This is my little contribute:
/*
FLTK callback on private non-static class member
I have a habit of keeping instance state as class member.
This way I can create multiple instances without "dirtying out"
and without accidentally changing the state of another instance.
So it's useful for me to have callbacks as a class member.
C++11 compatible!
*/
////////////
// HEADER //
////////////
#include <FL/Fl.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Button.H>
#include <iostream>
class ExampleWindow : public Fl_Window {
// Constructors and destructors
public:
ExampleWindow();
// Methods
private:
void callback_example_button(Fl_Widget* w); // private non-static member method
// Variables
private:
int my_private_variable = 0;
};
//////////
// CODE //
//////////
int main() {
ExampleWindow *window = new ExampleWindow();
window->show();
return Fl::run();
}
ExampleWindow::ExampleWindow() : Fl_Window(500, 70, "Callback with non static member method") {
Fl_Button *example_button = new Fl_Button(20, 20, 460, 30, "Example Button");
int my_private_and_instanced_value = 3;
my_private_variable++;
// This is where the magic happens
/*
callback parameters:
- lambda function (further information below)
- this (the pointer to the current instance)
lambda parameters:
- w (pointer to the example_button)
- data (the pointer to the current instance)
the lambda code:
- casting data as ExampleWindow*
- use casting to call member function.
* /
example_button->callback(
[](Fl_Widget *w, void *data) {
((ExampleWindow*)data)->callback_example_button(w);
},
this
);
}
void ExampleWindow::callback_example_button(Fl_Widget* w) {
std::cout << "my_private_variable: " << my_private_variable <<"!\n";
}
[ Reply ]
From NULL, 03:42 Nov 13, 2005 (score=3)
static static_callback(Fl_Widget *w, void *data) {
Fl_Widget *p = w->parent();
while (p->parent()) p = p->parent();
((MyClass*)p->user_data())->real_callback(w, data);
}
There is a bug in this method, if you use this on Fl_Window you will have seg fault.
Fl_Widget *p = w; // should be used insted of
Fl_Widget *p = w->parent();
[ Reply ] |