使用C ++ 11 lambda函数将点击事件连接到函数

时间:2016-03-24 10:46:58

标签: 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 Class的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应用程序就会意外崩溃。不知道为什么。这里有什么帮助?

2 个答案:

答案 0 :(得分:2)

您的错误是由于使用了对临时的引用。 pb_label仅在Qt存储lambda的GuiDisplay::make_connections期间存在,并且每次触发信号时都会引用connect(pb_ptr, &QPushButton::clicked, [=]{ on_pushbutton_clicked(pb_label); }); 。当发生这种情况时,您将引用被破坏的物体。

所以建立连接的正确方法是:

connect(pb_str, &QPushButton::clicked, this, [=]{ 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_ptr, &QPushButton::clicked, this, &GuiDisplay::on_pushbutton_clicked);

那说你不应该在这里使用lambda:

GuiDisplay::on_pushbutton_clicked

然后修改你的GuiDisplay::on_pushbutton_clicked不要参数。您可以通过调用sender()来获取pb_label中对象的名称:

  

返回指向发送信号的对象的指针

然后使用QObject::objectName获取pb_label

  

此属性包含此对象的名称

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

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

  1. 删除了为pb_label
  2. 存储临时lambda 临时QObject的需要
  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
  6.   

    接收器&#39;没有自动断开连接。被破坏是因为它是一个没有$baseUrl = Yii::$app->request->baseUrl; $script = <<< JS $('#selectedsession').on('change',function(){ var value1 = document.getElementById("selectedclass").value; var value2 = document.getElementById("selectedsession").value; $.ajax({ url: '{$baseUrl}/enrollment/rollno', type: "POST", data: { value1: value1, value2 : value2 }, success: function(data) { var abc = data; $("#roll").val(abc); } }); }); JS; 的仿函数。

答案 1 :(得分:1)

谢谢Piotr Skotnicki和Simple,你的两个建议都有效。我可能应该进一步阅读,我会在捕获列表中看到[=](参见:Lambda

因此,导致问题的一行代码可以是:

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

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