天天看点

Part 02 对话框(Qt)[2012.01.20]

Part 02 对话框(Qt)

——2012.01.20

0. 本次学习Qt时主要方法:分析代码,从分析中学习语法,从分析中掌握Qt的程序设计思路。

1. 编写学习笔记主要形式:展示程序功能,从功能分析程序,总结程序设计思路,摘录(经修改)代码。

2. 主要参考学习书籍《零基础学Qt编程》(吴迪)和《C++ GUI Qt 4编程(第二版)》电子工业出版社。

3. 本Part内容:对话框,了解如何使用Qt设计模态、非模态和不同表现形态的对话框。

004 Program– ExtensionDlg

01.展示程序功能

Part 02 对话框(Qt)[2012.01.20]

          如图,本Dialog Box 可以输入名字,选择性别,还可以按下确定,按下Detail按钮(如下图)。

Part 02 对话框(Qt)[2012.01.20]

          按下“Detail”按钮后,在原Dialog Box的基础上扩展开来了,一般把这个按钮称为“toggle button”,可以让用户在对话框的简单外观和扩展外观之间来回切换。

02.从功能分析程序设计思路

          看见这程序,可以想到的问题有:

          第一,可以将这个窗口划分为多少个子窗口,

          第二,每个子窗口之间又是如何布局,

          第三,如何去完成Detail的功能。

          首先,我们可以使用一个类来完成这一整个功能,而这个类中,我们需要两个子窗口的数据成员。

          即,我们可以把这个窗口先划分为两个大的子窗口,根据点击”Detail”前后的窗口可以按下图来划分。

Part 02 对话框(Qt)[2012.01.20]

          这样划分以后,然后,我们就可以在编写类的时候,分别给这两个Widget创建一个初始化函数,而这个初始化函数需要完成的工作就是将每一个子窗口再写出来,我们再细入到每一个窗口中去,可以把这两个窗口按下图划分:

Part 02 对话框(Qt)[2012.01.20]

          待写好每一个Widget后,就可以开始给这些Widget布局了:

Part 02 对话框(Qt)[2012.01.20]

          按照这个先合并列,使其成为行,再将行合并,使其成为一个整体的思想去设计整个窗口的布局。

          最后,如果需要完成toggle button的功能,只需要加上一slots函数,让用户点击时触发这个函数即可。

03. 从功能总结程序设计思路

Part 02 对话框(Qt)[2012.01.20]

04.程序代码

# 表示程序类型是app
TEMPLATE = app
# 指定可执行文件或库的基本文件名,其中不包含任何的扩展、前缀或版本号,默认的就是当前的目录名
TARGET =
DEPENDPATH += .
# INCLUDEPATH 指定C++编译器搜索全局头文件的路径
INCLUDEPATH += .

# Input
# HEADERS 指定工程的C++头文件(.h)多个文件可用空格或回车隔开
HEADERS += \
    extensionDlg.h

# SOURCES 指定工程的C++实现文件(.cpp)多个文件可用空格或回车隔开
SOURCES += \
    main.cpp \
    extensionDlg.cpp




           
// main.cpp

#include <QApplication>
#include "extensionDlg.h"

int main(int argc, char * argv[])
{
    QApplication app(argc, argv);
    ExtensionDlg exDlg;
    exDlg.show();
    return app.exec();
}
           
// extensionDlg.h

#ifndef EXTENSIONDLG_H
#define EXTENSIONDLG_H

#include <QtGui>                    // 引入QtGui模块的头文件

class ExtensionDlg: public QDialog  // 声明自定义对话框类ExtensionDlg单公有继承自QDialog
{
    Q_OBJECT    // 加入Q_OBJECT宏,程序中用到诸如[信号/槽]等Qt核心机制的时候,都要加入这个宏

    public:
        ExtensionDlg();         // 构造函数
        void initBasicInfo();   // 初始化基础信息
        void initDetailInfo();  // 扩展信息

    public slots:               // 声明公有槽类
        void slot2Extension();  // 这个公有槽将在用户单击Detail按钮时触发

    private:
        QWidget * baseWidget;      // 伸缩前的对话框框体
        QWidget * detailWidget;    // 伸缩后的对话框框体
};

#endif // EXTENSIONDLG_H
           
// extensionDlg.cpp

#include "extensiondlg.h"

