C ++ Qt,传递回调

时间:2017-12-25 00:22:28

标签: c++ qt

编辑#2:找出我需要的lambda调用语法!

[=](int value) { (this->*callback_function)(i, value); }

仍在寻找有关如何更好地协调此任务的建议......这看起来太乱了。

编辑:更新了代码,几乎在那里,但仍然遇到了障碍。

template <typename F>
void Dialog::create_spinbox_column(const int &NUM_ROWS, QFrame *&frame,
                                   QLabel *label_arr[],
                                   QSpinBox *spinbox_arr[],
                                   F callback_function) {
    frame = new QFrame();
    QGridLayout *layout = new QGridLayout;
    for(int i = 0; i < NUM_ROWS; i++) {
        int row = i+1;
        QString label_text = QObject::tr("Line %1:").arg(row);
        label_arr[i] = new QLabel(label_text);
        spinbox_arr[i] = new QSpinBox;
        layout->addWidget(label_arr[i], row, 1);
        layout->addWidget(spinbox_arr[i], row, 2);
        QObject::connect(spinbox_arr[i], qOverload<int>(&QSpinBox::valueChanged), this,
                        [=](int value) { callback_function(i, value); } );
    }
    frame->setLayout(layout);
}

我收到错误

error: must use '.*' or '->*' to call pointer-to-member function in 'callback_function (...)', e.g. '(... ->* callback_function) (...)'
                         [=](int value) { callback_function(i, value); } );
                                                       ^

我尝试过this->callback_function(i, value)之类的一些事情,但我尝试过的任何事情都没有奏效。我绝对不希望回调是静态的,这没有意义,它应该在当前调用create_spinbox_column函数的Dialog类的上下文中调用。

以下是原帖:

我最近开始使用Qt将我的一个程序从基于文本的输入转换为GUI输入,但我遇到了一些障碍。我可以使用高级设计反馈如何做到这一点&#34;正确&#34;在Qt中,以及如何调试当前问题的具体反馈。

首先,快速描述我当前的任务(如果你不在乎,直接跳到下面我的代码):我将有大量的旋转盒,我希望整齐地组织并连接到回调void callback_with_id(int id, int value)形式的函数,其中id将是一个唯一的数字,用于标识哪个旋转框的值已更改,而value当然是该旋转框的新值。< / p>

我设法创建了一个我喜欢的视觉布局,但是尝试将spinbox连接到回调函数会给我带来麻烦。这是我的代码,目前还没有编译。请暂时假装ACCOUNT_DATA_COLS = 1

void Dialog::create_spinbox_column(const int &NUM_ROWS, QFrame *&frame,
                                   QLabel **label_arr,
                                   QSpinBox **spinbox_arr,
                                   void (*callback_function)(int, int)) {
    frame = new QFrame();
    QGridLayout *layout = new QGridLayout;
    for(int i = 0; i < NUM_ROWS; i++) {
        int row = i+1;
        QString label_text = QObject::tr("Line %1:").arg(row);
        label_arr[i] = new QLabel(label_text);
        spinbox_arr[i] = new QSpinBox;
        layout->addWidget(label_arr[i], row, 1);
        layout->addWidget(spinbox_arr[i], row, 2);
        //QObject::connect(spinbox_arr[i], SIGNAL(valueChanged(int)), this,
        //                [=](int value) { callback_function(i, value); };
    }
    frame->setLayout(layout);
}

(我注释掉了连线,因为我收到了编译错误。)

void Dialog::create_account_data_grid() {
    account_data_box = new QGroupBox(tr("Account Data"));
    QHBoxLayout *layout = new QHBoxLayout;
    for (int i = 0; i < ACCOUNT_DATA_COLS; i++) {
        QFrame *frame;
        QLabel *label_arr[ACCOUNT_DATA_ROWS];
        QLabel *spinbox_arr[ACCOUNT_DATA_ROWS];
        create_spinbox_column(ACCOUNT_DATA_ROWS, frame, label_arr, spinbox_arr,
                              callback_with_id);
        // int col = i + 1;
        layout->addWidget(frame);
    }
    account_data_box->setLayout(layout);
}

和我的回调函数:

void Dialog::callback_with_id(int id, int value) {
    std::cout << "callback_with_id(" << value << ", " << id << ")" << std::endl;
}

我收到了错误

error: no matching function for call to 'Dialog::create_spinbox_column(const int&, QFrame*&, QLabel* [8], QLabel* [8], <unresolved overloaded function type>)'
                               callback_with_id);
                                               ^

我确定我在这里做了不止一件事,不胜感激任何反馈。

1 个答案:

答案 0 :(得分:3)

注释行的问题在于您混合了两种不同类型的连接:&#34;运行时&#34; (使用SIGNALSLOT宏)和&#34;编译时&#34; (允许你直接传递callable的那个)。

通常后者的语法是

QObject::connect(spinbox_arr[i], &QSpinBox::someSignal, this,
                [=](int value) { callback_function(i, value); };

但你不能直接对valueChanged信号执行此操作,因为它有两个重载,因此您必须使用qOverload,因此生成的代码将如下所示:

QObject::connect(spinbox_arr[i], qOverload<int>(&QSpinBox::valueChanged), this,
                [=](int value) { callback_function(i, value); };

这需要一些C ++ 14支持。如果您还没有,那么您必须使用QOverload<int>::of(&QSpinBox::valueChanged)

另外,正如评论中所指出的,请确保:

  1. callback_with_id是一个静态函数,
  2. 或使create_spinbox_column模仿仿函数类型,
  3. 或者只是将create_spinbox_column的最后一个参数更改为std::function<void(int, int)>并在呼叫站点传递lambda capture this
  4. 如果您希望我详细说明这些要点,请告诉我们。