使用C++11 lambda函数将点击事件连接到函数时出现问题
Trouble using C++11 lambda function to connect a click event to a function
在GUI应用程序中,我使用了不少按钮。这些按钮被标记为pbxx
,其中xx
是网格布局中按钮的行和列编号。按下按钮时,需要突出显示该按钮。今天我读到关于lambda函数的BrianPoteat&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
修改为不接受任何参数。您可以通过调用:sender()
来获得GuiDisplay::on_pushbutton_clicked
中对象的名称,该调用将:
返回一个指向发送信号的对象的指针
然后只需使用QObject::objectName
即可获得pb_label
:
此属性保存此对象的名称
因此,您只需要将pb_label
替换为:sender()->objectName()
直接插槽连接比lambda:更可取的原因有几个:
- 它消除了为
pb_label
存储临时lambda和临时QString
的需要 - 它删除了需要额外堆栈帧的lambda间接寻址
- 调试到lambdas并不总是对开发人员友好的,尽管有些IDE可以缓解这个问题
- 在Qt 5.2之前,如果lambda插槽所依赖的对象被破坏,则无法断开其连接:
当"接收器"被破坏时,不会自动断开连接,因为它是一个没有
QObject
的函子。
感谢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);});
- 是否有 Windows 用户空间函数来枚举连接的网络共享?
- 如何使用connect将qml按钮与同一类的cpp函数连接起来
- 您将如何连接"on the fly"文本+整数并将其传递给函数?
- 某些 boost::asio 异步函数是否将处理程序连接到操作,以便处理程序被触发一次?
- QObject::连接不起作用 - 使用函数语法找不到信号
- 在函数中连接两个字符,并在 C++ 中返回输出
- 用于连接向量的 Constexpr 函数
- deleteNode函数出现以中断连接列表
- QT - 连接 Qml 按钮 单击到 Cpp 构造函数
- Wt 连接函数,将参数传递给作为连接函数参数的函数
- Qt的新信号/时隙语法问题 - 连接到一个简单的函数
- C++ 将不同的类型连接成函数的字符串
- 如何编写模板函数来添加整数但连接字符串和字符类型?
- 在 for 循环中使用 lambda 函数连接信号插槽
- QObject::使用update()函数连接计时器
- 函数连接两个写入缓冲区开头的字符串
- 使用QObject::connect()时,类型签名是否重要,用于将函数连接到信号
- 如何将Qt动作与函数连接起来
- 如何从一个线程发出信号,并将信号与一个单独的函数连接起来
- QT 5 connect()函数连接textEditor和主窗口