排列窗体上的控件(Laying Out Widgets on a Form)
中英文对照:
form(窗体),layout(布局或者排列,意思是进行窗体上控件的排列的过程,如大小位置等)
absolute positioning(绝对位置定位),manual layout(手工布局), layout managers(布局管理器)
Qt中有三种方式对窗体上的控件进行布局管理:绝对位置定位(absolute positioning),手工布局(manual layout),布局管理器(layout managers)。我们使用图6.1中的对话框为例对这三种方式分别进行说明。
Figure 6.1. The Find File dialog
绝对位置定位的方法是最原始的排列控件的方法。这个方法是在程序中调用控件的函数设定它的位置和相对窗体它的大小。下面是用着个方法实现的FindFileDialog的构造函数。
FindFileDialog::FindFileDialog(QWidget *parent)
    : QDialog(parent)
{
    ...
    namedLabel->setGeometry(9, 9, 50, 25);
    namedLineEdit->setGeometry(65, 9, 200, 25);
    lookInLabel->setGeometry(9, 40, 50, 25);
    lookInLineEdit->setGeometry(65, 40, 200, 25);
    subfoldersCheckBox->setGeometry(9, 71, 256, 23);
    tableWidget->setGeometry(9, 100, 256, 100);
    messageLabel->setGeometry(9, 206, 256, 25);
    findButton->setGeometry(271, 9, 85, 32);
    stopButton->setGeometry(271, 47, 85, 32);
    closeButton->setGeometry(271, 84, 85, 32);
    helpButton->setGeometry(271, 199, 85, 32);
    setWindowTitle(tr("Find Files or Folders"));
    setFixedSize(365, 240);
}
这种方法缺点很多:
1.         用户不能改变窗体的大小
2.         如果改变字体或者翻译到另一种语言,控件上的文本可能不能完全显示
3.         在一些样式下,控件的尺寸会不合适
另一种方法为手工布局。给出控件的绝对位置,但是他们的尺寸根据窗口的大小确定,可以通过重写窗体的resizeEvent()实现对子控件的大小设置:
FindFileDialog::FindFileDialog(QWidget *parent)
    : QDialog(parent)
{
    ...
    setMinimumSize(265, 190);
    resize(365, 240);
}
void FindFileDialog::resizeEvent(QResizeEvent * /* event */)
{
    int extraWidth = width() - minimumWidth();
    int extraHeight = height() - minimumHeight();
   namedLabel->setGeometry(9, 9, 50, 25);
    namedLineEdit->setGeometry(65, 9, 100 + extraWidth, 25);
    lookInLabel->setGeometry(9, 40, 50, 25);
    lookInLineEdit->setGeometry(65, 40, 100 + extraWidth, 25);
    subfoldersCheckBox->setGeometry(9, 71, 156 + extraWidth, 23);
    tableWidget->setGeometry(9, 100, 156 + extraWidth,
                             50 + extraHeight);
    messageLabel->setGeometry(9, 156 + extraHeight, 156 + extraWidth,
                              25);
    findButton->setGeometry(171 + extraWidth, 9, 85, 32);
    stopButton->setGeometry(171 + extraWidth, 47, 85, 32);
    closeButton->setGeometry(171 + extraWidth, 84, 85, 32);
    helpButton->setGeometry(171 + extraWidth, 149 + extraHeight, 85,
                            32);
}
在FindFileDialog构造函数中,设置窗体的最小尺寸为265×190,初始大小为365×240。在resizeEvent()中,变量extraWidth和extraHeight为控件相对最小尺寸的差值,根据差值计算子控件的大小,这个在改变窗体大小时控件能够跟着改变其大小。
Figure 6.2. Resizing a resizable dialog
 
 
绝对位置定位和手工布局管理都是需要更多的代码,也需要更多的常量参与计算。这样编写代码非常令人讨厌,如果设计改变了,所有的值都要重新计算一遍。虽然手工布局能改变空间大小,但是有时仍然会无法显示全部文字,为了避免这个错误,可以考虑控件的sizeHint,但是这样的代码会更加复杂了。
管理窗体上控件最简单的方法就是使用Qt的布局管理类。这些类能够给出所有类型控件的默认值,能够根据控件的字体,样式,内容得到不同的控件的sizeHint。布局管理类能够得到控件的最大,最小尺寸,在字体,内容或者窗口改变时自动调整布局。
QHBoxLayout,QVBoxLayout,QGridLayout是三个最重要的布局管理器,这些类从QLayout继承,QLayout提供布局最基本的框架。这三个类可以在代码中使用,也可以在Qt Designer中使用,下面是FindFileDialog使用布局管理器的代码
FindFileDialog::FindFileDialog(QWidget *parent)
    : QDialog(parent)
{
    ...
    QGridLayout *leftLayout = new QGridLayout;
    leftLayout->addWidget(namedLabel, 0, 0);
    leftLayout->addWidget(namedLineEdit, 0, 1);
    leftLayout->addWidget(lookInLabel, 1, 0);
    leftLayout->addWidget(lookInLineEdit, 1, 1);
    leftLayout->addWidget(subfoldersCheckBox, 2, 0, 1, 2);
    leftLayout->addWidget(tableWidget, 3, 0, 1, 2);
    leftLayout->addWidget(messageLabel, 4, 0, 1, 2);
    QVBoxLayout *rightLayout = new QVBoxLayout;
    rightLayout->addWidget(findButton);
    rightLayout->addWidget(stopButton);
    rightLayout->addWidget(closeButton);
    rightLayout->addStretch();
    rightLayout->addWidget(helpButton);
    QHBoxLayout *mainLayout = new QHBoxLayout;
    mainLayout->addLayout(leftLayout);
    mainLayout->addLayout(rightLayout);
    setLayout(mainLayout);
    setWindowTitle(tr("Find Files or Folders"));
}
代码中用到了QHBoxLayout,QGridLayout和QVBoxLayout。窗体的左边的子控件由QGridLayout负责,右边的子控件由QVBoxLayout负责。这两个布局由QHBoxLayout进行控制。对话框四周的边缘大小和控件之间的间隔设置为当前空间样式的缺省值,函数QLayout::setMargin()和QLayout::setSpacing()能够对这两个值进行修改。
这个对话框也可以使用Qt Designer实现,首先把所有的子控件放置在近似适当的位置,选择需要布局管理器一同管理的控件,点击Form|Layout Horizontally,Form|Layout Vertically或者Form|Layout in a Grid。在第二章我们这样创建了Spreadsheet程序的Go-to-Cell对话框和Sort对话框。
Figure 6.3. The Find File dialog's layout
 
QHBoxLayout 和QVBoxLayout的使用很简单,QGridLayout有点复杂。QGridLayout工作的基础是一个二维的单元格。左上角的QLabel在布局中的位置为(0,0),旁边的QLineEdit位置为(0,1)。QCheckBox占用了(2,0)和(2,1)两个列的空间,下面的QTreeWidget和QLabel也是如此。QGridLayout::addWidget()语法如下:
layout->addWidget(widget, row, column, rowSpan, columnSpan);
参数widget为插入到这个布局的子控件,(row,column)为控件占据的左上角单元格位置,rowSpan是控件占据的行数,colunmSpan是控件占据的列的个数。rowSpan和colunmSpan默认值为1。
函数addStretch()使布局管理器在指定的位置留出一块空间。上面的代码中,布局管理器在Close按钮和Help按钮之间留出一个额外的空隙。在Qt Designer中,我们可以加入一个spacer实现这一功能,在Qt Designer中,spacer表现为蓝色的弹簧式折线。
使用布局管理类还能获得其他多的功能。如果把一个控件加到一个布局中,或者从布局中删除一个控件,布局管理器会自动适应变化,调整控件大小。调用子控件的hide()或者show()函数时,布局管理器同样也会自动进行调整。如果子控件的sizeHint改变了,布局管理器就会根据控件新的sizeHint进行调整。根据所有子控件的最小尺寸和sizeHint,布局管理器还会计算出整个窗体最小尺寸。
在上例中,我们只是把控件放到布局中,使用spacer(stretches)填满余下的空间。有时,光是这些还是不够的,我们还可以改变控件的sizePolicy,或者sizeHint,使窗体的布局更加符合我们的需要。
一个控件的sizePolicy说明控件在布局管理中的缩放方式。Qt提供的控件都有一个合理的缺省sizePolicy,但是这个缺省值有时不能适合所有的布局,开发人员经常需要改变窗体上的某些控件的sizePolicy。一个QSizePolicy的所有变量对水平方向和垂直方向都适用。下面列举了一些最长用的值:
1.         Fixed:控件不能放大或者缩小,控件的大小就是它的sizeHint。
2.         Minimum:控件的sizeHint为控件的最小尺寸。控件不能小于这个sizeHint,但是可以放大。
3.         Maximum:控件的sizeHint为控件的最大尺寸,控件不能放大,但是可以缩小到它的最小的允许尺寸。
4.         Preferred:控件的sizeHint是它的sizeHint,但是可以放大或者缩小
5.         Expandint:控件可以自行增大或者缩小
图6.4以文本为“Some Text”的QLabel显示了这些不同的sizePolicy的含义,
Figure 6.4. The meaning of the different size policies
 

