排列窗体上的控件(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. 2.7 编程之美--最大公约数的3种解法[efficient method to solve gcd problem]

    [本文链接] http://www.cnblogs.com/hellogiser/p/efficient-method-to-solve-gcd-problem.html [题目] 求两个正整数的最大 ...

  2. Java for LeetCode 152 Maximum Product Subarray

    Find the contiguous subarray within an array (containing at least one number) which has the largest ...

  3. HDU 1023 Traning Problem (2) 高精度卡特兰数

    Train Problem II Time Limit: 1000MS   Memory Limit: 32768KB   64bit IO Format: %I64d & %I64u Sub ...

  4. 越狱后想禁用Spotlight

    如果你的是ios7越狱后不想用Spotlight搜索功能,大老板源的NoSpot ios7可轻松帮你实现.亲测可用……………………

  5. php 面向对象之封装

    <body> <?php //类的概念 //对象的概念 //定义类 //class Ren //{ //成员变量 //成员方法 //} //造对象 //$r = new Ren(); ...

  6. WPF中的VisualTreeHelper

    VisualTreeHelper提供了一组WPF控件树模型,通过VisualTreeHelper可以遍历控件的树形结构,获取我们所需要的控件以及相应的属性: VisualTreeHelper提供了一下 ...

  7. oracle 执行计划详解

    简介:     本文全面详细介绍oracle执行计划的相关的概念,访问数据的存取方法,表之间的连接等内容.     并有总结和概述,便于理解与记忆! +++ 目录 ---     一.相关的概念    ...

  8. Wcf for wp8 使用iis Express 承载Wcf服务部署发布网站(三)

    我们接下来要做的是 本地电脑当作服务器(模拟外网服务器)来承载Wcf服务程序,通过引用本地电脑ip地址访问wcf服务程序接口 http://192.168.1.123/Service1.svc 一.先 ...

  9. String 和 document 的相互转换总结

    转自:http://blog.sina.com.cn/s/blog_7f865faf01014qrs.html 一.使用最原始的javax.xml.parsers,标准的jdk api // 字符串转 ...

  10. 关于android LinearLayout的比例布局(转载)

    关于android LinearLayout的比例布局,主要有以下三个属性需要设置: 1,android:layout_width,android:layout_height,android:layo ...