鱼C论坛

 找回密码
 立即注册

小白的Qt自学(4) 界面中组件布局

已有 979 次阅读2014-3-16 17:00 |个人分类:Qt自学

在MFC当中会有组件定位的技术,当然QT也是一样的。其中有绝对定位和布局定位。

绝对定位就是使用最原始的定位方法,给出这个组件在窗口的坐标和长宽值。这样,QT就自动把组件放到哪里,以及怎么设置组件的大小了。不过这么样是存在弊端的,如果用户改变了窗口大小,比如点击了最大化或者拖动宽口边缘改动窗口大小后,就需要我们自己去编写响应函数去改变控件大小,用来避免那些组件不随着窗口改变大小,除非你想要使用固定大小的窗口,但一般不会使用不会变换的窗口的哦~。

QT提供了另外一种机制,叫做布局,就是用来解决这个问题的。只要我们把相应的组件放入某一种布局之中,当需要我们调整大小或者位置的时候,QT就自己知道怎么进行调整了。MFC当中有自己的消息进行维护,QT就不用这么麻烦,都给我们封装好了,而且也是有限的几个,比较好操作。

来看一段代码:


在上段代码中出现了几个的组件:QSpinBox 和 QSlider,一个顶级窗口 QWidget。 QSpinBox 是一个有箭头的微调器, QSlider 是一个滑动杆,看不懂只要运行一下就知道什么意思了。

这里我们先看代码的18、19行,简单介绍一下,这是Qt最为引以自豪的信号槽机制,所谓信号槽,就像是插销一样:一个插头和一个插座。就是当发生一个事情后,比如用鼠标左键点击了一下控件,这是这个组件就会发出一个信号。这个就是插头,这个时候如果有一个槽,正好对应上了这个信号(插头),那么这个槽函数就会执行,也就是回调。就像MFC当中的消息机制一样。
18、19行myWidget是QObject类型,QObject是所有类的根。QT使用这个QObject实现一个单根继承的C++。它里面有一个 connect 静态函数,用于连接信号槽。当我们对QSpinBox和QSlider进行操作的时候,他们就会发出一个 valueChanged(int)信号,意思就是说向周围的组件声明:我获取了数据(int类型的)!很多别的控件当然不会去理睬它们的举动。如果对它们感兴趣,就告诉QObject的myOjbect对象说,你帮我盯着点,只要控件发出valueChanged信号,你就告诉我,但是很繁琐,所以直接让它们告诉某某某函数算了!就这样,一个信号槽就形成了。比如我们上面的例子QObject的实例myWidget来说,如果上面的spinBox控件发出了valueChanged信号,那么就会让slider去执行setValue函数,所以当我们对spinBox进行操作的时候,slider的setValue函数被调用。所以,这里valueChanged()就是一个信号,而setValue()就是一个槽,形象地说就是把这个信号插进这个槽里面去了。这里只做到理解槽的基本用法就行了。还是重点看看布局吧。

上面的代码并不难懂,我们一起简单的看一下。首先创建了一个QWidget的实例,调用setWindowTitle函数来设置窗口标题。然后创建了一个QSpinBox和QSlider,分别通过setRange函数设置了他们的范围。然后进行信号槽的连接。上面有提到信号槽的基本知识。然后是一个QHBoxLayout,即使一个水平布局,按照从左到右的顺序进行添加,使用addWidget添加好组件后,调用QWidget的setLayout把QWidget的layout设置为我们定义的myLayout,这样运行下来,程序就完事了。

编译一下看看结果是什么样的:


如果将窗口改变位置的话,我们看下:


虽然我们并没有添加任何代码,但是layout已经知道怎么进行布局了。

我们可能会想,那两个信号槽的连接操作会不会产生无限递归?因为setValue会引发valueChanged信号!可以明确的讲是不会的。这两句实现的具体操作是当spinBox发出valueChanged信号的时候,会回调slider的setValue,以便更新slider的值;而slider发出valueChanged信号的时候,又会回调slider的setValue。但是,如果新的value和旧的value一样的话,是不会发出信号的,没有信号就没有处理,所以是不会出现无线递归的可能的。

举个例子看一下。比如我们操作了 spinBox->setValue(66)执行的时候,首先,spinBox会将自己的值设置为66,这样,它的值与原来不一样了(因为默认的时候值是0),于是它发出了valueChanged信号。slider接收到这个信号,于是回调自己的setValue函数,将它的值也设置成66,它也发出了valueChanged信号。不过此时spinBox受到了这个信息,不过它发现这个发送过来的值和自己的现在的66这个值是一样的,于是它就不再发送信号了,所以信号传递就停止了。

其实我们利用QT的信号槽机制完成了一个数据绑定,使两个组件或者更多组件的状态能够同步变化而设计的。

QT一个有三种主要的layout,分别是:

QHBoxLayout  ——  按照水平方向从左到右布局;
QVBoxlayout   ——  按照竖直方向从上到下布局;
QGridLayout    ——  在一个网络中进行布局,类似于HTML的table。(HTML相关: http://www.w3chtml.com/ )

layout 使用 addWidget 添加组件,使用 addLayout 添加子布局,因此,这就有了多种多样的组合方式。当然布局固定了,但是控件的样子会随着运行平台的不同样子也会不同,这里就不多说了。

主要原因是QT使用的不是原生组件,而是自己绘画模拟的本地组件的样子,所以会根据系统的不同显示出不同的样式来。

PS: 提供一段代码,可以根据屏幕的大小来自动控制窗口的大小 需要在代码的 12 行插入如下:

QDesktopWidget* desktop = QApplication::desktop(); 
        myWidget->resize(QSize( desktop->width()/16*14, desktop->height()/9*7 ));

别忘了因为用到了QDesktopWidget类,所以我们要在开头包含对应的头文件,在第6行加入 :
#include <QtGui/QDesktopWidget>


路过

鸡蛋

鲜花

握手

雷人

评论 (0 个评论)

facelist

您需要登录后才可以评论 登录 | 立即注册

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-5-14 03:31

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

返回顶部