一、QSignalMapper用法
在Qt中,QSignalMapper是一個很有用的工具類,它可以將一個信號和多個對象進行關聯。當該信號被觸發時,QSignalMapper會發出自己的一個信號,同時在這個信號中傳遞與觸發的對象關聯的數據。
通常,我們可以使用QSignalMapper來處理一組控件的觸發信號,比如QPushButton的clicked()信號,使用QSignalMapper可以使每個按鈕觸發的操作都不同,這給我們的程序帶來了更靈活的設計。
接下來,我們來看一下QSignalMapper的使用方法。
// 創建QSignalMapper對象
QSignalMapper *mapper = new QSignalMapper(this);
// 創建QPushButton對象
QPushButton *btn1 = new QPushButton(tr("Button 1"));
QPushButton *btn2 = new QPushButton(tr("Button 2"));
// 信號與槽函數之間的關聯
connect(btn1, SIGNAL(clicked()), mapper, SLOT(map()));
connect(btn2, SIGNAL(clicked()), mapper, SLOT(map()));
// 將按鈕與數據相關聯
mapper->setMapping(btn1, "Button 1 clicked");
mapper->setMapping(btn2, "Button 2 clicked");
// 連接QSignalMapper自己的信號
connect(mapper, SIGNAL(mapped(QString)), this, SLOT(handleButton(QString)));
上面的例子中,我們先創建了一個QSignalMapper對象,並創建了兩個QPushButton對象。接着,使用connect()將兩個QPushButton對象的clicked()信號與QSignalMapper對象的map()槽函數關聯起來,將QPushButton對象與相關聯的數據(這裡是QString)使用setMapping()方法進行關聯。最後連接QSignalMapper自己的mapped()信號到handleButton()槽函數上。
當我們點擊QPushButton對象時,每個按鈕觸發的操作都會被區別對待,並且操作的具體內容會在handleButton()槽函數中處理。
二、QSignalMapper Mapping
在上一節中,我們使用setMapping()方法將QPushButton對象與QString數據相關聯。實際上,QSignalMapper可以與任意類型的QObject對象進行相關聯。
另外,使用QSignalMapper的一個重要技巧是將整個對象作為映射,而不是對象的一個屬性。這意味着如果想要對一個控件發射信號並提供額外的信息,我們可以將該控件本身作為映射,在槽函數中獲取所有需要的相關信息。
下面是一個基於QSignalMapper的完整的代碼示例:
#include
#include
#include
#include
#include
#include
#include
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = nullptr) : QWidget(parent)
{
// 創建QSignalMapper對象
mapper = new QSignalMapper(this);
// 創建標籤
QLabel *label = new QLabel(tr("Click any button"));
layout()->addWidget(label);
// 創建QPushButton對象
QVariantMap properties{{"text", tr("Button 1")}, {"tag", 1234}};
QPushButton *btn1 = createPushButton(properties);
properties.replace("text", tr("Button 2"), "tag", 5678);
QPushButton *btn2 = createPushButton(properties);
// 信號與槽函數之間的關聯
connect(btn1, SIGNAL(clicked()), mapper, SLOT(map()));
connect(btn2, SIGNAL(clicked()), mapper, SLOT(map()));
// 將按鈕與數據相關聯
mapper->setMapping(btn1, btn1);
mapper->setMapping(btn2, btn2);
// 連接QSignalMapper自己的信號
connect(mapper, SIGNAL(mapped(QObject*)), this, SLOT(handleButton(QObject*)));
setLayout(new QVBoxLayout());
layout()->addWidget(btn1);
layout()->addWidget(btn2);
}
public slots:
void handleButton(QObject *obj)
{
QPushButton *button = qobject_cast(obj);
QVariantMap properties = button->property("attributes").toMap();
QMessageBox::information(this, "Info", QString("Button clicked!\n"
"Text: %1\n"
"Tag: %2\n").arg(properties["text"].toString(),
properties["tag"].toInt()));
}
private:
QPushButton* createPushButton(const QVariantMap &properties)
{
QPushButton *button = new QPushButton(this);
button->setProperty("attributes", QVariant(properties));
button->setText(properties.value("text").toString());
return button;
}
QSignalMapper *mapper;
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
上面例子中,我們創建了一個QPushButton對象,並關聯了兩個數據:text和tag。我們使用QVariantMap將數據存儲在屬性中,並使用setMapping()方法將QPushButton對象與自身相關聯。在handleButton()槽函數中,我們使用qobject_cast()將QObject對象強制轉換為QPushButton對象,並從其屬性中檢索相關信息進行處理。
三、QSignalMapper替代類
雖然QSignalMapper是一個非常實用的工具類,但在一些簡單的應用程序中,它可能會顯得過於笨重和複雜。Qt提供了許多替代QSignalMapper的方法。
QObject::sender()方法經常被用來獲取發射信號的對象。當信號觸發時,QObject::sender()會返回最後一個發射信號的對象。
於是,我們可以在槽函數中使用switch()或者if()等條件語句對不同的對象進行判斷,並執行對應的操作。
下面以一個簡單的例子來演示如何使用QObject::sender()方法替代QSignalMapper:
#include
#include
#include
#include
#include
#include
#include
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = nullptr) : QWidget(parent)
{
QPushButton *btn1 = new QPushButton(tr("Button 1"));
QPushButton *btn2 = new QPushButton(tr("Button 2"));
connect(btn1, SIGNAL(clicked()), this, SLOT(handleButton()));
connect(btn2, SIGNAL(clicked()), this, SLOT(handleButton()));
setLayout(new QVBoxLayout());
layout()->addWidget(btn1);
layout()->addWidget(btn2);
}
public slots:
void handleButton()
{
QPushButton *button = qobject_cast(sender());
if(button == nullptr) { return; }
qDebug() <text());
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
上面例子中,我們創建了兩個QPushButton對象,並使用QObject::sender()方法檢索哪一個QPushButton發射了信號。在槽函數中使用qobject_cast()將QObject對象強制轉換為QPushButton對象,並輸出該QPushButton對象的文本。
四、QSignalMapper獲取信號發射對象選取
有時候,我們想在控件中保存一些數據,而不想使用屬性。在這種情況下,我們可以使用QWidget::setUserData()和QWidget::userData()來保存控件的相關信息。使用QSignalMapper是很方便的,我們可以將保存在QWidget::userData()中的數據直接傳遞到槽函數中。
下面是一段代碼示例,演示如何使用QWidget::userData():
#include
#include
#include
#include
#include
#include
#include
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = nullptr) : QWidget(parent)
{
QPushButton *btn1 = new QPushButton(tr("Button 1"));
QPushButton *btn2 = new QPushButton(tr("Button 2"));
btn1->setUserData(0, QVariant(1234));
btn2->setUserData(0, QVariant(5678));
connect(btn1, SIGNAL(clicked()), this, SLOT(handleButton()));
connect(btn2, SIGNAL(clicked()), this, SLOT(handleButton()));
setLayout(new QVBoxLayout());
layout()->addWidget(btn1);
layout()->addWidget(btn2);
}
public slots:
void handleButton()
{
QPushButton *button = qobject_cast(sender());
if(button == nullptr) { return; }
QVariant data = button->userData(0);
if(data.isValid() && data.type() == QVariant::Int) {
qDebug() <text(), data.toInt());
}
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
上面例子中,我們創建了兩個QPushButton對象,並使用QWidget::setUserData()將其與QVariant對象相關聯。在槽函數中,我們使用qobject_cast()檢索sender()對象,並使用QWidget::userData()獲取已關聯的數據。
五、總結
QSignalMapper是一個非常有用的工具類,可以使我們處理多個控件發射的信號更加靈活。使用QSignalMapper,可以將一個信號和多個對象進行關聯。當該信號被觸發時,QSignalMapper會發出自己的一個信號,同時在這個信號中傳遞與觸發的對象關聯的數據。
另外,QObject::sender()方法是一個方便的替代QSignalMapper的方式。當信號被觸發時,可以使用QObject::sender()獲取發射信號的對象,並使用qobject_cast()將QObject對象強制轉換為實際的控件對象。
最後,在控件中保存數據時,可以使用QWidget::userData()和QWidget::setUserData()方法,將控件與QVariant對象相關聯。
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/231969.html