Essential Qt 第三章 信號與槽


        還記得第一章的Hello Qt程序嗎,不知道你有沒有用QPushButton來代替QLabel來重新實現這個程序,因爲這一章需要用到這個
        在正式討論信號與槽之前,我們先簡單的討論一個問題,在界面中,有很多結束/關閉的選項,點擊一下程序就結束了,在Qt中,也有類似的情況,比如我點擊一個按鈕,整個程序就結束了,放在代碼的角度來說,有一個類,當我執行他的一個成員函數(點擊了這個按鈕),另一個類(整個窗體)就要執行對應的某個成員函數,那如何把這兩個類的成員函數鏈接在一起呢,確保執行了一個函數後另一個函數也會被執行?爲了解決類似的問題,Qt提供了信號與槽的概念用於來實現這類功能,當然熟悉UNIX/Linux的朋友也瞭解信號這個概念,但需要說明的是Qt的信號和UNIX/Linux的信號沒有任何關係
      以QPushButton爲例,當點擊他的時候就會出發clicked()信號,這個信號可以用來和對應的槽來連接,當沒有與槽連接時,這個信號沒有任何作用。碰巧的是QPushButton自身也有一個槽close(),這個槽的作用就是關閉自身,所以我們可以做一個按鈕,點擊他就會自己關閉,而不是點就右上角的"X"
#include<QApplication>
#include<QPushButton>
int main(int argc , char** argv)
{
  QApplication app(argc,argv);
  QPushButton* quit_pushbutton = new QPushButton("Quit");
  quit_pushbutton->show();
  QObject::connect(quit_pushbutton,SIGNAL(clicked()),quit_pushbutton,SLOT(close()));
  return app.exec();
}


           這段代碼和第一章Hello Qt代碼相比多了一行,就是信號與槽的鏈接,鏈接使用類QObject的靜態函數connect()來完成,這個函數看起來有點複雜,但其參數其實很簡單
            connect(信號對象,SIGNAL(信號函數),槽對象,SLOT(槽函數))
         這樣我們就完成了一個信號和槽的連接,當點擊按鈕是按鈕發出clicked()信號,接受這個信號的槽(函數),也就是close()也被觸發(執行),於是這個按鈕就被關閉了。
           這裏需要說明的是類QObject這個類,這個類是Qt中一個很基礎的類,在Qt中所有擁有信號和槽的對象都繼承子該類,換言之,如一個類需要擁有信號或槽,則必須繼承這個QObject

           然後我們來看一個稍顯負責的例子
         
           這個程序用於顯示年齡,在一個對話框裏安裝了2個窗體,一個“顯示塊”,一個“劃杆”,當然他們確切的名字分別是QSpinBox和QSlider,在這個程序中,拖動劃塊,“顯示塊”對於的數值就會改變,同樣,修改“顯示塊”的值也會是的“劃杆”的值改變。這裏就用到了信號與槽的連接,當QSpinBox數值改變,出發一個信號,這個信號與QSlider的槽連接,這個槽作用就是改變自身的值。同樣的QSlider的值改變是也會出發一個信號,這個信號同樣的和QSpinBox的槽連接。當然這裏我們還需要面對一個問題,那就是信號與槽直接除連接外,還需要傳輸數據。
#include<QApplication>
#include<QDialog>
#include<QSpinBox>
#include<QSlider>
#include<QHBoxLayout>
int main(int argc , char** argv)
{
  QApplication app(argc,argv);
 
  QDialog* top_dialog = new QDialog;
  QSpinBox* box_spinbox = new QSpinBox;
  QSlider* box_slider = new QSlider(Qt::Horizontal); //註釋1

  box_spinbox->setRange(0,130);   //註釋2
  box_slider->setRange(0,130);

  QObject::connect(box_spinbox,SIGNAL(valueChanged(int)),box_slider,SLOT(setValue(int)));  //註釋3
  QObject::connect(box_slider,SIGNAL(valueChanged(int)),box_spinbox,SLOT(setValue(int)));
  box_spinbox->setValue(30);  //註釋4

  QHBoxLayout* top_layout = new QHBoxLayout;
  top_layout->addWidget(box_spinbox);
  top_layout->addWidget(box_slider);

  top_dialog->setLayout(top_layout);
  top_dialog->setWindowTitle("Show Your Age");
  top_dialog->show();

  return app.exec();
}


     註釋1 這裏生產了我們需要的3個窗體,分別是QDialog,QSpinBox和QSlider,這裏需要說明的是QSlider的構造函數有個默認的參數,是一個枚舉量,取值分別爲Qt::Horzental和Qt::Vertical,其默認值爲Qt::Vertical,有興趣的可以使用默認值在編譯下這個程序
      註釋2  這裏設置2個窗體顯示數值的範圍,暫且假設人最大的年齡不會超過130歲
      註釋3 這裏是整個程序的核心代碼,QSpinBox和QSlider都有一個valueChanged(int)的信號,當他們的值改變的時候會發射,他們也都有一個槽setValue(int),用於改變自身的值,這裏也說明了,信號如何把數據傳遞給槽的,所以不同窗體(類)直接的數據傳輸也可以用信號與槽來實現,這種方式在後面的例子中將會不斷的用到。
      註釋4 這裏給定一個初始值,由於已經連接了信號與槽,所以設定一個窗體的值,另一個窗體的值也會改變,不需要而外設置,另外你也可以把這行代碼移動到註釋3上面看看效果

     關於信號與槽
     1 同一個信號可以和多個槽連接,一個槽也可以與多個信號鏈接。同時信號也可以與信號連接,類似與
        connect(對象A,SIGNAL(clicked),對象B,SIGNAL(valueChanged(int))
         這種情況通常用於多個信號需要同時發射
      2  對於通過信號與槽傳遞參數,信號函數和槽函數的參數必須一致,如果有這樣的連接
          connect(對象A,SIGNAL(valueChange(std::string,int),對象B,SLOT(valueChanged(int,std::string))
那槽 將無法接受到任何數據,如果槽函數的參數有默認值將會使用默認值,如果沒有就會出錯,而對於下面這樣的連接
           connect(對象A,SIGNAL(valueChange(std::string,int),對象B,SLOT(valueChanged(std::string))
 不會出現錯誤,但信號中int數據將無法傳遞到槽函數中     
        3 信號與槽其實就是類的成員函數,所不同的是信號函數一般沒有代碼,而槽函數有函數定義來實現具體的功能  ,當然這樣只是表明現象,其實信號函數之所以沒有代碼,是Qt已經做了一些處理,而並非真正的沒有代碼
發佈了92 篇原創文章 · 獲贊 19 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章