Qt之信號鏈接,你Out了嗎?

    在遇到多信號問題的時候,你是否常常會鏈接多個槽函數呢?若是你的答案是絕對的,那麼你已經Out好久了。多信號鏈接多個槽,實現不一樣的槽就在潛意識的加大程序的開銷!那麼爲何不去連接同一個槽呢?     數據庫

    今天在次寫下這篇文章,感受有些唐突,可是又不得不寫!由於信號與槽是Qt裏面的最基礎並且是最重要的部分,有不少人問過我關於信號與槽的問題,就總結一下。Qt主要包括:Qt基礎部分(Qt入門、Qt對話框、Qt窗口、自定義窗口部件)、Qt中級(佈局管理、事件處理、二維繪圖、容器、數據庫、多線程、網絡等)、Qt高級(國際化、自定義樣式、三維繪圖、建立插件、嵌入式編程等)。

Qt5以前,信號與槽的鏈接方式看起來會是這樣的:
connect(sender, SIGNAL(signal), receiver, SLOT(slot));
Qt5開始:
connect(sender, &Sender::signal, receiver, &Receiver::slot);
    前者:
    sender和receiver是指向QObject的指針,signal和slot是不帶參數的函數名。SIGNAL()宏和SLOT()宏會把他們的參數轉換成相應的字符串。
    後者:
    (1)編譯器,檢查信號與槽是否存在,參數類型檢查,Q_OBJECT宏是否存在
    (2)信號能夠和普通函數、類的普通成員函數、lambda函數鏈接(不在侷限於信號和槽函數)
    (3)參數能夠是typedef的或者使用不一樣的namespace specifier
    (4)能夠容許一些自動類型的轉換(即信號和槽函數類型沒必要徹底匹配)
一、一個信號鏈接一個槽
     connect(slider, &QSlider::valueChanged, spin_box, &QSpinBox::setValue);
二、一個信號鏈接多個槽
    connect(slider, &QSlider::valueChanged, spin_box, &QSpinBox::setValue);
    connect(slider, &QSlider::valueChanged, this, &QWidget::showValue);
三、多個信號鏈接同一個槽
    connect(push_button, &QPushButton::clicked, this, &QWidget::show);
    connect(tool_button, &QToolButton::clicked, this, & QWidget :: show );
四、一個信號鏈接另外一個信號
     connect(push_button, &QPushlButton::clicked, this, & QWidget :: buttonClicked );
五、鏈接被移除
    disconnect( push_button ); //斷開push_button的全部鏈接
    disconnect( push_button, &QPushButton::clicked, this, &QWidget::show ); //斷開此信號鏈接的槽

好了,這些都是最基本的應用。那麼多個信號鏈接同一個槽的時候如何進行區分呢?
方法一:
typedef enum{
BUTTON_1,
BUTTON_2,
BUTTON_3,
BUTTON_4
}BUTTON;

 push_button_1->setObjectName(QString::number( BUTTON_1, 10 ));
  push_button_2 ->setObjectName(QString::number( BUTTON_2 , 10 ));
  tool_button_1 ->setObjectName(QString::number( BUTTON_3 , 10 ));
  tool_button _2 ->setObjectName(QString::number( BUTTON_4 , 10 ));
 connect(push_button_1, &QPushButton::clicked, this, &MyWidget::changeButton);
 connect(push_button_2, &QPushButton::clicked, this, & MyWidget :: changeButton );
 connect(tool_button_1, &QToolButton::clicked, this, & MyWidget ::changeButton);
 connect( tool_button _2, & QToolButton ::clicked, this, & MyWidget :: changeButton );

void  MyWidget:: changeButton()
{
    QObject *object = QObject::sender();
    QPushButton *push_button = qobject_cast(object);
     QToolButton *tool_button = qobject_cast<</span>QToolButton  *>(object);
     int index;
    if( push_button )
    {
        QString object_name = push_button->objectName();
        index = object_name.toInt();
    }
    else if( tool_button   )
    {
           QString object_name =  tool_button ->objectName();
         index = object_name.toInt();
    }

    QString information = QString("");
    switch(index)
    {
    case  BUTTON_1:
         information = QString("clicked 1");
        break;

    case  BUTTON_2:
          information = QString("clicked 2");
        break;

    case  BUTTON_3:
         information = QString("clicked 3");
        break;

    case  BUTTON_4:
         information = QString("clicked 4");
        break;

    default:
        information = QString("which is clicked?");
        break;
    }
    QMessageBox::information(NULL, QString("Title"),  information );
}
    固然, setObjectName不是專門用來幹這事的,也可使用text進行區分或者其它方法,這裏介紹的只是一種思路而已!

方法二:
     QSignalMapper 類能夠簡單的理解爲 信號的翻譯和轉發器, 它能夠把一個無參數的信號翻譯成帶 int 參數、 QString 參數、 QObject* 參數或者 QWidget* 參數的信號,並將之轉發。 
QSignalMapper *signal_mapper = new QSignalMapper(this);
connect( push_button_1&QPushButton::clicked, signal_mapper, & QSignalMapper::map);
connect( push_button_2&QPushButton::clicked, signal_mapper,  & QSignalMapper:: map);
connect( tool_button_1&QToolButton::clicked, signal_mapper,  & QSignalMapper:: map);
connect( tool_button_2& QToolButton ::clicked, signal_mapper,  & QSignalMapper:: map);

signal_mapper->setMapping( push_button_1QString::number( BUTTON_1, 10 ));
signal_mapper->setMapping( push_button_2QString::number( BUTTON_2, 10 ));
signal_mapper->setMapping( tool_button_1QString::number( BUTTON_3, 10 ));
signal_mapper->setMapping( tool_button_2QString::number( BUTTON_4, 10 ));
connect(signal_mapper,  & QSignalMapper::mapped, this,  & MyWidget :: changeButton);

void  MyWidget:: changeButton( QString text )
{
    int index =  text .toInt();
    QString information = QString("");
    switch(index)
    {
    case  BUTTON_1:
         information = QString("clicked 1");
        break;

    case  BUTTON_2:
          information = QString("clicked 2");
        break;

    case  BUTTON_3:
         information = QString("clicked 3");
        break;

    case  BUTTON_4:
         information = QString("clicked 4");
        break;

    default:
        information = QString("which is clicked?");
        break;
    }
    QMessageBox::information(NULL, QString("Title"),  information );
}

    那麼,同一信號鏈接多個槽呢,槽函數執行沒有絕對的前後順序。
如:
connect(slider, &QSlider::valueChanged, spin_box, &QSpinBox::setValue);
connect(slider, &QSlider::valueChanged, this, &QWidget::showValue);
valueChanged信號發送時,並非說 setValue必定會比 showValue先執行。
    總結就到這裏,不少東西書上說的都很明白,都是很經常使用,多注意細節部分,編程裏就能夠很輕鬆的實現write less,do more。。。
相關文章
相關標籤/搜索