// 构造函数
ExtensionDlg::ExtensionDlg()
{
    setWindowTitle(tr("Extension Dialog")); // 设置应用程序的标题
    initBasicInfo();                        // 初始化基本信息窗体
    initDetailInfo();                       // 初始化扩展信息窗体

    // 设置窗体的布局
    QVBoxLayout * layout = new QVBoxLayout; // 定义一个垂直布局类实体layout
    layout -> addWidget(baseWidget);        // 将baseWidge加入布局中
    layout -> addWidget(detailWidget);
    layout -> setSizeConstraint(QLayout::SetFixedSize);
                                           // setSizeConstraint()设置窗体的缩放模式
                                           // QLayout::SetDefaultConstraint 设定为默认值
                                           // QLayout::SetFixedSize 固定的窗体大小,不可通过鼠标拖动改变
                                           // 如果这里不这样设置,用户再次单击Detail将无法恢复原来大小
    layout -> setSpacing(6);               // 设置位于布局之中的窗口部件之间的间隔大小

    setLayout(layout);                     // 将设置好的布局应用加载到窗体上
}

// 初始化基础信息
void ExtensionDlg::initBasicInfo()
{
    baseWidget = new QWidget;                        // 实例化私有数据成员 baseWidge
    QLabel * nameLabel = new QLabel(tr("Name"));     // 新建一个“name”的标签, 用QLabel
    QLineEdit * nameEdit = new QLineEdit;            // 新建的“name”的标签的后面加一行可输入行,用QLineEdit
    QLabel * sexLabel = new QLabel (tr("Sex"));      // 新建一个"sex“的标签,用QLabel
    QComboBox * sexComboBox = new QComboBox;         // 新建的"sex"后面加入一个下拉列表框,用QcomboBox
    sexComboBox -> addItem(tr("male"));              // 为下拉列表框中加入选项
    sexComboBox -> addItem(tr("female"));
    QPushButton * okButton = new QPushButton(tr("OK"));             // 新建按钮窗口部件,名字为"OK"
    QPushButton * detailButton = new QPushButton(tr("Detail"));     // 同上,名字为"Detail"
    connect(detailButton, SIGNAL(clicked()), this, SLOT(slot2Extension()));
                                    // 使用信号/槽机制连接detailButton的单击信号和this窗口类中的slot2Wxtension()函数

    // 下面三个语句,使用QDialogButtonBox创建一个符合当前窗口部件样式的一组按钮,并且它们被排列在某种布局之中。
    QDialogButtonBox * btnBox = new QDialogButtonBox(Qt::Horizontal);  // Qt::Horizontal 创建水平方向的按钮组合
    btnBox -> addButton(okButton, QDialogButtonBox::ActionRole);       // addButton将按钮加入到这个组合中
    btnBox -> addButton(detailButton, QDialogButtonBox::ActionRole);   // 并且ActionRole,创建的按钮有实际的功能

    // 设置窗口的布局。窗体的顶级布局是一个垂直布局,而其中嵌套了一个表单布局。
    QFormLayout * formLayout = new QFormLayout;     // 设置表单布局,使其可以整齐地分成两列的情况
    formLayout -> addRow(nameLabel, nameEdit);      // addRow加入行,行里面包含了哪些变量(窗口部件)
    formLayout -> addRow(sexLabel, sexComboBox);

    QVBoxLayout * vboxLayout = new QVBoxLayout;     // 创建窗体的顶级布局,并将其两个元素formLayout和btnBox都加入其中
    vboxLayout -> addLayout(formLayout);
    vboxLayout -> addWidget(btnBox);

    baseWidget -> setLayout(vboxLayout);            // 将设定好的布局都加载到窗体上

    return;
}

