精通Qt4编程
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

3.2 程序中引入自定义窗口部件

保存好Qt设计器绘制的GUI界面文件后,就可以将findfileform.ui加入到qmake工程文件中,并可以在应用程序中使用该GUI用户界面。Qt提供了3种方法在应用程序中使用Qt设计器绘制的界面类:

● 直接使用方式;

● 单一继承方式;

● 多继承方式。

下面一一进行详细阐述。

3.2.1 直接使用方式

首先,在“chapter03/findfile”目录下新建名字为“direct”的KDevelop工程。然后将ui文件加入到qmake工程中。步骤如下:

在KDevelop中,选择右侧的“QMake管理器”选项卡,在下面的窗口中右键单击“FORMS”选项,在弹出的上下文菜单中选择“添加已有的文件...”命令,如图3-21所示。

图3-21 在KDevelop中为工程添加界面表单

在打开的对话框中,选中需要添加的文件“findfileform.ui”。在最下面的下拉框中,有三个选项:

● 复制文件——复制ui文件到qmake工程文件src.pro所在的目录,并将复制的ui文件添加到qmake工程文件中;

添加符号连接——在qmake的工程文件src.pro所在的目录建立一个链接,指向需要添加的ui文件,并将链接添加到qmake工程文件中;

● 添加相对路径——以相对路径的形式添加到qmake工程文件src.pro中。

在此,选择“添加相对路径”选项,单击“确定”按钮,如图3-22所示。

这时候,findfileform.ui文件便添加到KDevelop工程当中,如图3-23所示。

图3-22 指定界面表单

图3-23 QMake工程选项

相应地,KDevelop会修改当前KDevelop工程的src目录下的qmake工程文件src.pro,其内容为:

        # File generated by kdevelop's qmake manager.
        # -------------------------------------------
        # Subdir relative project main directory: ./src
        # Target is ????? ../bin/direct

        FORMS += ../../findfileform.ui
        SOURCES += direct.cpp
        TARGET=../bin/direct

文件中以“#”开头的是KDevelop自动添加的一些注释和说明。这些说明指出了该qmake工程文件的创建者等信息。

变量FORMS告诉qmake编译工具添加了一个findfileform.ui文件,位置在chapter03/findfile目录下(注意,qmake工程文件src.pro在目录chapter03 /findfile/direct/src下)。

此外,也可以手动修改qmake工程文件src.pro,将findfileform.ui加入到工程中。

现在进一步修改qmake工程文件src.pro,将资源文件引入到工程文件中。最终src.pro的内容如下。

        FORMS += ../../findfileform.ui
        SOURCES += direct.cpp
        TARGET=../bin/direct
        RESOURCES   += ../../findfile.qrc

修改主程序文件direct.cpp,其内容如下。

        // chapter03/findfile/direct/src/direct.cpp.
        #include <QtGui>

        #include <QtCore/QTextCodec>

        #include "ui_findfileform.h"
        int main(int argc, char *argv[])
        {
            QApplication app(argc, argv);
            QTextCodec::setCodecForTr(QTextCodec::codecForName("gb2312"));
            Q_INIT_RESOURCE(findfile);
            QWidget *pWidget = new QWidget;
            Ui::FindFileForm ui;
            ui.setupUi(pWidget);
            pWidget->show();

            return app.exec();
        }

main函数中创建了一个Qt标准的QWidget对象pWidget,pWidget对象用来加载(host)findfileform.ui文件描述的GUI窗口部件。

Ui::FindFileForm类来自ui_findfileform.h文件,该类定义了Qt设计器中绘制的所有窗口部件以及关联的信号和槽。通过调用它的setupUi()函数,初始化、部署窗口部件,并设置窗体的大小和标题等。

现在编译运行应用程序。不过由于没有实现查找功能,用户是无法与界面进行交互的。

