计算器示例演示了怎样使用QUiLoader类在Qt设计器师中动态创建用户界面。(使不重新编译应用程序而可以改变窗体布局的做法成为可能)
我们使用CalculatorForm里创建的ui文件来演示当程序运行时动态加载用户界面。
准备工作:
Calculator Form示例中我们定义的用户界面我们可以不用做任何改动,在这个示例中我们把上个示例中生成的calculatorform.ui文件保存到工程的资源文件里,当然也可以直接保存在磁盘上。
为了实现运行时加载,我们需要添加uitools库,如下工程文件包含了我们所需的所有内容:
CONFIG += uitools
HEADERS = calculatorform.h
RESOURCES = calculatorbuilder.qrc
SOURCES = calculatorform.cpp \
main.cpp
CalculatorForm类的定义:
CalculatorForm class定义为一个容纳用户界面的窗口部件。
class CalculatorForm : public QWidget
{
Q_OBJECT
public:
CalculatorForm(QWidget *parent = 0);
private slots:
void on_inputSpinBox1_valueChanged(int value);
void on_inputSpinBox2_valueChanged(int value);
private:
QSpinBox *ui_inputSpinBox1;
QSpinBox *ui_inputSpinBox2;
QLabel *ui_outputWidget;
};
需要注意的的是我们并不需要包含用描述户界面的头文件。我们只需要定义两个公共槽,使用uic自动连接时使用的名字,声明用来和用户界面上的控件建立关联的私有变量。
CalculatorForm类的定义:
我们需要使用QUiLoader类,它由libQtUiTools库提供,所以需要包含这个库的头文件:
#include <QtUiTools>
构造函数里声明一个loader对象,它通过QFile对象读取资源文件,创建了我们要恢复的用户界面。
CalculatorForm::CalculatorForm(QWidget *parent)
: QWidget(parent)
{
QUiLoader loader;
QFile file(":/forms/calculatorform.ui");
file.open(QFile::ReadOnly);
QWidget *formWidget = loader.load(&file, this);
file.close();
通过把用户界面保存在资源文件里,我们保证在示例运行时能找到它,loader.load()函数引导文件中的用户界面,并让它成为 CalculatorForm类的一个子类。
我们需要使用用户界面中的三个控件,两个选值框和一个标签,方便起见,我们定义了指向这个控件的指针,便于以后使用。qFindChild()模板函数返回与给定名字和类型相匹配的子对象。
ui_inputSpinBox1 = findChild<QSpinBox*>("inputSpinBox1");
ui_inputSpinBox2 = findChild<QSpinBox*>("inputSpinBox2");
ui_outputWidget = findChild<QLabel*>("outputWidget");
(findChild前应该改为formWidget->findChild,不加的话应该是默认的this->,因为formWidget是CalculatorForm的孩子,findChild会遍历formWidget及其孩子,最终会去找formWidget)
动态加载的窗口部件需要连接 CalculatorForm中特定的槽,我们使用Qt的meta-object系统建立连接:
QMetaObject::connectSlotsByName(this);
窗口部件被加入布局管理器,并设置窗口的标题:
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(formWidget);
setLayout(layout);
setWindowTitle(tr("Calculator Builder"));
}
两个槽向在示例 Calculator Form 中那样定义,不同的是我们使用构造函数中定义的指向他们的指针来获得相应的数值。
void CalculatorForm::on_inputSpinBox1_valueChanged(int value)
{
ui_outputWidget->setText(QString::number(value + ui_inputSpinBox2->value()));
}
void CalculatorForm::on_inputSpinBox2_valueChanged(int value)
{
ui_outputWidget->setText(QString::number(value + ui_inputSpinBox1->value()));
}
这种方法的好处是我们可以在程序运行时更换用户界面,但我们仍可以控制所有控件,只要他们具有恰当的名字。
我们使用CalculatorForm里创建的ui文件来演示当程序运行时动态加载用户界面。
准备工作:
Calculator Form示例中我们定义的用户界面我们可以不用做任何改动,在这个示例中我们把上个示例中生成的calculatorform.ui文件保存到工程的资源文件里,当然也可以直接保存在磁盘上。
为了实现运行时加载,我们需要添加uitools库,如下工程文件包含了我们所需的所有内容:
CONFIG += uitools
HEADERS = calculatorform.h
RESOURCES = calculatorbuilder.qrc
SOURCES = calculatorform.cpp \
main.cpp
CalculatorForm类的定义:
CalculatorForm class定义为一个容纳用户界面的窗口部件。
class CalculatorForm : public QWidget
{
Q_OBJECT
public:
CalculatorForm(QWidget *parent = 0);
private slots:
void on_inputSpinBox1_valueChanged(int value);
void on_inputSpinBox2_valueChanged(int value);
private:
QSpinBox *ui_inputSpinBox1;
QSpinBox *ui_inputSpinBox2;
QLabel *ui_outputWidget;
};
需要注意的的是我们并不需要包含用描述户界面的头文件。我们只需要定义两个公共槽,使用uic自动连接时使用的名字,声明用来和用户界面上的控件建立关联的私有变量。
CalculatorForm类的定义:
我们需要使用QUiLoader类,它由libQtUiTools库提供,所以需要包含这个库的头文件:
#include <QtUiTools>
构造函数里声明一个loader对象,它通过QFile对象读取资源文件,创建了我们要恢复的用户界面。
CalculatorForm::CalculatorForm(QWidget *parent)
: QWidget(parent)
{
QUiLoader loader;
QFile file(":/forms/calculatorform.ui");
file.open(QFile::ReadOnly);
QWidget *formWidget = loader.load(&file, this);
file.close();
通过把用户界面保存在资源文件里,我们保证在示例运行时能找到它,loader.load()函数引导文件中的用户界面,并让它成为 CalculatorForm类的一个子类。
我们需要使用用户界面中的三个控件,两个选值框和一个标签,方便起见,我们定义了指向这个控件的指针,便于以后使用。qFindChild()模板函数返回与给定名字和类型相匹配的子对象。
ui_inputSpinBox1 = findChild<QSpinBox*>("inputSpinBox1");
ui_inputSpinBox2 = findChild<QSpinBox*>("inputSpinBox2");
ui_outputWidget = findChild<QLabel*>("outputWidget");
(findChild前应该改为formWidget->findChild,不加的话应该是默认的this->,因为formWidget是CalculatorForm的孩子,findChild会遍历formWidget及其孩子,最终会去找formWidget)
动态加载的窗口部件需要连接 CalculatorForm中特定的槽,我们使用Qt的meta-object系统建立连接:
QMetaObject::connectSlotsByName(this);
窗口部件被加入布局管理器,并设置窗口的标题:
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(formWidget);
setLayout(layout);
setWindowTitle(tr("Calculator Builder"));
}
两个槽向在示例 Calculator Form 中那样定义,不同的是我们使用构造函数中定义的指向他们的指针来获得相应的数值。
void CalculatorForm::on_inputSpinBox1_valueChanged(int value)
{
ui_outputWidget->setText(QString::number(value + ui_inputSpinBox2->value()));
}
void CalculatorForm::on_inputSpinBox2_valueChanged(int value)
{
ui_outputWidget->setText(QString::number(value + ui_inputSpinBox1->value()));
}
这种方法的好处是我们可以在程序运行时更换用户界面,但我们仍可以控制所有控件,只要他们具有恰当的名字。