// 初始化扩展信息
void ExtensionDlg::initDetailInfo()
{
    detailWidget = new QWidget;                     // 实例化私有数据成员detailWidget

    // 定义“age"一栏的两个Widget
    QLabel * ageLabel = new QLabel(tr("Age"));
    QLineEdit * ageEdit = new QLineEdit;
    ageEdit -> setText(tr("25"));
    QLabel * deptLabel = new QLabel(tr("Department"));

    // 定义Department一栏的两个Widget
    QComboBox * deptComboBox = new QComboBox;
    deptComboBox -> addItem(tr("department 1"));
    deptComboBox -> addItem(tr("department 2"));
    deptComboBox -> addItem(tr("department 3"));
    deptComboBox -> addItem(tr("department 4"));

    // 定义address一栏的两个Widget
    QLabel * addressLabel = new QLabel(tr("address"));
    QLineEdit * addressEdit = new QLineEdit;

    // 定义表单布局,并且将三行内容分别添加进去
    QFormLayout * formLayout = new QFormLayout;
    formLayout -> addRow(ageLabel, ageEdit);
    formLayout -> addRow(deptLabel, deptComboBox);
    formLayout -> addRow(addressLabel, addressEdit);

    detailWidget -> setLayout(formLayout);
    detailWidget -> hide();

    return;
}


// 在用户单击Detail按钮时触发
void ExtensionDlg::slot2Extension()
{
    // 通过一个if语句,可以控制它显示和隐藏两个动作
    // 当时,也可以用 isShown()函数
    if(detailWidget -> isHidden())
    {
        detailWidget -> show();
    }
    else
    {
        detailWidget -> hide();
    }
    return;
}
           

005 Program – FindDialog

01. 展示程序功能

          如图,本FindDialog有六个子窗口,可以实现关键字查找,查找匹配,往后查找,关闭的功能。

Part 02 对话框(Qt)[2012.01.20]

          在未在Findwhat的EditLine输入字符时,”Find”Button不允许用户单击,输入字符后,情况则不同了。

Part 02 对话框(Qt)[2012.01.20]

          最后,这个对话框中,还有两个可选项,可以根据用户需求选择功能。

Part 02 对话框(Qt)[2012.01.20]

02. 从界面分析总结程序设计思路

          看见这程序,可以想到的问题有:

          第一,可以将这个窗口划分为多少个子窗口,

          第二,每个子窗口之间又是如何布局,

          第三,如何去完成LineEdit、2个CheckBox与FindButtonBox之间建立信号/槽机制。

          首先,这个程序与上一个程序的情况有点不同,因为它不需要实现切换的功能,不需要“ toggle Button”,所以,不用创建多个QWidget父类,来实现整个窗口的布局了,只需要创建QPushButton, QLabel, QCheckBox, QLineEdit这些子类就可以完成窗口布局了。如下图所示。

Part 02 对话框(Qt)[2012.01.20]

          然后,关于第三个问题,它们之间如何建立信号/槽机制。

Part 02 对话框(Qt)[2012.01.20]

03. 程序代码

#FindDialog.pro

HEADERS += \
    finddialog.h

SOURCES += \
    finddialog.cpp \
    main.cpp



           
// main.cpp

#include <QApplication>
#include "finddialog.h"

int main(int argc, char * argv[])
{
    QApplication app(argc, argv);
    finddialog * dialog = new finddialog;
    dialog -> show();
    return app.exec();
}
           
// finddialog.h

#ifndef FINDDIALOG_H
#define FINDDIALOG_H

#include <QDialog>      // 包含Qt对话框的基类

class QCheckBox;
class QLabel;
class QLineEdit;
class QPushButton;

class finddialog: public QDialog
{
        Q_OBJECT     // 对于所有定义了信号和槽的类,在类定义开始处的Q_OBJECT宏都是必需的

    public:
        finddialog(QWidget * parent = 0); // parent参数指定父窗口对象,空指针则指明该对话框无父对象

    signals:         // signals,用户消息事件,这关键字实际上也是一个宏,C++预处理器会在编译前转换成标准的C++代码。
        void findNext(const QString &str, Qt::CaseSensitivity cs);
        void findPrevious(const QString & str, Qt::CaseSensitivity cs);

    private slots:  // slots,槽,这关键字也是一个宏,C++预处理器会在编译前转换成标准的C++代码。
        void findClicked();
        void enableFindButton(const QString & test);

    private:        // 这里的私有数据成员,实际上就是按照对话框需要的Widget的顺序而定义的。
        QLabel * label;
        QLineEdit * lineEdit;
        QCheckBox * caseCheckBox;
        QCheckBox * backwardCheckBox;
        QPushButton * findButton;
        QPushButton * closeButton;
};

#endif // FINDDIALOG_H

/* C++知识补充:
 * 这里使用了类的前置声明。
 * 由于这些私有数据成员都是指针,也没有在头文件中就访问它们,所以编译程序就不需要这些类的完整定义。
 * 这也是这里没有包含与这几个类相关的头文件的原因。
 * 只是使用一些前置声明,这可以使编过程更加快些。
 **/
           
