FLTK logo

Article #379: How Can I Use a Class Method as a Callback?

FLTK matrix user chat room
(using Element browser app)   FLTK gitter user chat room   GitHub FLTK Project   FLTK News RSS Feed  
  FLTK Apps      FLTK Library      Forums      Links     Login 
 Home  |  Articles & FAQs  |  Bugs & Features  |  Documentation  |  Download  |  Screenshots  ]
 

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 ]


Comments

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 ]

 
 

Comments are owned by the poster. All other content is copyright 1998-2024 by Bill Spitzak and others. This project is hosted by The FLTK Team. Please report site problems to 'erco@seriss.com'.