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

第5章 布局管理

GUI用户界面的每一个窗口部件都必须有一个显示位置和大小尺寸,特别是当用户拉伸窗口部件时,窗口部件中的子窗口部件都应该做出适当的变化,以免无法正常显示子窗口部件的内容。在这一章,将学习Qt的布局管理器、分裂器以及栈部件和工作空间部件的使用。

5.1 Qt布局管理器——QLayout

Qt布局管理器是Qt图形用户界面设计的基本内容,在前面的几章中也陆陆续续地讲到了Qt的布局管理器的使用,也做了一些简单的应用。本节将详细介绍Qt的布局管理器,详细阐述Qt布局管理器的一些特性。

5.1.1 Qt布局管理器简介

Qt提供了几种在窗口部件上管理子窗口部件的基本方式。

(1)绝对位置方式。这种方式是通过基类QWidget提供的setGeometry()函数来设置子窗口部件的大小及其在父窗口部件中的位置。使用这种方式的缺点有很多,比如用户不能够重定义窗口的大小;再比如,当用户随意的改变窗口的大小时,子窗口部件无法作出相应的改变,子窗口部件的大小以及文本都有可能被截断。此外,使用这种方法必须要程序员反复的计算子窗口部件的大小和位置,并不断地运行、调试和观察GUI界面的效果。很显然,使用这种方式管理GUI用户界面的外观远远降低了程序员的开发效率,降低了应用程序的质量和适应性。

(2)手工布局方式。这种方式也是通过基类QWidget提供的setGeometry()函数来设置子窗口部件的位置和大小。与绝对位置方式不同的是,它是通过重载QWidget::resizeEvent(QResizeEvent*)函数来实现的。当窗口大小改变的时候,通过重新计算窗口的大小或者变化比例,能够使得子窗口部件的大小和位置作出适应性的改变。但它同样存在一个很严重的问题,就是程序员必须手工计算子窗口部件的大小和位置。因此,使用这种方式进行GUI开发,其效率仍然是低下的。

(3)布局管理器方式。这种方式是使用Qt设计图形化用户界面、组织管理Qt GUI窗口部件的最好方法。布局管理器为窗口部件提供了有感知的默认值(sensible default sizes),可以随着窗口部件大小的变化,对子窗口部件的大小和位置做出适当的调整。

Qt主要提供了4种布局管理器,具体如图5-1所示。

● 水平布局管理器QHBoxLayout,按水平方向组织管理Qt GUI窗口部件;

● 垂直布局管理器QVBoxLayout,按垂直方向组织管理Qt GUI窗口部件;

● 网格布局管理器QGridLayout,按二维网格方式组织管理Qt GUI窗口部件;

● 栈布局管理器QStackedLayout,按照一种类似于栈的方式组织窗口部件,在某一时刻只有一个窗口部件是可见的。Qt设计器没有提供对该布局管理器的支持,不过提供了一个栈部件QStackedWidget。因此,使用Qt设计器绘制GUI界面时,完全可以使用QStackedWidget代替QStackedLayout。

图5-1 Qt布局管理器类

Qt的三种布局管理器的管理模式如图5-2、图5-3和图5-4所示。

图5-2 QHBoxLayout

图5-3 QVBoxLayout

图5-4 QGridLayout

Qt布局管理器可以有效地管理窗口中的子窗口部件,同时子窗口部件的布局也受到其本身的大小策略(size policies)及其最大值/最小值的影响。

窗口部件的大小策略告诉布局管理器该窗口部件自身应该如何被拉伸或者压缩。大小策略包含水平方向的大小策略和垂直方向的大小策略两个方面。每个方向分别有7个策略值(其类型为枚举类型QSizePolicy::Policy),它们是:

● QSizePolicy::Fixed,窗口部件既不能被拉伸也不能被压缩,它总是保持在大小提示(sizeHint)的尺寸。窗口部件的大小范围是sizeHint()~sizeHint()。

● QSizePolicy::Minimum,窗口部件的大小提示是它的最小尺寸,即窗口部件的大小不能够被压缩的比大小提示更小。但窗口部件可以被拉伸来填充尽可能多的空间。窗口部件的大小范围是:sizeHint()~无穷大。

