排列窗体上的控件(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. object-c 基本数据类型

    1.基本数据类型   int  float  double  char   布尔类型   枚举类型 2.对象类型和id类型  就是类类型或协议所声明的指针类型.  id类型可以表示任何类型,一般只表示 ...

  2. linux shell脚本守护进程监控svn服务

    最近搭建的svn服务不知道什么原因服务总是被关闭(如果你不知道怎么搭建svn可以参考linux下搭建svn版本控制软件),因此用shell脚本实现一个守护进程.用于监控svn服务是否启动,如果服务不在 ...

  3. 使用Antlr实现简单的DSL

    为什么要使用DSL DSL是领域专用语言,常见的DSL有SQL,CSS,Shell等等,这些DSL语言有别于其他通用语言如:C++,Java,C#,DSL常在特殊的场景或领域中使用.如下图: 领域专用 ...

  4. 基于Twemproxy的Redis集群方案

    概述 由于单台redis服务器的内存管理能力有限,使用过大内存redis服务器的性能急剧下降,且服务器发生故障将直接影响大面积业务.为了获取更好的缓存性能及扩展型,我们将需要搭建redis集群来满足需 ...

  5. 拷贝Java项目报错

    经常需要将一个项目,导出,然后发给同事,或者是自己用另一个Eclipse工具打开. 这时,导入项目后,就会出现各种各样的问题.大牛笔记:www.weixuehao.com 代码相同,环境不同,主要是修 ...

  6. ytu 1937:查找最大元素(水题)

    查找最大元素 Time Limit: 1 Sec  Memory Limit: 64 MBSubmit: 51  Solved: 23[Submit][Status][Web Board] Descr ...

  7. 一个功能完备的.NET开源OpenID Connect/OAuth 2.0框架——IdentityServer3

    今天推荐的是我一直以来都在关注的一个开源的OpenID Connect/OAuth 2.0服务框架--IdentityServer3.其支持完整的OpenID Connect/OAuth 2.0标准, ...

  8. Chromium Embedded Framework 中文文档(简介)

    转自:http://www.cnblogs.com/think/archive/2011/10/06/CEF-Introduce.html 简介 Chromium Embedded Framework ...

  9. ☆☆配置NDK环境

    1 前提是 已经配置好 安卓SDK开发环境. 2 下载 android-ndk64-r10-windows-x86_64,可以从官方网站下载,这里有一个现成的. http://pan.baidu.co ...

  10. HDU 4258 Covered Walkway 斜率优化DP

    Covered Walkway Problem Description   Your university wants to build a new walkway, and they want at ...