C QT,通过回调

C++ Qt, Passing Callbacks

本文关键字:回调 QT      更新时间:2023-10-16

编辑#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函数的当前对话框类的上下文中调用。


以下是原始帖子:


我最近开始使用QT将我的一个程序从基于文本的输入转换为GUI输入,但我遇到了一些障碍。我可能可以在QT中使用"正确执行此操作"的高级设计反馈,以及如何调试我当前问题的具体反馈。

首先,对我当前任务的快速描述(如果您不在乎,请直接跳到下面的代码):我将拥有大量的旋转式盒子 void callback_with_id(int id, int value)的表单,其中 id将是一个唯一的数字识别哪个自旋框的值已更改,而 value当然是该旋转框的新值。

我设法创建了一个我喜欢的视觉布局,但是尝试将旋转框连接到回调功能引起了我的麻烦。这是我的代码,目前尚未编译。现在可以随意假装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);
                                               ^

我确定我在这里做错了一件事,对任何反馈都会很感激。

评论行的问题是您要混合两种不同的连接风格:"运行时"(使用SIGNALSLOT宏)和" Compile-time"(允许您的一个compile time"直接通过可可)。

通常的语法是

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)>,然后通过呼叫站点捕获this的lambda。

请让我知道您是否希望我详细说明这些要点!