● QSizePolicy::Maximum,窗口部件的大小提示是它的最大尺寸,即窗口部件的大小不能够被拉伸的比大小提示更大,但窗口部件可以被压缩。窗口部件的大小范围是:0~sizeHint()。

● QSizePolicy::Preferred,窗口部件的大小提示是窗口部件最合适的尺寸,但是如果需要,窗口部件还是能够被拉伸和被压缩的。窗口部件的大小范围是:0~无穷大。

● QSizePolicy::Expanding,窗口部件可以被拉伸也可以被压缩,但它更倾向于被拉伸。窗口部件的大小范围是:0~无穷大。

● QSizePolicy::MinimumExpanding,窗口部件的大小提示是它的最小尺寸;然而,它也倾向于被拉伸来填充尽可能多的空间。它相当于QSizePolicy::Minimum和QSizePolicy::Expanding的组合。窗口部件的大小范围是:sizeHint()~无穷大。

● QSizePolicy::Ignored,窗口部件忽略它的大小提示,并且它尽可能地伸展到可用的空间。窗口部件的大小范围是:0~无穷大。

图5-5 窗口部件大小策略的含义

在介绍Qt窗口部件的大小策略的时候,提到一个很重要的概念:大小提示。大小提示是进行Qt GUI编程的时候,Qt推荐的一个窗口部件的大小。当Qt GUI窗口部件在进行初始化的时候,将通过虚函数QWidget::sizeHint()获得该窗口部件的大小提示:

● 如果该窗口部件没有布局管理器,那么该函数将返回一个无效的值;

● 如果该窗口部件具有布局管理器,那么该函数返回一个布局管理器认为比较合适的大小尺寸。

值得注意的是,程序中使用Qt设计器绘制的GUI界面的时候,顶层窗口部件的大小提示sizeHint()不再起作用,即调用show()(或setVisible(true))显示顶层窗口部件的时候,QWidget::sizeHint()函数不再被调用。这就决定了顶层窗口部件的大小策略变化的参照已不再是窗口部件的大小提示,而是窗口部件在Qt设计器中的实际大小(准确地讲,应该取设计器中顶层窗口部件的尺寸和顶层窗口部件mimimumSizeHint()中的较大尺寸),从而达到Qt设计器绘制GUI用户界面的所见即所得(顶层窗口部件的子窗口部件因为受到其父窗口部件的布局管理器的管理,尺寸会根据各自的大小策略随父窗口部件的变化而变化。这也是在Qt设计器中嵌套使用布局管理器的原因,即通过布局管理器一层层的管理,保证Qt绘制的GUI界面就是应用程序实际运行的用户界面)。

uic根据Qt设计器绘制的GUI界面生成的C++头文件中,函数setupUi()会调用函数QWidget::mimimumSizeHint(),结合Qt设计器中顶层窗口部件的实际绘制尺寸,完成顶层窗口部件的大小设置。函数QWidget::mimimumSizeHint()的返回值遵循下列规则:

● 如果该窗口部件没有布局管理器,QWidget::mimimumSizeHint()函数返回一个无效的值;

● 如果该窗口部件具有布局管理器,QWidget::mimimumSizeHint()函数返回布局管理器认为适合的一个大小尺寸。

最小提示(minimum size hint)是Qt为窗口部件推荐的最小尺寸,它的使用情况是(在最小提示有效的情况下):

如果需要绘制的窗口部件的大小尺寸(包括长宽两个方面)小于其最小提示(这在Qt设计器中往往表现有些被压缩到看不到它的内容),并且该窗口部件的最小提示在最大尺寸和最小尺寸允许的范围内,那么该窗口部件显示后的大小尺寸将是最小提示的值。

然而,当多个窗口部件用布局管理器组合在一起的时候,窗口部件的大小及它们是否能够伸展或者缩短是要受到其他窗口部件的大小策略影响的。有下列几种情况:

● 相同大小策略的窗口部件被布局管理器组合在一起。在这种情况下,除了窗口部件不能超出它的大小范围外,不同的窗口部件可以按自己的伸缩因子在其允许的范围内自由地伸缩。

