0

I have 6 buttons' clicked events that I would like to connect with 6 member functions using array of pointers. I can do it like this:

QObject::connect(button_1, SIGNAL(clicked()), this, SLOT(Button1_Function()));
QObject::connect(button_2, SIGNAL(clicked()), this, SLOT(Button2_Function()));
...

But I would like to use array of pointers to buttons and array of pointers to member functions. How can I do it? So far I have this, but I am getting the error about No such slot

class.h

Class(){
    private:
      typedef void (Class::*p_buttons)(void);
      p_buttons p_incr_buttons[6];
    public Q_SLOTS:
      void Button1_Function();
      void Button2_Function();
      ...
    }

class.cpp

Class::Class(){
  p_incr_buttons = {&Class::Button1_Function, &Class::Button2_Function, ... };
  for(int i=0; i<NUM_JOINTS; i++)
  {
    QObject::connect(incr_buttons[i], SIGNAL(clicked()), this, SLOT( (this->*(p_incr_buttons[i]))() ));
  }
}

Thank you very much for your help in advance.

zenzu
  • 51
  • 5
  • Did you consider `QSignalMapper` class? – vahancho Apr 28 '21 at 11:02
  • Use the new [signal/slot syntax](https://wiki.qt.io/New_Signal_Slot_Syntax#New:_connecting_to_QObject_member). – G.M. Apr 28 '21 at 11:04
  • Just an observation: `p_buttons` is the same in every instance, so it's more efficient to make it `static` and initialise it at compile time. – TonyK Apr 28 '21 at 11:36

1 Answers1

1

The SLOT macro just wraps its argument in double quotes (after prepending "1" to show that it's a slot). Then the argument (in your case, "1(this->*(p_incr_buttons[i]))") gets looked up at run-time in a table of slots. But there is no slot called (this->*(p_incr_buttons[i])), hence the error message.

But using the signal/slot syntax that @G.M. links to in a comment, we can do this with a magic lambda expression (after fixing various unrelated errors in your code):

class Class : public QObject { // Must derive from QObject!
      Q_OBJECT             // Must declare this here!
      Class() ;            // And this!
    private:
      typedef void (Class::*p_buttons)(void);
      static p_buttons p_incr_buttons[2];
                           // Better static, because the same in all instances
    public Q_SLOTS:
      void Button1_Function();
      void Button2_Function();
    } ;                    // Terminating semi-colon required!

Class::p_buttons Class::p_incr_buttons[2] = {
      &Class::Button1_Function,
      &Class::Button2_Function,
    } ;

Class::Class(){
  for(int i=0; i<2; i++)
    QObject::connect (incr_buttons[i], &QPushButton::clicked,
      this, [this, i]() { (this ->* p_incr_buttons[i])() ; }) ;
}

Alternatively, you can initialise the p_incr_buttons array inside the class definition. You have to declare it constexpr, and it has to come after the function declarations:

class Class : public QObject {
      Q_OBJECT
      Class() ;
    public Q_SLOTS:
      void Button1_Function();
      void Button2_Function();
    private:
      typedef void (Class::*p_buttons)(void);
      static constexpr p_buttons p_incr_buttons[2] = {
        &Class::Button1_Function,
        &Class::Button2_Function,
      } ;
    } ;
TonyK
  • 16,761
  • 4
  • 37
  • 72
  • I think you could skip the lambda, and directly connect to the function pointer – king_nak Apr 28 '21 at 13:13
  • @king_nak: `p_incr_buttons[i]` is not a function pointer, it's a pointer-to-member-function. – TonyK Apr 28 '21 at 13:17
  • The unrelated errors were done in the process of simplification code, I was not careful. Thank you for your answer, it works :) I had to change `&clicked` to `&QPushButton::clicked`. Few theoretical things: What is this declaration called? Why cant I do it within the constructor?: `Class::p_buttons Class::p_incr_buttons[2] = {...}` Also can I put it into `class.h` file? – zenzu Apr 29 '21 at 07:25
  • 1
    It's called [static data initialization](https://stackoverflow.com/q/11300652/428857). And no, you can't do it in the constructor, at least not using your sytnax. But see my updated answer for another solution. – TonyK Apr 29 '21 at 09:10