How to create a handler in Qt?

638 Views Asked by At

I'm working on an application using Qt version 4.8 in C++.

I need to use a C function which requires a pointer to a free function:

void handler(int dummy)

I need to change the displayed values in my GUI depending on what happens inside the function.

So I've been reading on how to convert a member function to a free function. I've found out that I can do it only if my member function is static.

But I can't make it static - I won't be able to change any widgets if I make it static.

So, how can I deal with the problem? How can I pass a non-static member function as a pointer to a free function. If it's not possible, how to make a workaround?

I'll be grateful for any suggestions different that use another library.

2

There are 2 best solutions below

4
On

Yes, C++ does not allow member functions to be passed as a function pointer to C libraries.

In this cases a common approach is using a helper function that acts like a bridge between the C library and our class instance. This helper function is a free function that takes a pointer to the current instance of the class and in its body invoke the corresponding member method of the class instance.

void handler_helper(int data){
    MyClass *obj = (MyClass *) data;
    obj->handler(); // This is the corresponding member method
}

And where you invoke a function from that C library, you should pass handler_helper as the function pointer and (int) this as its argument.

6
On

Since the C function takes an argument, you can use the argument as an index into an array of functors:

class MyWidget : public QWidget {
  using vector_t = QVector<std::function<void()>>;
  static vector_t m_functions;
public:
  using function_type = void(*)(int);
  using size_type = vector_t::size_type;

  static function_type getHandler() {
    return +[](int index){ MyWidget::m_functions[index]; };
  }
  template <typename F> static size_type getIndexFor(F && fun) {
    m_functions.append(std::forward<F>(fun));
    return m_functions.size() - 1;
  }
  //...
  size_type getIndexForSetTitle();
};

The getHandler returns the address of the handler function. The getIndexFor returns the argument to be passed to the handler to run a given functor. The functor can encapsulate calls to the widget's methods. Here, we'll call setWindowTitle on the widget:

MyWidget::size_type MyWidget::getIndexForSetTitle() {
  static size_type index = getIndexFor([this]{ setWindowTitle("Foo"); });
  return index;
}