● QSizePolicy::Fixed和任何其他的大小策略组合在一起。具有QSizePolicy::Fixed大小策略的窗口部件其大小总是不变的,即保持在sizeHint()大小,而其他的窗口部件可以在允许的范围内自由伸缩。

● QSizePolicy::Preferred和QSizePolicy::Expanding(或者QSizePolicy::MinimumExpanding)组合在一起,具有QSizePolicy::Preferred大小策略的窗口部件其大小是不变化的,即它认为大小提示sizeHint()是最适合它的,而其他的窗口部件大小可以在其允许的范围内自由伸缩。

● QSizePolicy::Ignored和其他大小策略(QSizePolicy::Fixed策略除外)组合在一起的时候,不同的窗口部件在各自允许的范围内自由伸缩。

● QSizePolicy::Preferred,QSziePolicy::Minimum和QSizePolicy::Maximum组合在一起的时候,各窗口部件在各自允许的范围内可以自由伸缩。

当多个窗口部件被布局管理器组合在一起的时候,它们都可以在其范围内自由伸缩的情况下,它们伸缩的多少也是互相影响的,这通过设置窗口部件的伸缩因子来实现的,即设置窗口部件大小策略的属性QSizePolicy::horizontalStretch和QSizePolicy::verticalStretch的值来实现的。默认情况下,被布局管理器组合在一起的窗口部件的伸缩因子是相等的,都为0。此时,在所有的窗口部件都没有超出各自的大小范围允许的情况下,窗口部件的大小始终是相等的。

假设,窗口部件widget1和widget2被一个布局管理器QHBoxLayout组合在一起,如图5-6所示,并且widget1的QSizePolicy::horizontalStretch设置为“1”,而wdget2的QsizePolicy::horizontalStretch设置为“2”,并且它们的水平大小策略都为QSizePolicy::Preferred,那么窗口部件widget1和widget2的大小总是保持在1:2的关系,而无论布局管理器在水平方向上伸缩到何种程度。垂直方向的大小关系与它们的大小策略也有类似的关系。

图5-6 伸缩因子对大小尺寸的影响

此外,主窗口部件(main widget)的大小还要受到其布局管理器的sizeConstraint属性的约束:

● QLayout::SetDefaultConstraint,主窗口部件的最小尺寸设置为minimumSize(),除非该窗口部件已经有一个最小尺寸;

● QLayout::SetFixedSize,主窗口部件的尺寸设置为sizeHint(),并且不允许改变该窗口部件的尺寸;

● QLayout::SetMinimumSize,主窗口部件的最小尺寸设置为minimumSize(),并且该窗口部件不能够变得更小;

● QLayout::SetMaximumSize,主窗口部件的最大尺寸设置为maximumSize(),并且该窗口部件不能够变得更大;

● QLayout::SetMinAndMaxSize,主窗口部件的最小尺寸设置为minimumSize()、最大尺寸设置为maximumSize();

● QLayout::SetNoConstraint,主窗口部件的大小不会受到约束。

所谓主窗口部件,就是能够放置一个布局管理器管理其所有子窗口部件的窗口部件。例如,放置了一个布局管理器的“个人信息”QGroupBox(它使用一个网格布局管理器管理它内部的所有子窗口部件)。顶层窗口是一个主窗口部件,如图5-7所示。

图5-7 一个主窗口部件的例子

可以通过QWidget::layout()获取主窗口部件的布局管理器,然后可以调用QLayout::setSizeConstraint()函数设置该布局管理器的sizeConstraint属性(将在下面的例子中演示这些属性)。

Qt的布局管理器是Qt GUI用户界面设计的一个重要部分,在Qt设计器中以及在代码中添加窗口部件、排列组织窗口部件的时候,总要用到Qt的布局管理器。当多个窗口部件被一个布局管理器组合在一起,以及多个布局管理器嵌套管理窗口部件的时候,出现的情况可能还要复杂。在此,笔者也只是归纳了几种简单使用Qt布局管理器的情况,希望给读者以提示。

5.1.2 布局管理器及窗口部件大小策略的应用

刚才简述了Qt布局管理器的基本原理,Qt窗口部件的尺寸受到各种各样的策略的影响,看起来比较复杂。上面的介绍也是比较枯燥的,下面用一个较简单的例子演示一下布局管理器的使用。