这种在程序中使用Qt设计器的*.ui文件的方式,直接简单,实现快。然而,在较大型的项目中,仅仅使用Qt设计器绘制用户界面是不够的,还需要通过应用程序的代码操作控制生成的窗口部件,达到与用户交互的目的。这就需要使用下面两种方式在应用程序中引入Qt设计器的ui文件。

3.2.2 单一继承方式

在直接使用方式中,主程序创建了一个QWidget对象,并使用Ui_FindFileForm界面对象的setupUi()函数进行初始化和加载窗口部件。而在单一继承方式中,需要声明一个继承自QWidget的自定义类,并在这个类的构造函数中初始化和加载GUI用户界面,如图3-24所示。

图3-24 单一继承方式使用Ui类

在chapter03/findfile目录下,新建KDevelop工程“singleinherit”,并新建两个文件findfileform.h和findfileform.cpp,加入到工程中。

自定义类CFindFileForm的头文件findfileform.h代码清单如下。

        // chapter03/findfile/singleinherit/src/findfileform.h.
        #ifndef _FINDFILEFORM_H_
        #define _FINDFILEFORM_H_

        #include "ui_findfileform.h"

        class CFindFileForm :   public QWidget
        {
            Q_OBJECT
        public:
            CFindFileForm(QWidget* = 0);

        private:
            Ui_FindFileForm ui;
        };
        #endif

在CFindFileForm类的定义文件中,定义了一个私有成员变量ui,它的类型是Ui_FindFileForm。前面已经讲过,类Ui_FindFileForm是由uic工具根据findfileform.ui文件创建的,它的功能是在构造函数中初始化、加载和管理GUI用户界面。

自定义类CFindFileForm的实现文件findfileform.cpp的内容如下所示。

        // chapter03/findfile/singleinherit/src/findfileform.cpp.
        #include <QtGui>
        #include "findfileform.h"

        CFindFileForm::CFindFileForm(QWidget* parent)
        :  QWidget(parent)
        {
            ui.setupUi(this);
            ui.statusLabel->setText(tr("就绪"));
            ui.resultLabel->setText(tr("找到0个文件"));
            ui.nameComboBox->setEditText("*");
            ui.dirComboBox->setEditText(QDir::currentPath());
            ui.dirComboBox->addItem(QDir::currentPath());
            ui.sensitiveCheckBox->setEnabled(false);
            ui.stopPushBtn->setEnabled(false);
        }

在类CFindFileForm的构造函数中调用了它的成员变量ui的setupUi()函数,对Qt设计器绘制的GUI用户界面进行初始化和加载。

然后,程序对用户界面中的一些窗口部件的状态进行了初始化。QComboBox::setEditText()设置下拉列表框的显示文本,该文本对用户是可编辑的。静态函数QDir::currentPath()返回应用程序所在目录的绝对路径。

QCheckBox::setEnabled(false) 设置“区分大小写”复选框的初始状态为不可用的(显示为灰色)。

QPushButton::setEnabled(false)设置“停止查找”按钮为不可用的。

现在,在主函数main()中实例化和显示Qt设计器绘制的GUI用户界面。singleinherit.cpp文件的内容如下。

        // chapter03/findfile/singleinherit/src/singleinherit.cpp.
        #include <QtGui/QApplication>
        #include <QtCore/QTextCodec>
        #include "findfileform.h"

        int main(int argc, char* argv[])
        {
            QApplication app(argc, argv);
            QTextCodec::setCodecForTr(QTextCodec::codecForName("gb2312"));
            Q_INIT_RESOURCE(findfile);
            CFindFileForm form;
            form.show();

            return app.exec();
        }

主程序很简单,首先声明了一个CFindFileForm对象form,然后调用该对象的公共函数show()进行显示。

为了简便起见,此处没有实现真正的查找文件功能,只是显示界面,而没有响应。单一继承方式使用Qt设计器绘制的用户界面是能够实现与用户进行交互的,它和下一节讲到的“多继承方式”基本相同。不同的是,单一继承方式需要通过成员ui来引用Qt设计器中部署的窗口部件,而在多继承方式中可以直接引用这些窗口部件。在下一小节中,将定义信号和槽,实现文件的查找功能。

