c++ - 使用 C++11 lambda 函数将点击事件连接到函数时出现问题

标签 c++ qt c++11 lambda

在 GUI 应用程序中,我使用了相当多的按钮。这些按钮标记为 pbxx,其中 xx 是网格布局中按钮的行号和列号。按下按钮时,需要突出显示它。今天我读到了 lambda 函数 Brian Poteat & Kuba Ober并认为我会尝试在我的代码中实现它。

在我的 GuiDisplay 类(继承 QMainWindow 的类)中,我有一个函数叫做:

make_connections(); 

这将使我所有的按钮连接(所有信号都连接到一个插槽 on_pushbutton_clicked()。我在此处添加了代码:

GuiDisplay 类

class GuiDisplay : public QMainWindow
{
    Q_OBJECT

public:
    explicit GuiDisplay(QWidget *parent = 0);
    ~GuiDisplay();

    ... Some more public functions ...

    /**
     * @brief Connects all custom signals and slots.
     */
    void make_connections();

    /**
     * @brief Will highlight the provided pushbutton with provided rgb colour
     */
    void highlight_pushbutton(QPushButton &pb, const int rgb[]);

private slots:
    void on_pushbutton_clicked(const QString& label);

private:
    Ui::GuiDisplay *ui;
};

GuiDisplay类的make_connections函数

void GuiDisplay::make_connections()
{
    // Loop through all the pushbuttons and connect clicked signal to clicked slot
    QString pb_label = "";
    for(int i = 0; i < 8; ++i)
    {
        for(int j = 0; j < 8; ++j)
        {
            // Find the pushbutton
            pb_label = "pb" + QString::number(i) + QString::number(j);
            QPushButton* pb_ptr = this->findChild<QPushButton*>(pb_label);
            //connect(pb_ptr, SIGNAL(clicked()), this, SLOT(on_pushbutton_clicked()));
            connect(pb_ptr, &QPushButton::clicked, [this]{on_pushbutton_clicked(pb_label);});
        }
    }
}

连接时出现问题

connect(pb_ptr, &QPushButton::clicked, [this]{on_pushbutton_clicked(pb_label);});

构建给了我以下错误

'pb_label' is not captured

所以我想好吧,那么改为执行以下操作似乎没有错:

connect(pb_ptr, &QPushButton::clicked, [this, &pb_label]{on_pushbutton_clicked(pb_label);});

构建时的错误消失了,但是每当执行这段代码时,我的 GUI 应用程序就会意外崩溃。不知道为什么。这里有什么帮助吗?

最佳答案

您的错误是由于使用了对临时文件的引用。 pb_label 仅在 GuiDisplay::make_connections 期间存在,您的 lambda 由 Qt 存储,每次触发信号时都会被引用。发生这种情况时,您将引用一个已销毁的对象。

所以正确的连接方式是:

connect(pb_ptr, &QPushButton::clicked, [=]{ on_pushbutton_clicked(pb_label); });

从 Qt 5.2 开始 QMetaObject::Connection QObject::connect(const QObject *sender, PointerToMemberFunction signal, const QObject *context, Functor functor, Qt::ConnectionType type = Qt::AutoConnection)添加了重载,它将在对象生命周期结束时自动断开连接。在这种情况下,连接将是:

connect(pb_str, &QPushButton::clicked, this, [=]{ on_pushbutton_clicked(pb_label); });

那就是说你不应该在这里使用 lambda,你可以简单地这样做:

connect(pb_ptr, &QPushButton::clicked, this, &GuiDisplay::on_pushbutton_clicked);

然后修改您的 GuiDisplay::on_pushbutton_clicked 以不接受任何参数。您可以通过调用以下命令获取 GuiDisplay::on_pushbutton_clicked 中对象的名称:sender()这将:

Returns a pointer to the object that sent the signal

然后只需使用 QObject::objectName获取pb_label:

This property holds the name of this object

因此,您只需将 pb_label 替换为:sender()->objectName()

直接槽连接优于 lambda 有几个原因:

  1. 它消除了为 pb_label
  2. 存储临时 lambda 临时 QString 的需要
  3. 它删除了需要额外堆栈框架的 lambda 间接寻址
  4. 调试到 lambdas 并不总是对开发人员友好,尽管一些 IDE 缓解了这个问题
  5. Prior to Qt 5.2 there was no way to disconnect a lambda slot if objects it depended upon were destroyed :

There is no automatic disconnection when the 'receiver' is destroyed because it's a functor with no QObject.

关于c++ - 使用 C++11 lambda 函数将点击事件连接到函数时出现问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36198350/

相关文章:

c++ - 从windbg堆输出垃圾摘要

c++ - 模板化运行时检查调用包装器以检测输入参数或返回值中的转换溢出

c++ - 用类 fnc 中的数据填充 vector

c++ - Qt:正确存储自定义小部件的图像资源

c++ - 在 QSqlQuery::addBindValue() 中为 LIKE 转义 %(百分比)

c++ - 使用 QMathGL 绘制实时数据?

c++ - 运行中的Thread与线程对象的关系

templates - C++11 非常量 constexpr 函数,带模板 : OK, 不带模板:错误

c++ - 从不在子对话框中调用子的 DoDataExchange? - MFC

c++ - 获取具有计数的 vector 的不同 vector