在学习对话框应用的时候,曾看到过可以改变形状的QMessageBox的一个例子,如图5-8 所示。

此处将实现一个类似效果的对话框。为了简单起见,下面的例子中,仅仅控制窗口部件的水平方向的策略、伸缩比例等。在Qt设计器绘制GUI图形用户界面(保存为“layoutdlg.ui”),如图5-9所示。

图5-8 形状可变的对话框

图5-9 布局管理器应用的ui界面

窗口部件属性如表5-1所示。

表5-1 窗口部件属性(从上到下、从左到右,缩进表征窗口部件的父子关系)

下面,首先来看一下类CLayoutDlg的头文件layoutdlg.h,如下所示。

        // chapter05/layout/src/layoutdlg.h.
        #ifndef _LAYOUTDLG_H_
        #define _LAYOUTDLG_H_

        #include "ui_layoutdlg.h"
        class CLayoutDlg :  public QDialog,
                            public Ui_LayoutDlg
        {
            Q_OBJECT
        public:
            CLayoutDlg(QWidget* = 0);
        private:
            void    init();

            QAction*    actDefaultConstraint;
            QAction*    actFixedSize;
            QAction*    actMinimumSize;
            QAction*    actMaximumSize;
            QAction*    actMinAndMaxSize;
            QAction*    actNoConstraint;

声明了6个动作指针变量,分别对应QLayout的6个大小约束,用来设置顶层窗口部件的布局管理器的大小约束。

        QAction*    actLFixed;
        QAction*    actLMinimum;
        QAction*    actLMaximum;
        QAction*    actLPreferred;
        QAction*    actLExpanding;
        QAction*    actLMinimumExpanding;
        QAction*    actLIgnored;

声明了7个动作指针变量,分别对应QSizePolicy的7个策略,用于设置GUI界面左侧编辑框QTextEdit对象lTextEdit的水平方向的策略。

        QAction*    actLStretch0;
        QAction*    actLStretch1;
        QAction*    actLStretch2;
        QAction*    actLStretch4;

声明了4个动作指针变量,分别对应QSizePolicy的4个伸缩值,用于设置GUI界面左侧编辑框QTextEdit对象lTextEdit的水平方向的伸缩值。

接下来,继续声明设置GUI用户界面的右侧文本编辑框QTextEdit对象rTextEdit的策略和伸缩值的动作。

            QAction*    actRFixed;
            QAction*    actRMinimum;
            QAction*    actRMaximum;
            QAction*    actRPreferred;
            QAction*    actRExpanding;
            QAction*    actRMinimumExpanding;
            QAction*    actRIgnored;
            QAction*    actRStretch0;
            QAction*    actRStretch1;
            QAction*    actRStretch2;
            QAction*    actRStretch4;
        private slots:
            void doActConstraint();
            void doActLPolicy();
            void doActRPolicy();
            void doActLStretch();
            void doActRStretch();
        };
        #endif

声明的5个槽函数分别响应设置布局管理器的约束、设置左编辑框的策略、设置右编辑框的策略、设置左编辑框的伸缩值和设置右编辑框的伸缩值。

现在,看一下类CLayoutDlg的实现文件layoutdlg.cpp的内容。

        // chapter05/layout/src/layoutdlg.cpp.
        #include <QtGui>
        #include "layoutdlg.h"

        CLayoutDlg::CLayoutDlg(QWidget* parent)
        :  QDialog(parent)
        {
            setupUi(this);
            init();
        }

在构造函数中,调用init()初始化函数,初始化GUI用户界面的状态。

        void CLayoutDlg::init()
        {
            showPushBtn->setCheckable(true);
            showPushBtn->setChecked(true);
            groupBox->setVisible(showPushBtn->isChecked());
            connect(showPushBtn, SIGNAL(toggled(bool)),
                groupBox, SLOT(setVisible(bool)));

函数QPushButton::setCheckable()设置按钮showPushBtn是否具有可选中的(checked)状态。在此,设置showPushBtn是可选中的。QPushButton::setChecked()设置按钮的可选中状态为true(此时,按钮表现为凹陷的)。最后设置“演示”QGroupBox对象groupBox的显隐,并关联信号和槽。

        QMenu*  constraintMenu  = new QMenu(constraintPushBtn);
        actDefaultConstraint = constraintMenu->addAction(
                tr("QLayout::SetDefaultConstraint"));
        actFixedSize = constraintMenu->addAction(
                tr("QLayout::SetFixedSize"));
        actMinimumSize  =
            constraintMenu->addAction(tr("QLayout::SetMinimumSize"));
        actMaximumSize  =
            constraintMenu->addAction(tr("QLayout::SetMaximumSize"));
        actMinAndMaxSize =
            constraintMenu->addAction(tr("QLayout::SetMinAndMaxSize"));
        actNoConstraint = constraintMenu->addAction(
            tr("QLayout::SetNoConstraint"));
        connect(actDefaultConstraint, SIGNAL(triggered()),
            this, SLOT(doActConstraint()));
        connect(actFixedSize, SIGNAL(triggered()),
            this, SLOT(doActConstraint()));
        connect(actMinimumSize, SIGNAL(triggered()),
            this, SLOT(doActConstraint()));
        connect(actMaximumSize, SIGNAL(triggered()),
            this, SLOT(doActConstraint()));
        connect(actMinAndMaxSize, SIGNAL(triggered()),
            this, SLOT(doActConstraint()));
        connect(actNoConstraint, SIGNAL(triggered()),
            this, SLOT(doActConstraint()));
        constraintPushBtn->setMenu(constraintMenu);

上面,创建了控制布局管理器的大小约束菜单,并初始化它的所有动作。最后,通过调用函数QPushButton::setMenu()将该菜单设置到一个QPushButton对象上。

接下来,使用同样的方法初始化其他的菜单,并将菜单添加到相应的QPushButton对象上。

            QMenu*  lpolicyMenu = new QMenu(lpolicyPushBtn);
            actLFixed   = lpolicyMenu->addAction(tr("QSizePolicy::Fixed"));
            actLMinimum = lpolicyMenu->addAction(tr("QSizePolicy::Minimum"));
            actLMaximum = lpolicyMenu->addAction(tr("QSizePolicy::Maximum"));
            actLPreferred = lpolicyMenu->addAction(tr("QSizePolicy::Preferred"));
            actLExpanding = lpolicyMenu->addAction(tr("QSizePolicy::Expanding"));
            actLMinimumExpanding =
                lpolicyMenu->addAction(tr("QSizePolicy::MinmumExpanding"));
            actLIgnored = lpolicyMenu->addAction(tr("QSizePolicy::Ignored"));
            connect(actLFixed, SIGNAL(triggered()),
                this, SLOT(doActLPolicy()));
            connect(actLMinimum, SIGNAL(triggered()),
                this, SLOT(doActLPolicy()));
            connect(actLMaximum, SIGNAL(triggered()),
                this, SLOT(doActLPolicy()));
            connect(actLPreferred, SIGNAL(triggered()),
                this, SLOT(doActLPolicy()));
            connect(actLExpanding, SIGNAL(triggered()),
                this, SLOT(doActLPolicy()));
            connect(actLMinimumExpanding, SIGNAL(triggered()),
                this, SLOT(doActLPolicy()));
            connect(actLIgnored, SIGNAL(triggered()),
                this, SLOT(doActLPolicy()));
            lpolicyPushBtn->setMenu(lpolicyMenu);

            QMenu*  rpolicyMenu = new QMenu(rpolicyPushBtn);
            actRFixed =
                rpolicyMenu->addAction(tr("QSizePolicy::Fixed"));
            actRMinimum =
                rpolicyMenu->addAction(tr("QSizePolicy::Minimum"));
            actRMaximum =
                rpolicyMenu->addAction(tr("QSizePolicy::Maximum"));
            actRPreferred   =
                rpolicyMenu->addAction(tr("QSizePolicy::Preferred"));
            actRExpanding   =
                rpolicyMenu->addAction(tr("QSizePolicy::Expanding"));
            actRMinimumExpanding =
                lpolicyMenu->addAction(tr("QSizePolicy::MinmumExpanding"));
            actRIgnored =
                rpolicyMenu->addAction(tr("QSizePolicy::Ignored"));
            connect(actRFixed, SIGNAL(triggered()),
                this, SLOT(doActRPolicy()));
            connect(actRMinimum, SIGNAL(triggered()),
                this, SLOT(doActRPolicy()));
            connect(actRMaximum, SIGNAL(triggered()),
                this, SLOT(doActRPolicy()));
            connect(actRPreferred, SIGNAL(triggered()),
                this, SLOT(doActRPolicy()));
            connect(actRExpanding, SIGNAL(triggered()),
                this, SLOT(doActRPolicy()));
            connect(actRMinimumExpanding, SIGNAL(triggered()),
                this, SLOT(doActRPolicy()));
            connect(actRIgnored, SIGNAL(triggered()),
                this, SLOT(doActRPolicy()));
            rpolicyPushBtn->setMenu(rpolicyMenu);

            QMenu*  lstretchMenu= new QMenu(lstretchPushBtn);
            actLStretch0    = lstretchMenu->addAction(tr("伸缩比例 0"));
            actLStretch1    = lstretchMenu->addAction(tr("伸缩比例 1"));
            actLStretch2    = lstretchMenu->addAction(tr("伸缩比例 2"));
            actLStretch4    = lstretchMenu->addAction(tr("伸缩比例 4"));
            connect(actLStretch0, SIGNAL(triggered()),
                this, SLOT(doActLStretch()));
            connect(actLStretch1, SIGNAL(triggered()),
                this, SLOT(doActLStretch()));
            connect(actLStretch2, SIGNAL(triggered()),
                this, SLOT(doActLStretch()));
            connect(actLStretch4, SIGNAL(triggered()),
                this, SLOT(doActLStretch()));
            lstretchPushBtn->setMenu(lstretchMenu);

            QMenu*  rstretchMenu= new QMenu(rstretchPushBtn);
            actRStretch0    = rstretchMenu->addAction(tr("伸缩比例 0"));
            actRStretch1    = rstretchMenu->addAction(tr("伸缩比例 1"));
            actRStretch2    = rstretchMenu->addAction(tr("伸缩比例 2"));
            actRStretch4    = rstretchMenu->addAction(tr("伸缩比例 4"));
            connect(actRStretch0, SIGNAL(triggered()),
                this, SLOT(doActRStretch()));
            connect(actRStretch1, SIGNAL(triggered()),
                this, SLOT(doActRStretch()));
            connect(actRStretch2, SIGNAL(triggered()),
                this, SLOT(doActRStretch()));
            connect(actRStretch4, SIGNAL(triggered()),
                this, SLOT(doActRStretch()));
            rstretchPushBtn->setMenu(rstretchMenu);
        }

下面的槽函数doActConstraint()响应用户选择“窗口大小约束”菜单的动作发出的信号,设置顶层窗口部件的布局管理器的大小约束。

        void CLayoutDlg::doActConstraint()
        {
            QAction* act = qobject_cast<QAction*>(sender());
            if(act == actDefaultConstraint)
                layout()->setSizeConstraint(QLayout::SetDefaultConstraint);
            else if(act == actFixedSize)
                layout()->setSizeConstraint(QLayout::SetFixedSize);
            else if(act == actMinimumSize)
                layout()->setSizeConstraint(QLayout::SetMinimumSize);
            else if(act == actMaximumSize)
                layout()->setSizeConstraint(QLayout::SetMaximumSize);
            else if(act == actNoConstraint)
                layout()->setSizeConstraint(QLayout::SetNoConstraint);
            constraintPushBtn->setText(act->text());
        }

函数QWidget::layout()获取安装在当前窗口部件(此处为顶层窗口)的布局管理器。函数QLayout::setSizeConstraint()设置布局管理器的大小约束。

最后,设置QPushButton对象的显示文本为选择的大小约束。

        void CLayoutDlg::doActLPolicy()
        {
            QAction* act = qobject_cast<QAction*>(sender());
            QSizePolicy policy = lTextEdit->sizePolicy();
            if(act == actLFixed)
                policy.setHorizontalPolicy(QSizePolicy::Fixed);
            else if(act == actLMinimum)
                policy.setHorizontalPolicy(QSizePolicy::Minimum);
            else if(act == actLMaximum)
                policy.setHorizontalPolicy(QSizePolicy::Maximum);
            else if(act == actLPreferred)
                policy.setHorizontalPolicy(QSizePolicy::Preferred);
            else if(act == actLExpanding)
                policy.setHorizontalPolicy(QSizePolicy::Expanding);
            else if(act == actLMinimumExpanding)
                policy.setHorizontalPolicy(QSizePolicy::MinimumExpanding);
            else if(act == actLIgnored)
                policy.setHorizontalPolicy(QSizePolicy::Ignored);
            lTextEdit->setSizePolicy(policy);
            lpolicyPushBtn->setText(act->text());
        }

函数doActLPolicy()设置左侧文本编辑框QTextEdit对象水平方向的策略。

函数QTextEdit::sizePolicy()获取文本编辑框的大小策略,该函数继承自QWidget类。

函数QSizePolicy::setHorizontalPolicy()设置大小策略对象(QSizePolicy对象)的水平方向的策略。

最后,函数QTextEdit::setSizePolicy()为文本编辑框设置新的大小策略;设置相应按钮的显示文本。

        void CLayoutDlg::doActRPolicy()
        {
            QAction* act = qobject_cast<QAction*>(sender());
            QSizePolicy policy = rTextEdit->sizePolicy();
            if(act == actRFixed)
                policy.setHorizontalPolicy(QSizePolicy::Fixed);
            else if(act == actRMinimum)
                policy.setHorizontalPolicy(QSizePolicy::Minimum);
            else if(act == actRMaximum)
                policy.setHorizontalPolicy(QSizePolicy::Maximum);
            else if(act == actRPreferred)
                policy.setHorizontalPolicy(QSizePolicy::Preferred);
            else if(act == actRExpanding)
                policy.setHorizontalPolicy(QSizePolicy::Expanding);
            else if(act == actRMinimumExpanding)
                policy.setHorizontalPolicy(QSizePolicy::MinimumExpanding);
            else if(act == actRIgnored)
                policy.setHorizontalPolicy(QSizePolicy::Ignored);
            rTextEdit->setSizePolicy(policy);
            rpolicyPushBtn->setText(act->text());
        }

函数doActRPolicy()设置右侧文本编辑框rTextEdit对象的水平方向的策略。

        void CLayoutDlg::doActLStretch()
        {
            QAction* act = qobject_cast<QAction*>(sender());
            QSizePolicy policy = rTextEdit->sizePolicy();
            if(act == actLStretch0)
                policy.setHorizontalStretch(0);
            else if(act == actLStretch1)
                policy.setHorizontalStretch(1);
            else if(act == actLStretch2)
                policy.setHorizontalStretch(2);
            else if(act == actLStretch4)
                policy.setHorizontalStretch(4);
            lTextEdit->setSizePolicy(policy);
            lstretchPushBtn->setText(act->text());
        }

函数doActLStretch()设置左侧文本编辑框lTextEdit大小策略的水平伸缩值。

函数QSizePolicy::setHorizontalStretch()设置大小策略对象的水平伸缩值。

设置GUI用户界面右侧文本编辑框大小策略的水平伸缩值与上面类似,实现代码如下。

        void CLayoutDlg::doActRStretch()
        {
            QAction* act = qobject_cast<QAction*>(sender());
            QSizePolicy policy = rTextEdit->sizePolicy();
            if(act == actRStretch0)
                policy.setHorizontalStretch(0);
            else if(act == actRStretch1)
                policy.setHorizontalStretch(1);
            else if(act == actRStretch2)
                policy.setHorizontalStretch(2);
            else if(act == actRStretch4)
                policy.setHorizontalStretch(4);
            rTextEdit->setSizePolicy(policy);
            rstretchPushBtn->setText(act->text());
        }

现在,建立新的KDevelep工程layout,创建主程序并将刚才建立的ui文件和类CLayoutDlg的定义文件和实现文件加入到工程中。最后编译运行应用程序,效果如图5-10所示。

图5-10 布局管理器应用的运行界面

在这个例子中,当管理器的策略设置为QLayout::SetFixedSize时,就是一个可变形的对话框。读者可以试着组合这些策略,体会一下Qt布局管理的一些特性。