// finddialog.cpp

#include "finddialog.h"
#include <QtGui>    // 包含了QDialog, QCheckBox, QLabel, QLineEdit, QPushButton

// 构造函数
finddialog::finddialog(QWidget * parent):QDialog(parent)    // 把parent参数传递给基类的构造函数
{
// 设置Widget

    // 设置第一列第一行的两个Widget
    label = new QLabel(tr("Find &what:"));  // 在字符串中的“&”可以表示快捷键
    lineEdit = new QLineEdit;
    label -> setBuddy(lineEdit);    // 设置标签伙伴(buddy),接收焦点(focus)
                                    // 即,当按下label的快捷键后,焦点(focus)移动到LineEdit上.
    // 设置第一列第二行的两个Widget
    caseCheckBox = new QCheckBox(tr("Match & case"));
    backwardCheckBox = new QCheckBox(tr("Search &backward"));

    // 设置第二列的第一个 Widget--fidButton
    findButton = new QPushButton(tr("&Find"));
    findButton -> setDefault(true);         // 让findButton按钮成为默认按钮
    findButton -> setEnabled(false);        // 禁用Find按钮,使其不能与用户进行交互操作

    // 设置第二列的第二个 Widget -- closeButton
    closeButton = new QPushButton(tr("Close"));

 // 设置槽

    // 只要行编辑器中的文本发生变化,就会调用私有槽enableFindNutton(const QString&);
    connect(lineEdit, SIGNAL(textChanged(const QString &)),
            this, SLOT(enableFindButton(const QString &)));
    // 单击Find按钮时,能实现其功能,调用findClicked()函数
    connect(findButton, SIGNAL(clicked()), this, SLOT(findClicked()));
    // 单击closeButton时,可以调用QWidget的close()函数,将对话框关闭
    connect(closeButton, SIGNAL(clicked()), this, SLOT(close()));

// 设置布局

    // 设置最上面两个Widget为水平排列
    QHBoxLayout * topLeftLayout = new QHBoxLayout;
    topLeftLayout -> addWidget(label);
    topLeftLayout -> addWidget(lineEdit);

    // 设置左边的三行竖排列
    QVBoxLayout * leftLayout = new QVBoxLayout;
    leftLayout -> addLayout(topLeftLayout);
    leftLayout -> addWidget(caseCheckBox);
    leftLayout -> addWidget(backwardCheckBox);

    // 设置右边的两个按钮竖排列
    QVBoxLayout * rightLayout = new QVBoxLayout;
    rightLayout -> addWidget(findButton);
    rightLayout -> addWidget(closeButton);

    // 使整个窗口水平排列
    QHBoxLayout * mainLayout = new QHBoxLayout;
    mainLayout -> addLayout(leftLayout);
    mainLayout -> addLayout(rightLayout);

// 设置该 dialog box的主要参数
    setLayout(mainLayout);              // 设定布局
    setWindowTitle(tr("Find"));         // 设置标题
    setFixedHeight(sizeHint().height());// QWidget::sizeHint()返回一个窗口部件“理想”的尺寸大小
}

// 对话框中所用到的槽
void finddialog::findClicked()
{
    QString text = lineEdit -> text();
    Qt::CaseSensitivity cs = caseCheckBox -> isChecked() ? Qt::CaseSensitive
                                                         : Qt::CaseInsensitive;
    // backwardCheckBox功能启动时,则激发信号,向后找,否则,向前找
    if(backwardCheckBox -> isChecked())
    {
        emit findPrevious(text, cs);
    }
    else
    {
        emit findNext(text, cs);
    }
    return;
}

// 判断是否允许开始查找的功能
void finddialog::enableFindButton(const QString &text)
{
    findButton -> setEnabled(!text.isEmpty());
    return;
}
           

006 Program – GoToCellDialog(QtDesigner)

01. 展示程序功能

Part 02 对话框(Qt)[2012.01.20]

      该对话框的WindowTitle为Go to Cell, 对话框内有正常的确认取消按钮,有一个QLabel一个LineEdit,当在LineEdit输入时,仅能按照"[A-Za-z][1-9][0-9]{0,2}"这样的格式输入。

02. 使用Qt Desinger设计程序的一般思路

        第一步:使用Qt Designer创建.ui文件:(设置窗口部件及窗口布局)

                     ① 创建并初始化子窗口部件

                     ② 把子窗口部件放到布局中

                     ③ 设置Tab键顺序

                     ④ 建立信号-槽之间的连接

                     ⑤ 实现对话框中的自定义槽

        第二步:创建.h头文件。(通过简单地增加另一个间接层,解决直接使用.ui的大多数问题)

        第三步:创建.cpp源文件。(包括main, 类)

        第四步:创建.pro工程文件。

03. 程序编写过程

        第一步:使用Qt Designer创建.ui文件:(设置窗口部件及窗口布局)

               ① 创建并初始化子窗口部件

Part 02 对话框(Qt)[2012.01.20]

               -> 创建

Part 02 对话框(Qt)[2012.01.20]

                 -> 设置属性

Part 02 对话框(Qt)[2012.01.20]

 &&

Part 02 对话框(Qt)[2012.01.20]

                -> 设置属性,伙伴关系

Part 02 对话框(Qt)[2012.01.20]

                ② 把子窗口部件放到布局

                -> 弄好基本布局

Part 02 对话框(Qt)[2012.01.20]

                -> 这是令窗口能自动调整大小的前提

Part 02 对话框(Qt)[2012.01.20]

                -> 调整大小

Part 02 对话框(Qt)[2012.01.20]

                -> 布局完成

Part 02 对话框(Qt)[2012.01.20]

                ③ 设置Tab键顺序

                ④ 建立信号-槽之间的连接

                ⑤ 实现对话框中的自定义槽

第二步:创建.h头文件。(通过简单地增加另一个间接层,解决直接使用.ui的大多数问题)

// gotocelldialog.h

#ifndef GOTOCELLDIALOG_H
#define GOTOCELLDIALOG_H

#include <QDialog>
#include "ui_gotocelldialog.h"
// uic工具会将gotocelldialog.ui文件转换为C++并且将转换结果存放在ui_gotocelldialog.h文件中。

// 生成的ui_gotocelldialog.h文件中包含了类Ui::GoToCellDialog(用QtDesigner时定义的类名)的定义
class GoToCellDialog:public QDialog, public Ui::GoToCellDialog
{
        Q_OBJECT         // 程序中用到诸如信号/槽等Qt核心机制的时候,都要加入这个宏。
		
	public:
		GoToCellDialog(QWidget * parent = 0);

        private slots:   // 建立私有槽
		void on_lineEdit_textChanged();
};

#endif
           

第三步:创建.cpp源文件。(包括main, 类)

// gotocelldialog.cpp

#include <QtGui>
#include "gotocelldialog.h"

// 构造函数
GoToCellDialog::GoToCellDialog(QWidget * parent): QDialog(parent)
{
        setupUi(this);          // 用于初始化窗体
        QRegExp regExp("[A-Za-z][1-9][0-9]{0,2}"); // 检验器类,限制输入范围
	lineEdit -> setValidator(new QRegExpValidator(regExp, this));

        // 注意,这里的okButton变量和cancelButton变量是从gotocelldialog.ui那里设置的。
        connect(okButton, SIGNAL(clicked()), this, SLOT(accept()));     // 接受信号
        connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); // 取消信号
}

// 一个关于okButton的私有槽
void GoToCellDialog::on_lineEdit_textChanged()
{
    // 当lineEdit有输入数据时,okButton的按钮变为可操作的。
    // 注意,这里的okButton变量是从gotocelldialog.ui那里设置的。
    okButton -> setEnabled(lineEdit -> hasAcceptableInput());
}
           
// main.cpp
#include <QApplication>
#include <QDialog>

#include "gotocelldialog.h"

int main(int argc, char *argv[])
{
	QApplication app(argc, argv);
	GoToCellDialog * dialog = new GoToCellDialog;
	dialog -> show();

	return app.exec();
}
           

第四步:创建.pro工程文件。

# GoToCellDialog(QtDesigner).pro

HEADERS += \
    gotocelldialog.h

SOURCES += \
    main.cpp \
    gotocelldialog.cpp

FORMS += \
    gotocelldialog.ui

           

007 Program – sortdialog(QtDesigner)

01. 展示程序功能

Part 02 对话框(Qt)[2012.01.20]

        这个对话框是一个用于电子制表软件应用程序的排序对话框(Sort对话框),在这个对话框中,用户可以选择一列或多列进行排序。More按钮允许用户在简单外观和扩展外观之间切换。

02. 使用Qt Desinger设计程序的一般思路

        第一步:使用Qt Designer创建.ui文件:(设置窗口部件及窗口布局)

                ① 创建并初始化子窗口部件

                ② 把子窗口部件放到布局中

                ③ 设置Tab键顺序

                ④ 建立信号-槽之间的连接

                ⑤ 实现对话框中的自定义槽

        第二步:创建.h头文件。(通过简单地增加另一个间接层,解决直接使用.ui的大多数问题)

        第三步:创建.cpp源文件。(包括main, 类)

        第四步:创建.pro工程文件。

03. 程序编写过程

        第一步:使用Qt Designer创建.ui文件:(设置窗口部件及窗口布局)

Part 02 对话框(Qt)[2012.01.20]

                ① 创建并初始化子窗口部件

                -> 先创建出三个Group Box

Part 02 对话框(Qt)[2012.01.20]

                -> 然后,创建子窗口部件

Part 02 对话框(Qt)[2012.01.20]

                -> 这时,记得将MoreButton的属性设置为Checkable

Part 02 对话框(Qt)[2012.01.20]

                ->然后,设置它们的伙伴关系

Part 02 对话框(Qt)[2012.01.20]

               ② 把子窗口部件放到布局中

Part 02 对话框(Qt)[2012.01.20]

                ③ 设置Tab键顺序

Part 02 对话框(Qt)[2012.01.20]

                ④ 建立信号-槽之间的连接

Part 02 对话框(Qt)[2012.01.20]

                ⑤ 实现对话框中的自定义槽

        第二步:创建.h头文件。(通过简单地增加另一个间接层,解决直接使用.ui的大多数问题)

// sortdialog.h

#ifndef SORTDIALOG_H
#define SORTDIALOG_H

#include <QDialog>
#include "ui_sortdialog.h"

class SortDialog: public QDialog, public Ui::SortDialog
{
        Q_OBJECT

public:
    SortDialog(QWidget * parent = 0);
    void setColumnRange(QChar first, QChar last);
};

#endif // SORTDIALOG_H
           

        第三步:创建.cpp源文件。(包括main, 类)

// sortdialog.cpp

#include "sortdialog.h"

SortDialog::SortDialog(QWidget * parent):QDialog(parent)
{
    setupUi(this);

    groupBox_2 -> hide();
    groupBox_3 -> hide();
    layout() -> setSizeConstraint(QLayout::SetFixedSize); // 使用户不能再修改这个对话框窗体的大小

    setColumnRange('A', 'Z');
}

// 根据电子制表软件,选择初始化组合框中的内容。
void SortDialog::setColumnRange(QChar first, QChar last)
{
    // 清空组合框中的内容
    comboBox -> clear();
    comboBox_3 -> clear();
    comboBox_5 -> clear();

    // 给组合框中添加None选项
    comboBox_6 -> addItem(tr("None"));
    comboBox_4 -> addItem(tr("None"));
    comboBox_2 -> setMinimumSize(comboBox_3 -> sizeHint());

    // 给组合框添加内容,使用一个循环语句
    QChar ch = first;
    while (ch <= last)
    {
        comboBox -> addItem(QString(ch));
        comboBox_3 -> addItem(QString(ch));
        comboBox_5 -> addItem(QString(ch));
        ch = ch.unicode() + 1;
    }
    return;
}
           
// main.cpp

#include <QApplication>
#include "sortdialog.h"

int main(int argc, char * argv[])
{
    QApplication app(argc, argv);
    SortDialog * dialog = new SortDialog;
    dialog -> setColumnRange('A', 'G'); // 给ComboBox添加选项
    dialog -> show();
    return app.exec();
}
           

        第四步:创建.pro工程文件。

# sortdialog(QtDesigner).pro

SOURCES += \
    main.cpp \
    sortdialog.cpp

HEADERS += \
    sortdialog.h

FORMS += \
    sortdialog.ui

           

        第五步:最后小结

                        设计一个扩展对话框并不比设计一个简单对话框难,需要:

                         1. 一个切换按钮  2. 信号-槽连接 3. 一个不可改变大小的布局