您的位置:首页 > 产品设计 > UI/UE

在Qt中如何使用QtDesigner创建的UI文件

2017-06-11 16:30 375 查看
使用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)。

[cpp] view
plain copy

#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

[cpp] view
plain copy

#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

[cpp] view
plain copy

#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;
因此,相应的头文件中只要前置声明即可:

[cpp] view
plain copy

namespace Ui   

{   

    class GoToCellDialog;   

} // 前置声明即可,只在实现文件中包含相应的头文件   

  

class GoToCellDialog: public QDialog  

{   

      // 同上   

 private:   

       Ui::GoToCellDialog *ui;   

};  

实现文件:

[cpp] view
plain copy

#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类多重派生。看代码就清楚了:
头文件:

[cpp] view
plain copy

#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  

实现文件:

[cpp] view
plain copy

#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:
 

[cpp] view
plain copy

void CalculatorForm::changeEvent(QEvent *e)  

{  

    QWidget::changeEvent(e);  

    switch (e->type()) {  

    case QEvent::LanguageChange:  

        ui->retranslateUi(this);  

        break;  

    default:  

        break;  

   }  

}  

    除了在编译时处理ui文件外,Qt还提供了在运行时动态加载ui文件的机制。通过QtUiTools模块的QUiLoader可以在运行时加载ui文件。
    加载ui文件的方式如以下代码所示:

[cpp] view
plain copy

QWidget* TextFinder::loadUiFile()  

{  

    QUiLoader loader;  

  

    QFile file(":/forms/textfinder.ui"); //  文件名可以是绝对路径或相对于应用程序的相对路径  

    file.open(QFile::ReadOnly);  

  

    QWidget *formWidget = loader.load(&file, this);  

    file.close();  

  

    return formWidget;  

}  

   使用方式:

 

[cpp] view
plain copy

ui_lineEdit = qFindChild<QLineEdit*>(formWidget, "lineEdit"); //  需要指定对象的名字QUiLoader类放在一个独立的库中。  

   为了在应用程序中使用QUiLoader,必须在工程文件 .pro 中加入一行内容:
                     CONFIG += uitools

    在实际项目中,动态加载ui文件的需求似乎不怎么强烈,我所经历的项目就还从来没有使用过这种方式。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: