使用Qt有一些時間了,一直在IDE環境(qtcreator和VS2003+集成器)中使用,自然少了很多麻煩的步驟。但是在享受這種便利的同時,我們也失去了理解更多知識背后的點滴。在IDE中,如果我們要開發一個對話框,通常是使用 “新建—>Qt—>Qt設計師界面類” 這樣IDE會自動的幫我們生成三個文件(filename.ui, filename.h,filename.cpp)。qmake也非常智能,可以自動檢測到這個用戶界面文件(filename.ui)並且生產適當的makefile規則。這樣在編譯之前,IDE會自動調用uic(Qt自帶的用戶界面編譯器,User Interface Compiler)將界面文件(filename.ui)轉換成C++代碼並保存在ui_filename.h文件中。並且在另外兩個C++源文件(filename.h和filename.cpp)中使用了組合(即委托或代理)的方式使用了ui_filename.h里的類(該類通常定義在命名空間Ui下)。
如果你不主動的留心這些細節,你可能永遠都不明白這些,即使使用了多年的Qt,我就是這樣。一次,項目組的需求人員嫌棄我們開發人員做的界面布局不夠恰當,美觀。於是有了自己來開發界面的想法。很好!開發人員很快手把手的教會了需求人員用Qt Designer設計窗體界面,然而,等到需求人員把 pureui_filename.ui文件扔給我們開發人員使用時,我們頓時傻了眼,怎么用?於是使用了一個最愚蠢當然也是最簡單的辦法: 還是和之前一樣,通過IDE“新建—>Qt—>Qt設計師界面類”生成與“pureui_filename.”同名的文件,然后用需求人員給的pureui_filename.ui替換IDE自動生成的 *.ui 文件。雖然轉了一個小彎,但目的達到!
后來想想,總覺得多少有些遺憾,於是查閱了Qt文檔之Using a Designer UI File in Your Application
在這個文檔中,詳細說明了在應用程序中使用UI文件的方法。
一、直接的方法(The Direct Approach)
即把filename.ui經過uic轉換后的C++代碼文件ui_filename.h直接包含,使用其里面Ui命名空間下的類(名稱和主窗體的objectname相同,這里假設為GoToCellDialog)。
- #include "ui_gotocelldialog.h" // uic工具將gotocelldialog.ui生成的C++代碼
- int main(int argc, char *argv[])
- {
- QApplication app(argc, argv);
- QDialog *dialog= new QDialog; // 用於顯示界面的父窗體QDialog(QWidget的子類)
- Ui::GotoCellDialog ui; // 界面類,必須顯示在一個QWidget(或其子類)上
- ui.setupUi(dialog); // 將QDialog設置為 GotoCellDialog 的父窗體,這樣GotoCellDialog 里面定義的控件就會顯示在QDialog窗體內
- dialog->show();
- return app.exec();
- }
#include "ui_gotocelldialog.h" // uic工具將gotocelldialog.ui生成的C++代碼
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QDialog *dialog= new QDialog; // 用於顯示界面的父窗體QDialog(QWidget的子類)
Ui::GotoCellDialog ui; // 界面類,必須顯示在一個QWidget(或其子類)上
ui.setupUi(dialog); // 將QDialog設置為 GotoCellDialog 的父窗體,這樣GotoCellDialog 里面定義的控件就會顯示在QDialog窗體內
dialog->show();
return app.exec();
}
二、單繼承方式(The Single Inheritance Approach)
單繼承方式是相對於后面要講的多繼承方式,單繼承方式也稱組合(即委托或代理)方式。單繼承方式簡單來說就是在代碼中首先要自定義一個子類(例如下文中的GoToCellDialog類),該類要從form對應的窗體類(或其兼容的子類)派生;並用ui生成的類定義一個類里的成員變量,該成員變量可以是值也可以是指針,根據使用成員變量的形式不同,又分為成員變量和指針成員變量兩種形式。這樣在GoToCellDialog的構造函數中可以直接調用ui和ui中的變量和函數,使用起來很方便。
1、使用成員變量
即將 Ui::GotoCellDialog ui; 作為類GotoCellDialog(只繼承自QDialog,單一繼承)的成員變量。這里有一點值得注意的地方,就是ui文件提供的類被包含在了名為Ui的name space里,這樣做的目的是將ui文件的命名空間與用戶的代碼分離,避免兩者出現命名沖突的情況。
頭文件: gotocelldialog.h
- #include <QDialog>
- #include "ui_gotocelldialog.h" // 因為是成員變量形式,必須包含相應的頭文件
- class GoToCellDialog: public QDialog
- {
- Q_OBJECT
- public:
- explicit GoToCellDialog(QDialog *parent = 0);
- private slots:
- void on_lineEdit_textChanged();
- private:
- Ui::GoToCellDialog ui;
- };
#include <QDialog>
#include "ui_gotocelldialog.h" // 因為是成員變量形式,必須包含相應的頭文件
class GoToCellDialog: public QDialog
{
Q_OBJECT
public:
explicit GoToCellDialog(QDialog *parent = 0);
private slots:
void on_lineEdit_textChanged();
private:
Ui::GoToCellDialog ui;
};
實現文件: gotocelldialog.cpp
- #include "gotocelldialog.h"
- #include <QtGui>
- GoToCellDialog::GoToCellDialog(QWidget *parent)
- : QDialog(parent)
- {
- ui.setupUi(this);
- QRegExp regExp("[A-Za-z][1-9][0-9]{0,2}");
- lineEdit->setValidator(new QRegExpValidator(regExp, this));
- connect(okButton, SIGNAL(clicked()), SLOT(accept()));
- connect(cancelButton, SIGNAL(clicked()), SLOT(reject()));
- }
- void GoToCellDialog::on_lineEdit_textChanged()
- {
- // bool hasAcceptableInput () const
- // This property holds whether the input satisfies the inputMask and the validator.
- // By default, this property is true.
- okButton->setEnabled(lineEdit->hasAcceptableInput());
- }
#include "gotocelldialog.h"
#include <QtGui>
GoToCellDialog::GoToCellDialog(QWidget *parent)
: QDialog(parent)
{
ui.setupUi(this);
QRegExp regExp("[A-Za-z][1-9][0-9]{0,2}");
lineEdit->setValidator(new QRegExpValidator(regExp, this));
connect(okButton, SIGNAL(clicked()), SLOT(accept()));
connect(cancelButton, SIGNAL(clicked()), SLOT(reject()));
}
void GoToCellDialog::on_lineEdit_textChanged()
{
// bool hasAcceptableInput () const
// This property holds whether the input satisfies the inputMask and the validator.
// By default, this property is true.
okButton->setEnabled(lineEdit->hasAcceptableInput());
}
2、使用指針成員變量 與成員變量形式相似,唯一不同的是,將Ui::GoToCellDialog聲明為指針成員,即 Ui::GoToCellDialog *ui;
因此,相應的頭文件中只要前置聲明即可:
- namespace Ui
- {
- class GoToCellDialog;
- } // 前置聲明即可,只在實現文件中包含相應的頭文件
- class GoToCellDialog: public QDialog
- {
- // 同上
- private:
- Ui::GoToCellDialog *ui;
- };
namespace Ui
{
class GoToCellDialog;
} // 前置聲明即可,只在實現文件中包含相應的頭文件
class GoToCellDialog: public QDialog
{
// 同上
private:
Ui::GoToCellDialog *ui;
};
實現文件:
- #include "ui_gotocelldialog.h"
- GoToCellDialog::GoToCellDialog(QDialog *parent) :
- QDialog(parent), ui(new Ui::GoToCellDialog)
- {
- ui->setupUi(this);
- }
- CalculatorForm::~CalculatorForm()
- {
- delete ui; // 切記刪除,釋放資源
- }
#include "ui_gotocelldialog.h"
GoToCellDialog::GoToCellDialog(QDialog *parent) :
QDialog(parent), ui(new Ui::GoToCellDialog)
{
ui->setupUi(this);
}
CalculatorForm::~CalculatorForm()
{
delete ui; // 切記刪除,釋放資源
}
三、多繼承方式(The Multiple Inheritance Approach) 多繼承方式就是自定義的類從窗體類和Ui類多重派生。看代碼就清楚了:
頭文件:
- #ifndef GOTOCELLDIALOG_H
- #define GOTOCELLDIALOG_H
- #include <QDialog>
- #include "ui_gotocelldialog.h"
- class GoToCellDialog : public QDialog, public Ui::GoToCellDialog
- {
- Q_OBJECT
- public:
- explicit GoToCellDialog(QWidget *parent = 0);
- private slots:
- void on_lineEdit_textChanged();
- };
- #endif // GOTOCELLDIALOG_H
#ifndef GOTOCELLDIALOG_H
#define GOTOCELLDIALOG_H
#include <QDialog>
#include "ui_gotocelldialog.h"
class GoToCellDialog : public QDialog, public Ui::GoToCellDialog
{
Q_OBJECT
public:
explicit GoToCellDialog(QWidget *parent = 0);
private slots:
void on_lineEdit_textChanged();
};
#endif // GOTOCELLDIALOG_H
實現文件:
- #include "gotocelldialog.h"
- #include <QtGui>
- GoToCellDialog::GoToCellDialog(QWidget *parent)
- : QDialog(parent)
- {
- this->setupUi(this); //第1個this指Ui::GoToCellDialog,第2個this指(QDialog) 即 Ui::GoToCellDialog->setupUi(QDialog)
- QRegExp regExp("[A-Za-z][1-9][0-9]{0,2}");
- lineEdit->setValidator(new QRegExpValidator(regExp, this));
- connect(okButton, SIGNAL(clicked()), SLOT(accept()));
- connect(cancelButton, SIGNAL(clicked()), SLOT(reject()));
- }
- void GoToCellDialog::on_lineEdit_textChanged()
- {
- // bool hasAcceptableInput () const
- // This property holds whether the input satisfies the inputMask and the validator.
- // By default, this property is true.
- okButton->setEnabled(lineEdit->hasAcceptableInput());
- }
#include "gotocelldialog.h"
#include <QtGui>
GoToCellDialog::GoToCellDialog(QWidget *parent)
: QDialog(parent)
{
this->setupUi(this); //第1個this指Ui::GoToCellDialog,第2個this指(QDialog) 即 Ui::GoToCellDialog->setupUi(QDialog)
QRegExp regExp("[A-Za-z][1-9][0-9]{0,2}");
lineEdit->setValidator(new QRegExpValidator(regExp, this));
connect(okButton, SIGNAL(clicked()), SLOT(accept()));
connect(cancelButton, SIGNAL(clicked()), SLOT(reject()));
}
void GoToCellDialog::on_lineEdit_textChanged()
{
// bool hasAcceptableInput () const
// This property holds whether the input satisfies the inputMask and the validator.
// By default, this property is true.
okButton->setEnabled(lineEdit->hasAcceptableInput());
}
PS:關於UI界面中的國際化
如果用戶界面語言發送了改變,Qt通過發送 QEvent::LanguageChange 事件通知應用程序。為了調用 retranslateUi() 函數以達到切換語言的目的,我們需要重新實現界面類里面的QWidget::changeEvent() 事件處理函數。
Reacting to Language Changes
Qt notifies applications if the user interface language changes by sending an event of the type QEvent::LanguageChange. To call the member function retranslateUi() of the user interface object, we reimplement QWidget::changeEvent() in the form class, as follows:
- void CalculatorForm::changeEvent(QEvent *e)
- {
- QWidget::changeEvent(e);
- switch (e->type()) {
- case QEvent::LanguageChange:
- ui->retranslateUi(this);
- break;
- default:
- break;
- }
- }
- http://blog.csdn.net/e5max/article/details/9869977

