在 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 有几个原因:
- 它消除了为
pb_label
存储临时 lambda 和临时 - 它删除了需要额外堆栈框架的 lambda 间接寻址
- 调试到 lambdas 并不总是对开发人员友好,尽管一些 IDE 缓解了这个问题
- Prior to Qt 5.2 there was no way to disconnect a lambda slot if objects it depended upon were destroyed :
QString
的需要
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/