QT中connect()函數的用法


connect()函數實現的是信號與槽的關聯。

注意:只有QO bject類及其派生的類才能使用信號和槽的機制

函數原型:

static QMetaObject::Connection connect(const QObject *sender, const char *signal,const QObject *receiver, const char *member, Qt::ConnectionType = Qt::AutoConnection);  static QMetaObject::Connection connect(const QObject *sender, const QMetaMethod &signal,const QObject *receiver, const QMetaMethod &method, Qt::ConnectionType type = Qt::AutoConnection);  inline QMetaObject::Connection connect(const QObject *sender, const char *signal,const char *member, Qt::ConnectionType type = Qt::AutoConnection) const;

在第一個函數中:第1個參數為信號發射源對象,例如后面的dlg;第2個參數是所發射的信號,例如后面的SIGNAL(dlgReturn(int));第3個參數是接受信號的對象,例如后面的this,表明是本部件,即Widget,當這個參數是this時,可以將其省略掉,因為在第3個函數中,該參數默認為this;第4個參數是要執行的槽,例如:后面的SLOT(showValue(int)),也可以指定一個信號,實現信號與信號的關聯。

注意:

1、對於信號與槽,必須使用SIGNAL()和SLOT()宏,它們將參數轉化為const char *類型

2、第四個參數指定的槽聲明時必須使用slots關鍵字。

eg:

private slots://槽的聲明
  void showValue(int value);   void on_label_linkActivated(const QString &link);

第5個參數,只是一般使用默認值,在滿足某些特殊需求的時候可能需要手動設置。

Qt::AutoConnection:默認值,使用這個值則連接類型會在信號發送時決定。如果接收者和發送者在同一個線程,則自動使用Qt::DirectConnection類型。如果接收者和發送者不在一個線程,則自動使用Qt::QueuedConnection類型。

Qt::DirectConnection:槽函數會在信號發送的時候直接被調用,槽函數運行於信號發送者所在線程。效果看上去就像是直接在信號發送位置調用了槽函數。這個在多線程環境下比較危險,可能會造成奔潰。

不在同一個線程用這個,也可能導致另一個線程槽函數始終不響應。

Qt::QueuedConnection:槽函數在控制回到接收者所在線程的事件循環時被調用,槽函數運行於信號接收者所在線程。發送信號之后,槽函數不會立刻被調用,等到接收者的當前函數執行完,進入事件循環之后,槽函數才會被調用。多線程環境下一般用這個。

Qt::BlockingQueuedConnection:槽函數的調用時機與Qt::QueuedConnection一致,不過發送完信號后發送者所在線程會阻塞,直到槽函數運行完。接收者和發送者絕對不能在一個線程,否則程序會死鎖。在多線程間需要同步的場合可能需要這個。

Qt::UniqueConnection:這個flag可以通過按位或(|)與以上四個結合在一起使用。當這個flag設置時,當某個信號和槽已經連接時,再進行重復的連接就會失敗。也就是避免重復連接

 

connect()函數的5中用法:

第一種

Qt 4 使用宏,主要通過connect + 宏的方式進行通信連接。

connect(發送對象,信號,接收對象,槽函數),其中發送信號和槽函數需要用 SIGNAL() 和 SLOT() 來進行明確的聲明。

以下示例先自定義一個 Button,然后定義兩個信號:

class MyButton : public QWidget
{
Q_OBJECT
public:
  explicit MyButton(QWidget *parent = nullptr);

signals:
  void sigClicked();
  void sigClicked(bool check);  //重載信號
};
那么在用這個 Button 的時候連接這兩個信號,按照舊版本的寫法,應該是這樣:

  connect(m_pBtn,SIGNAL(sigClicked()),this,SLOT(onClicked()));

  connect(m_pBtn,SIGNAL(sigClicked(bool)),this,SLOT(onClicked(bool)));

這種寫法比較麻煩,常常在用的時候缺少括號,不過該寫法很明確,一眼就能看出來是將哪個信號連接到哪個槽。

第二種

Qt 5 推出了新的 connect 函數,不需要使用 SIGNAL() 和 SLOT() 宏,可以在編譯時做類型檢查:

connect函數原型如下:

[static] QMetaObject::Connection QObject::connect(const QObject *sender, PointerToMemberFunction signal, const QObject *context, Functor functor, Qt::ConnectionType type = Qt::AutoConnection)

用 connect 將信號與槽函數連接,不需要再使用 SIGNAL() 和 SLOT() 宏:

  connect(m_pBtn,&MyButton::sigClicked,this,&Widget::onClicked);

這種寫法看起來很簡潔,但是存在一些坑需要注意,這句寫法如果用在上面的示例中,會報錯下面的錯誤:

error: no matching member function for call to 'connect' connect(m_pBtn,&MyButton::sigClicked,this,&Widget::onClicked);

這是因為我們自定義的 Button 中存在兩個重載信號,然后用這種 connect 的方式會無法識別到底想要連接哪個信號。所以,如果信號是重載的話,需要用下面的寫法來替換:

  connect(m_pBtn, static_cast<void (MyButton::*)(bool)>(&MyButton::sigClicked), this, &Widget::onClicked);

問題又來了,如果我的onClicked槽也是重載的話,還是會報同樣的錯誤。因為編譯器不知道你想要真正連接哪個槽。所以這里建議,如果信號重載,可以用上面的方法來寫,如果槽重載…還是用第一種方法來 connect 吧,比較保險,雖然比較麻煩點。

第三種
最后來看一種最新的寫法,忘記是在 Qt 的哪個版本推出的了,主要針對重載信號的連接做了調整,會更簡單些:
同樣是上面的示例:

connect(m_pBtn, QOverload<bool>::of(&MyButton::sigClicked),this,&Widget::onClicked);

很顯然這種寫法相對於第二種會比較簡單些,但依然不能連接到重載的槽函數,如果連接重載槽函數,還是會報之前的錯誤。

第四種:Lambda 函數寫法
個人比較喜歡用lambda函數的方式,如果槽函數中的內容比較簡單的話,沒必要再去單獨定義一個槽來連接, 直接用Lambda 函數會更簡單。
來看一下示例:

connect(m_pBtn, QOverload<bool>::of(&MyButton::sigClicked), this, [=](bool check){
  qDebug()  << "do something";
});

connect(m_pBtn, static_cast<void (MyButton::*)(bool)>(&MyButton::sigClicked), this, [=](bool check){
  qDebug()  << "do something";
});

connect(ui->lineEdit, &QLineEdit::textEdited, this, [=](QString s){   qDebug() << s; });

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM