標籤:
QSignalMapper這個類並不是個新鮮概念, 早在Qt2裡就已經存在, 而且它的功能也是始終如一。 不過由於宣傳力度不夠(例子裡涉及到它的很少)瞭解這個類人可能還不是很多, 所以特此撰文介紹此類的功能和用法。簡單的理解,可以把SignalMapper這個類看成是訊號的翻譯和轉寄站, 它可以把一個無參數的訊號翻譯成帶int參數、QString參數、QObject*參數或者QWidget*參數的訊號, 並將之轉寄。這麼一說大家有沒有聯想到該類的適用範圍呢? 呵呵, 是不是一下就想到了如果我有一堆的button, 可以把clicked事件放在一個函數裡處理, 只要給button編個號或者給button起個名就行了, 這樣就不用給每個button寫一個slot了,豈不是很方便?
下面這段代碼就實現了該功能:
/***mainwin.h***/
#ifndef MAINWIN_H#define MAINWIN_H#include <QWidget>class QSignalMapper;class MainWin : public QWidget{ Q_OBJECT public: MainWin(QWidget *parent = 0); ~MainWin();private slots: void doClicked(const QString &btnname);private: QSignalMapper *signalMapper;};#endif // MAINWIN_H
/***mainwin.cpp***/
#include "mainwin.h"#include <QSignalMapper>#include <QLayout>#include <QPushButton>#include <QMessageBox>MainWin::MainWin(QWidget *parent) : QWidget(parent){ QString buttontext = "btn1,btn2,btn3,btn4,btn5,btn6,btn7,btn8,btn9,btn10";//10個button QStringList texts = buttontext.split(","); signalMapper = new QSignalMapper(this); QGridLayout *gridLayout = new QGridLayout; for (int i = 0; i < texts.size(); ++i) { QPushButton *button = new QPushButton(texts[i]); connect(button, SIGNAL(clicked()), signalMapper, SLOT(map()));//原始訊號傳遞給signalmapper signalMapper->setMapping (button, texts[i]); //設定signalmapper的轉寄規則, 轉寄為參數為QString類型的訊號, 並把texts[i]的內容作為實參傳遞。 gridLayout->addWidget(button, i / 3, i % 3); } connect(signalMapper, SIGNAL(mapped (const QString &)), this, SLOT(doClicked(const QString &)));//將轉寄的訊號串連到最終的槽函數 setLayout(gridLayout);}void MainWin::doClicked(const QString& btnname){ QMessageBox::information(this,"Clicked",btnname+" is clicked!");}MainWin::~MainWin(){ }
/***main.cpp***/
#include <QApplication>#include "mainwin.h"int main(int argc, char *argv[]){ QApplication a(argc, argv); MainWin w; w.show(); return a.exec();}
從這個例子來看QSignalMapper的用法是非常簡單的, 也很容易理解。
(1)首先把原始不帶參數的訊號串連到signalmapper的map槽函數, 這樣signalmapper能在第一時間接收到原始訊號;
(2)其次調用setMapper方法告訴signalmapper怎樣去處理原始訊號。 在這個例子中是把原始訊號轉化為一個帶QString參數的訊號
(3)最後接收轉化後的帶參數訊號, 這裡所把轉化後的訊號與槽函數串連, 在槽函數中獲得需要的資料。
QSignalMapper類的功能核心是要建立一個從發出原始訊號的object到需要的資料的映射(setMapper函數), 如果你的程式恰巧需要這樣的功能,那麼當然QSignalMapper就是當仁不讓的最佳選擇。 除了上述最常見的用法, 我們也來開動腦筋想想還有什麼別的場合適合使用這個類呢?
在Qt的examples裡有一個例子用到了QSignalMapper這個類, 在examples/mainwindow/mdi/mainwindow.cpp裡。 它的用法是將QWidget指標作為參數, 然後菜單選中的訊號映射到子Window的指標, 最終由QMainWindow來處理, 用於實現子視窗的切換。 這個用法很有些意思, 可以說是QSignalMapper的最佳用例, 建議大家學習一下。 這裡截取其中最核心的代碼, 有注釋應該很好看懂吧, 如果還是有問題就留言:
//主類從QMainWindow派生MainWindow::MainWindow(){ //... windowMapper = new QSignalMapper(this); connect(windowMapper, SIGNAL(mapped (QWidget *)), this, SLOT(setActiveSubWindow(QWidget *))); //轉寄的訊號直接連接到QMainWindow的setActiveSubWindow槽 //...}void MainWindow::updateWindowMenu(){ //... QList windows = mdiArea->subWindowList(); separatorAct->setVisible(!windows.isEmpty()); for (int i = 0; i < windows.size(); ++i) { MdiChild *child = qobject_cast(windows.at(i)->widget()); QString text; if (i < 9) { text = tr("&%1 %2").arg(i + 1) .arg(child->userFriendlyCurrentFile()); } else { text = tr("%1 %2").arg(i + 1) .arg(child->userFriendlyCurrentFile()); } QAction *action = windowMenu->addAction(text); action->setCheckable(true); action ->setChecked(child == activeMdiChild()); connect(action, SIGNAL(triggered()), windowMapper, SLOT(map ()));//監控action的triggered訊號 windowMapper->setMapping (action, windows.at(i));//建立action指標到QWidget*的映射 } //... }}<pre name="code" class="cpp">void MainWindow::setActiveSubWindow(QWidget *window) // 設定活動子視窗{ if (!window) // 如果傳遞了視窗組件,則將其設定為使用中視窗 return; ui->mdiArea->setActiveSubWindow(qobject_cast<QMdiSubWindow *>(window));}
此外,在C:\Qt\4.8.4\examples\tools\inputpanel此例中也用到了訊號映射器。
引自:http://blog.csdn.net/cuteqt/article/details/4306900
轉自:http://blog.csdn.net/zzwdkxx/article/details/28437441
QSignalMapper類處理多訊號關聯同一個槽的方法(1)