将findfileform.ui文件和资源文件findfile.qrc加入到qmake工程文件src.pro中,src.pro文件的内容如下:

        FORMS += ../../findfileform.ui
        HEADERS += findfileform.h
        SOURCES += singleinherit.cpp \
            findfileform.cpp
        TARGET=../bin/singleinherit
        RESOURCES +=../../findfile.qrc

编译运行应用程序。

单一继承方式将Qt设计器绘制的GUI用户界面对象包含在自定义类中,作为一个私有成员来使用。这种方式的优点是,应用程序能够控制用户界面的外观和显示方式,并能够与用户进行交互;此外,还可以使用同样的一个ui文件来生成多个不同的自定义界面类,可以重复使用Qt设计器绘制的GUI用户界面。

3.2.3 多继承方式

多继承方式中,需要从标准的QWidget类和Qt设计器绘制的界面类继承。这样,继承自Qt标准的窗口部件类和界面类的子类就可以直接访问其父类的公有成员和保护成员,如图3-25所示。

图3-25 多继承关系

在chapter03 /findfile目录下,新建KDevelop工程“mulinherit”。新建两个文件findfileform.h和findfileform.cpp,并加入到工程中。

多继承方式中,自定义类CFindFileform的定义如下。

        // chapter03/findfile/mulinherit/src/findfileform.h.
        #ifndef _FINDFILEFORM_H_
        #define _FINDFILEFORM_H_

        #include <QStringList>
        #include <QDir>

        #include "ui_findfileform.h"

        class CFindFileForm :   public QWidget,
                                public Ui_FindFileForm
        {
            Q_OBJECT
        public:
            CFindFileForm(QWidget* = 0);
        };

        #endif

类CFindFileForm以公有方式继承自QWidget和Ui_FindFileForm。

注意,多继承的情况下,Qt的类必须要放在其他类的前面,即必须先继承QWidget,再继承Ui_FindFileForm。这是因为元对象编译器(Meta-Object Compiler, moc)假定第一个继承的类是QObject的子类。此外,Qt不支持对QOjbect(或QObejct子类)的虚继承(virtual inheritance)。

类CFindFileFrom的实现文件findfileform.cpp内容如下。

        // chapter03/findfile/mulinherit/src/findfileform.cpp
        #include <QtGui>

        #include "findfileform.h"
        CFindFileForm::CFindFileForm(QWidget* parent)
        :  QWidget(parent)
        {
            setupUi(this);
            statusLabel->setText(tr("就绪"));
            resultLabel->setText(tr("找到0个文件"));
            nameComboBox->setEditText("*");
            dirComboBox->setEditText(QDir::currentPath());
            dirComboBox->addItem(QDir::currentPath());
            sensitiveCheckBox->setEnabled(false);
            stopPushBtn->setEnabled(false);
        }

在类CFindFileForm的构造函数中,直接调用了父类Ui_FindFileForm的函数setupUi(),来进行界面窗口部件的初始化、加载和部署。

接着,程序初始化了各子窗口部件的初始状态。与单一继承方式使用ui文件不同的是,多继承方式下可以在类的实现代码中直接引用Qt设计器绘制的子窗口部件。

将findfileform.ui文件和资源文件findfile.qrc加入到QMake工程文件src.pro中,src.pro文件的内容如下。

        FORMS += ../../findfileform.ui
        HEADERS += findfileform.h
        SOURCES += mulinherit.cpp \
                findfileform.cpp
        TARGET=../bin/mulinherit
        RESOURCES +=../../findfile.qrc

编译并运行应用程序。

在应用程序中,多继承方式使用Qt设计器中绘制的界面窗口部件比单一继承方式更简单直接;同直接使用方式相比较,多继承方式更具代码的可扩展性。因此,在应用程序中,一般的都使用多继承方式引用Qt设计器绘制的用户界面对象。在下一节中,讲述Qt的信号和槽的时候,就是通过多继承方式来实现查找文件功能的。