Essential Qt 第五章 記事本(二)簡單事件處理

          這一章裏出要會把前兩章製作的2個窗體合併爲一個程序,這裏需要我們手動修改一個關閉事件,在Qt編程中,事件是一個很重要的部分,後面將會一單獨的章節來詳細講述,但應爲這個程序就會用到,所以在這一章簡單的介紹下。
           事件(event)是由窗口系統或者Qt自身產生,用以響應所發生的各類事情。就如第一章裏的使用到的窗部件QPushButton,當鼠標(左鍵或右鍵)點擊就會觸發這個窗體的mousePressEvent()事件,雙擊就會觸發mouseDoubleClickEvent(),當你關閉一個窗體時就會觸發他的closeEvent()事件,這些事件可以根據需要進行修改,比如這章的例子,我們需要修改窗體的關閉時間,使得用戶點擊關閉的時候,窗體隱藏而不是關閉。
          另外需要說明的是,在Qt的類中,大多數事件屬於類的保護函數,

          首先來看上一章製作的ReadMe程序,在這個程序的“編輯”菜單中有“查詢”這個選項,我們希望點擊查詢的時候能夠跳出第三章完成的對話框FindDialog.一個比較簡單的方法就是在ReadMe程序中添加一個FindDialog對象,然後通過信號與槽鏈接,即點擊“查詢”後,顯示FindDialog對象,然後點擊對話框的取消來刪除該對象。但這裏遇到一個問題,FindDialog對象顯示後用戶如果再次點擊"查詢“對話框,就會創建第二個FindDialog,這顯然不符合常理,對於這類情況,可以通過判斷該對象是否存在來,但顯得有點麻煩,另外這樣需要多次生產/刪除一個FindDialog對象,頻繁的向系統申請內存並不是一個好習慣。
          這裏有一個更”取巧“的辦法,關鍵就在於FindDialog類上,當點擊對話框上的”取消“來關閉這個對象,我們修改下這個類的關閉事件,使得他不是關閉,而僅僅是隱藏,那上面的問題就可以得到解決,當點擊”查詢"就顯示FindDialog,用戶點擊"取消"的時候對話框消失,但他其實只是隱藏了,下次用戶再次點擊查詢的時候對話框就會再次顯示(show()函數),另外對已經顯示的窗體調用show()函數不會有任何影響,這也避免了用戶多次點擊查詢而跳出多個對話框的問題

            首先是對FindDialog.h文件最一些修改
#include<QDialog>
#include<QLineEdit>
#include<QCheckBox>
#include<QPushButton>
#include<QLabel>
#include<QCloseEvent>  //註釋1
class FindDialog:public QDialog
{
  Q_OBJECT
  private:
    QLabel* Title_Label;
    QLineEdit* FindString_LineEdit;
    QPushButton* Find_PushButton;
    QPushButton* Close_PushButton;
    QCheckBox* MatchCase_CheckBox;
    QCheckBox* GoBack_CheckBox;
  public:
    FindDialog(QWidget* parents = 0);
  protected:
    void closeEvent(QCloseEvent* event);  //註釋2
  public slots:
    void Find_PushButtonIsEnable(const QString& str);
};


註釋1 :這裏新包含了一個頭文件,用於事件函數的參數,雖然這個參數沒什麼用
註釋2 :關閉事件函數,注意這是一個protected函數,這個函數原先作用是關閉自身,而這裏我們需要他不是
              關閉自身窗體,而是隱藏窗體
            在FindDialog.cxx文件改動就是要實現這個保護函數(事件),代碼很簡單
void FindDialog::closeEvent(QCloseEvent* event)
{
  hide();
}


           這個函數的功能從原先的關閉窗體變成了隱藏窗體
           然後要做的就是把這個改好的FindDialog對話框安裝到ReadMe上,在ReadMe.h頭文件中包含這個類,另外由於需要信號與槽的鏈接,出於模塊化的設計目的,我們在ReadMe.h頭文件中再添加一個私有函數,用於信號與槽的鏈接,這樣ReadMe.h文件將添加下面的代碼
#include"FindDialog.h"
//.
//.
void ConnectSignalAndSlot();


          在ReadMe.cxx中首先需要需要實現這個新添加的私有函數
void ReadMe::ConnectSignalAndSlot()
{
  connect(Find_Action,SIGNAL(triggered()),FindWordsDialog,SLOT(show()));
}


           這裏將動作"查詢"和對話框的show()連接起來,QAction被點擊後會發出triggered()信號,最後需要改動的是構造函數,這裏我貼出改動後的構造函數的完成代碼
ReadMe::ReadMe(QWidget* parent):QMainWindow(parent)
{
  CreateAction();
  CreateMenu();
  CreateMenuBar();
  MainEditWindow = new QTextEdit;
  setCentralWidget(MainEditWindow);
  FindWordsDialog = new FindDialog(this);  //註釋1
  setWindowTitle(tr("記事本"));
  ConnectSignalAndSlot();  //註釋2
}


註釋1 : FindDialog的構造函數的參數是QWidget* parent = 0;具有默認參數,如果他是頂層窗體,就沒有父窗
               體,參數爲0,如果就就使用父窗體的指針作爲參數,這裏FindDialog的父窗體是this
註釋2 :注意這個用於鏈接信號和槽的函數的調用順序,必需等所有對象都創建後才能進行連接,連接到一個未
              創建的對象的話,在程序運行是會出現段錯誤

           最後把修改後的文件進行重新編譯,如果你是在使用GCC編譯器的話會出現類似這樣的錯誤信息
           FindDialog.o:在函數‘FindDialog::FindDialog(QWidget*)’中:
           FindDialog.cxx:(.text+0x19):對‘vtable for FindDialog’未定義的引用
           FindDialog.cxx:(.text+0x20):對‘FindDialog::staticMetaObject’未定義的引用
           collect2: error: ld returned 1 exit status
           如果你使用的是VS系列編譯器也會出現類似的情況

         之所以會出現這個問題是因爲在上一章的ReadMe程序中只是單純的界面製作,而沒用涉及他的功能,更確切的說是沒有用到信號與槽,而在這章的例子添加了信號與槽,在私有函數ConnectSignalAndSlot()中,而一旦莫個類需要使用信號與槽,就必須在頭文件中添加Q_OBJECT這個宏,添加這個宏後,再使用make -project重新生產MakeFile,再編譯的時候就不會出現上面的情況了
發佈了92 篇原創文章 · 獲贊 19 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章