在图中,Preferred和Expanding的表现是一样的,二者的区别何在那?如果一个窗体中既有Preferred控件也有Expanding控件,在改变大小时,由Expanding控件填满其余的控件,而Preferred控件不变,认为它的sizeHint。
还有两个sizePolicy值为MinimumExpanding和Ignored。MinimumExpanding在老的Qt版本中有时会用到,但是现在已经不用了。替代的方法时使用Expanding值和重写合适的minimumSizeHint()函数。Ignored和Expanding很像,只是它忽略控件的sizeHint和最小的sizeHint。
除了水平和垂直方向的值,QSizePolicy还包含了一个水平和垂直方向的放缩倍数(stretch factor)。当窗体放大时,这两个值决定不同控件放大的程度。例如,如果QTreeWidget和QTextEdit上下排列,如果我们希望QTextEdit高度为QTreeWidget的两倍,就可以设置QTextEdit的垂直放缩倍数为2,QTreeWidget的垂直放缩倍数为1。
控件的最小尺寸,最大尺寸和固定尺寸也是影响布局的因素。布局管理器排列控件时会考虑这些限制。如果这些还不够,可以创建新类重写sizeHint()。

[译]- 6-1 排列窗体上的控件(Laying Out Widgets on a Form)的更多相关文章

  1. WinForm中新开一个线程操作 窗体上的控件(跨线程操作控件)

    最近在做一个winform的小软件(抢票的...).登录窗体要从远程web页面获取一些数据,为了不阻塞登录窗体的显示,开了一个线程去加载数据远程的数据,会报一个错误"线程间操作无效: 从不是 ...

  2. Ruby操作VBA的注意事项和技巧(2):宏里调用和控制窗体以及窗体上的控件、不同workbook之间的宏互相调用

    4.宏里调用并控制窗体以及窗体上的各种控件 1 Sub Criterion_Check() 2 If Workbooks.count = 0 Then '如果当前没有打开的工作薄的话需要发出警告 3 ...

  3. 窗体透明,但窗体上的控件不透明(简单好用)good

    1.在Delphi中,设置窗体的AlphaBlend := true;AlphaBlendValue := 0-255; AlphaBlendValue越小窗体的透明度就越高.这种方法将会使窗体和窗体 ...

  4. Delphi - 子窗体继承父窗体后如何显示父窗体上的控件

    1.创建子窗体Form1 File -> New -> Form,新建一个form,在form的单元文件中修改 2.子窗体中引用父窗体单元 uses TFatherForm 3.将子窗体中 ...

  5. 问题-Delphi在多线程中使用其他窗体上的控件,报“尚未调用CoInitialize”解决方法

    1.uses ActiveX; 2. procedure HLCJ.Execute;begin    CoInitialize(nil);    //要使用的控件    CoUninitialize; ...

  6. c# 多线程调用窗体上的控件 示例

    private delegate void InvokeCallback(string msg); private void SetCountValue(string s) { if (this.fo ...

  7. VC窗体透明而控件不透明以及Static文本背景透明方法

    出自http://my.oschina.net/ypimgt/blog/60951 优点:    1.Dialog 窗体完全透明.     2. 窗体上的控件不透明. DC 绘制的图形不透明.     ...

  8. 在WebBrowser中通过模拟键盘鼠标操控网页中的文件上传控件(转)

    引言 这两天沉迷了Google SketchUp,刚刚玩够,一时兴起,研究了一下WebBrowser. 我在<WebBrowser控件使用技巧分享>一文中曾谈到过“我现在可以通过WebBr ...

  9. WPF中不规则窗体与WindowsFormsHost控件的兼容问题完美解决方案

    首先先得瑟一下,有关WPF中不规则窗体与WindowsFormsHost控件不兼容的问题,网上给出的解决方案不能满足所有的情况,是有特定条件的,比如  WPF中不规则窗体与WebBrowser控件的兼 ...

随机推荐

  1. FZU 2148 moon game (计算几何判断凸包)

    Moon Game Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit St ...

  2. Count Color(poj 2777)

    题意: 给一个固定长度为L的画板 有两个操作: C A B C:区间AB内涂上颜色C. P A B:查询区间AB内颜色种类数. 分析:显然是要用线段树来操作的,设定一个sum[]来维护一个区间内的颜色 ...

  3. stm32——RTC实时时钟

    stm32——RTC实时时钟 一.关于时间 2038年问题 在计算机应用上,2038年问题可能会导致某些软件在2038年无法正常工作.所有使用UNIX时间表示时间的程序都将将受其影响,因为它们以自19 ...

  4. Java内部类的访问规则

    1.内部类可以直接访问外部类中的成员,包括私有      原因:因为在内部类中持有一个外部类的应用,格式:外部类.this class Outer {     private int x = 1; c ...

  5. 查看nginx版本号

    # ./nginx -v Tengine version: Tengine/ (nginx/)

  6. Android:dimen尺寸资源文件的使用

    dimen.xml在values文件夹下面 <resources> <!-- Default screen margins, per the Android Design guide ...

  7. 安装完最小化 RHEL/CentOS 7 后需要做的 30 件事情(二)转载自码农网

    7. 安装 PHP PHP 是用于 web 基础服务的服务器端脚本语言.它也经常被用作通用编程语言.在最小化安装的 CentOS 中安装 PHP: # yum install php 安装完 php ...

  8. android自定义弹出框样式实现

    前言: 做项目时,感觉Android自带的弹出框样式比较丑,很多应用都是自己做的弹出框,这里也试着自己做了一个. 废话不说先上图片: 实现机制 1.先自定义一个弹出框的样式 2.自己实现CustomD ...

  9. Linux磁盘分区与格式化

    磁盘分区格式说明 linux分区不同于windows linux下分区标示: 例如:hda1 hd这两个字母表示分区所在的设备类型,hd标示IDE类型硬盘,sd表示SCSI类型硬盘 第三字母a标示硬盘 ...

  10. 原生JS代码实现一个Ajax异步请求

    异步加载的方式 (1) defer,只支持IE (2) async: (3) 创建script,插入到DOM中,加载完毕后callBack 实现ajax之前必须要创建一个 XMLHttpRequest ...