天天看點

Qt信号槽機制的簡單例子

回到QT,先在VS中建立一個QT Application,項目裡面有幾個目錄:

1、Form Files目錄,它裡面放的是使用QT designer制作的基于XML的布局檔案,輕按兩下它就會自動進入QT designer。

2、Generated Files目錄,它裡面放的是一些臨時生成的檔案,這些檔案用來處理QT的信号和槽等機制。

3、Resource Files目錄,它裡面放的是基于XML的資源檔案,你可以在窗體裡面使用它們。

4、Header Files和Source Files這兩個和VS預設是一樣的。

了解了目錄結構之後,先來試着寫一個Hello World,先把除了main.cpp之外的所有檔案移除(使用QT designer會提高制作效率,但是會讓QT入門門檻變高)!打開main.cpp,僅保留以下代碼:

#include <QtGui/QApplication>   

int main(int argc, char *argv[])  

{   

         QApplication a(argc, argv);         

         return a.exec();   

}  

編譯通過。運作沒有任何反應,因為還沒有往裡面增加任何東西。

在代碼中,Main函數是C語言的入口,之後申請的QApplication用來管理控制流和主要設定,這是核心,一定要保留。

按鈕是GUI中最基本的一個控件,先看看怎麼增加一個按鈕。使用按鈕控件必須先包含頭檔案:

#include <QtGui/QPushButton>

然後在QApplication a(argc, argv);與return a.exec();中間插入下面代碼:

QPushButton button("HELLO");   

button.setGeometry(100,100,300,300);   

button.show();  

代碼第一行是申請一個按鈕,并把按鈕的Caption标題設為HELLO,第二行表示這個按鈕出現在螢幕坐标(100,100)的位置,寬高為(300,300),最後一行是顯示這個按鈕,你可以嘗試把它去掉看看效果(官方助手裡有QPushButton的更多資料,請自行檢視)。

編譯出來,發現螢幕上出現一個框,框裡面有一個按鈕,按鈕可以點選,但是沒有任何反應,因為還沒有為這個按鈕增加任何的槽(Slot)。

在MFC對控件的處理一般是通過事件機制,而在QT中是使用信号(Signal)和槽(Slot)機制,其實你也可以把它了解為事件機制。

簡單了解信号其實就是輸入,而槽就是輸出,拿按鈕打比方,在一次點選中,這個點選,就是一個信号,而點選後的回報,就是槽。

每一個控件都擁有一些預設的Signal和Slot,這些都可以在官方提供的助手中檢視。

綁定Signal和slot是使用靜态函數connect。函數原型是:

Bool connect ( const QObject * sender, const char * signal, const QObject * receiver, const char * method, Qt::ConnectionType type = Qt::AutoConnection ) 

其中sender是發送者,而receiver是接收者,signal是信号,而method就是slot,type裡面提供了幾種綁定方式,可以詳細檢視助手。

         先看一個例子,在上面代碼中加入點選按鈕後關閉應用程式的效果。很簡單,隻需要在

button. setGeometry(100,100,300,300);

後面加入

QObject::connect(&button, SIGNAL(clicked()), &a, SLOT(quit()));

編譯運作,點選後窗體關閉。

這是使用預設槽的例子,有時候需要點選按鈕之後執行自定義的效果,那麼就需要使用自定義槽了。

下面是一個使用自定義Slot的例子,滑鼠點選按鈕之後,文本框文字會改變。

先加入一個QLabel控件,你先加入頭檔案:

#include <QtGui/QLabel>

然後在connect前加入

QLabel label("World");

label.setGeometry(50,50,300,300);

先嘗試編譯一下,結果label沒有出現在窗體裡面!它當然不會出現在窗體裡面,因為我們隻是對Button使用了Show()函數,嘗試加入label.show(),結果出現了兩個窗體,一個裡面有按鈕,另一個裡面有一個label。那麼怎麼把它們放在一起呢

通過上面的測試發現,調用一次show就會産生一個視窗,那麼是不是隻調用一次show就行了?把函數裡面代碼改為:

QApplication a(argc, argv);   

QWidget window;   

QPushButton button("HELLO");   

button.setGeometry(100,100,300,300);   

QLabel label("World");   

label.setGeometry(50,50,300,300);   

QHBoxLayout layout;   

Layout.addWidget(&button);   

Layout.addWidget(&label);   

QObject::connect(&button, SIGNAL(clicked()), &window, SLOT(close()));   

window.setLayout(&layout);   

window.show();          

 return a.exec(); 

附上此時的頭檔案清單:

#include <QtGui/QPushButton>

#include <QtGui/QApplication>

#include <QtGui/QLabel>

#include <QtGui/QHBoxLayout>

#include <QtGui/QWidget>

一開始,我就申請了一個QWidget,QWidget類是QT中所有使用者界面對象的基類,它本身并沒有什麼實際意義,在這裡你可以把它看成一個窗體容器,然後又添加了一個

QHBoxLayout layout; QHBoxLayout這是個可以對子widget進行特定布局的控件,通過它可以把按鈕和label并排,之後把窗體的layout設為指定的layout,然後調用show()。

調試運作,終于兩個控件都出現了。

回到之前的話題,自定義槽。在QT中所有自定義槽都需要先編譯成moc,才可以被使用。不過你放心,這個過程由QT自動完成,當然你也可以手動進行編譯,QT的Bin目錄裡面有moc.exe,參照說明進行使用。

你應該可以看到我已經偷偷把按鈕的點選信号轉向了窗體的close槽。為什麼要這樣做呢,因為我們需要把自定義槽函數定義放在頭檔案裡。

第一步,先把window封裝起來,我建立一個MainWidget類,繼承自QWidget類,類的頭檔案如下:

view plaincopy to clipboardprint?

#ifndef _MAIN_WIDGET_H_ 

#define _MAIN_WIDGET_H_ 

#include <QtGui/QLabel> 

#include <QtGui/QHBoxLayout> 

#include <QtGui/QWidget> 

#include <QtGui/QPushButton>  

class MainWidget: public QWidget  

{  

public:  

         MainWidget();  

         ~MainWidget();  

protected:                   

private:      

         QLabel*                               m_pLabel;  

         QPushButton*          m_pButton;  

         QHBoxLayout*                   m_pLayout;  

}; 

#endif  

CPP如下: 

#include "MainWidget.h"  

MainWidget::MainWidget()  

{  

         m_pLabel = new QLabel("World");  

         m_pLabel ->setGeometry(50,50,300,300);  

         m_pButton = new QPushButton ("HELLO");  

         m_pButton ->setGeometry(100,100,300,300);  

         m_pLayout = new QHBoxLayout();  

         m_pLayout -> addWidget(m_pButton);  

         m_pLayout -> addWidget(m_pLabel);  

         connect(m_pButton, SIGNAL(clicked()), this, SLOT(close()));  

         setLayout(m_pLayout);  

}  

MainWidget::~MainWidget()  

{  

Main.cpp改為:

#include <QtGui/QApplication> 

#include "MainWidget.h"  

int main(int argc, char *argv[])  

{  

         QApplication a(argc, argv);  

         MainWidget window;        

         window.show();         

         return a.exec();  

編譯運作,結果和上次一樣。

接下來申請一個自定義Slot,首先在頭檔案public:前加入宏

Q_OBJECT;

隻有加入了Q_OBJECT,你才能使用QT中的signal和slot機制。這點很重要,不然你編譯的時候會報“找不到slot”的錯誤。

然後在protected:  前加入:

private slots:

void                SetText ();

slot同樣也分private、public、protected,意義和c++一樣。

CPP中加入相應執行:

void MainWidget:: SetText ()

{

         m_pLabel -> setText("Test");

}

把connect改成: 

connect(m_pButton, SIGNAL(clicked()), this, SLOT(SetText ()));

編譯運作,這時點選按鈕就會改變文字了。就這麼簡單。

信号也可以自定義,不過信号自定義相對來說用武之地稍微小一點,定義的方式和slot定義差不多,都得在頭檔案中定義,舉個例子:點選按鈕後文本改變,觸發一個新信号,這個信号會把文字又變回來。

在頭檔案中加入:

signals:

     void TextChanged ();

再增加一個Slot用來對這個信号進行回報。在private slots:後加入

void                              RecoverText ();

CPP中加入執行:

void MainWidget::RecoverText()

{

         m_pLabel -> setText("Hello");

}

注意信号是不需要加執行代碼。

然後修改SetText()函數加入觸發新信号的代碼:

emit TextChanged();

最後加入新的connect:

connect(this, SIGNAL(TextChanged()), this, SLOT(RecoverText()));

編譯運作,結果和我們想要的一樣。

注:信号和槽都是可以有參數的。

有關QT的基礎知識就介紹到這裡,具體控件的使用方法,請自行參考助手。

本文來自CSDN部落格,轉載請标明出處:http://blog.csdn.net/pizi0475/archive/2010/05/19/5609474.aspx

繼續閱讀