Qt第一章的最后一个内容是部件的布局。
书中的例子用到了一个QHBoxLayout类
这个类能够将放置在布局内的控件自动调整大小和位置,我们不需要手动去调整,比较方便。
第10行:创建一个QWidget对象
QWidget是所有用户界面对象的基类。在这里将会用作其它部件的父对象,在这之上显示相应的控件。也就是说它将作为程序的主窗口。
第11行:设置窗口标题
字面意思上看也的确是设置窗口的标题。
第13行:创建一个QSpinBox对象
用到的函数:QSpinBox::QSpinBox ( QWidget * parent = 0 )
函数的说明:构造一个微调框,默认最小值为0,最大值值为99,初始值为0。
第14行:创建一个QSlider对象
用到的函数:QSlider::QSlider ( Qt::Orientation orientation, QWidget * parent = 0 )
函数的说明:构造一个滑块,并指定滑块方向,Qt::Vertical为垂直方向,Qt::Horizontal为水平方向。
第15~16行:设置有效范围
QSpinBox用到的函数:void QSpinBox::setRange ( intminimum, intmaximum )
QSlider用到的函数:void QAbstractSlider::setRange ( intmin, intmax )
函数的说明:设置微调框和滑块的有效范围,设置完成之后,在实际使用中是不会超过这个范围的,微调框自己手动输入一个非法值也不会被正常输入,这也确保了数值的有效性。
第18~21行:设置信号和槽的连接
QSpinBox和QSlider都拥有一个valueChanged(int)信号,表明当数值发生改变时会发射valueChanged信号。
同时它们也都拥有一个setValue(int)槽。
将QSpinBox的valueChanged信号和QSlider的setValue槽连接之后,当QSpinBox的数值发生改变,QSlider的值也将随之改变。
同理,就可以理解另外一个连接会发生的事情了。
另外,这里可能有一个疑问:微调框的值发生改变,它会调用滑块的setValue来设置滑块的值,这样一来滑块的值也发生改变,滑块也会调用微调框的setValue来设置微调框……如此反复,似乎感觉这样子会出现死循环…?
也不知道是不是我初学的关系,不知道其它人会不会呢?我学到这里的时候就有这个疑问了。后来书中也解释过了,并不会出现这种死循环的局面。
所以,需要知道的是对象何时会发射信号,它是有条件的。微调框发射valueChanged信号的条件是:当数值已经改变。
假如数值改变了,它会发射信号,由滑块响应并调用setValue槽来改变自身的值,这时它的值"改变了",但是这里的改变只是"替换"成微调框新的值。
如果这个新的值与滑块原本已有的值是一样的,这就不叫改变了。所以滑块的值保持原样,并不符合数值已经改变这个条件,不会再次发射信号。
一个疑问就这样解开了,它不会造成死循环。
第22行:设置QSpinBox的值
由于已经将信号和槽进行连接了,所以在连接之后进行设置值的话,就会发射信号,相应地会有槽在执行,把QSlider的值设置为和QSpinBox一样的数值。
第24行:创建一个QHBoxLayout对象
用到的函数:QHBoxLayout::QHBoxLayout ()
函数的说明:创建一个水平布局管理器,管理各个控件位置和大小。
第25~26行:将部件添加到水平布局对象中
用到的函数:void QBoxLayout::addWidget ( QWidget * widget, intstretch = 0, Qt::Alignmentalignment = 0 )
函数的说明:将部件添加到布局中,并调整布局内各个控件的大小与位置。
第27行:在主窗口上设置布局管理器
用到的函数:void QWidget::setLayout ( QLayout * layout )
函数的说明:设置布局管理器为这个部件的布局。
最后自然就是将主窗口show()出来了
无论怎样调整窗口的宽度,微调框和滑块都会自动调整大小,的确是个很方便的东西。
接下来比较详细讲的就是布局管理器了:
布局管理器就是一个能够对其所负责窗口部件的尺寸大小和位置进行设置的对象。
Qt中有三个主要的布局管理器类:
QHBoxLayout:在水平方向上排列窗口部件,从左到右。头文件<QHBoxLayout>。
QVBoxLayout:在竖直方向上排列窗口部件,从上到下。头文件<QVBoxLayout>。
QGridLayout:把各个窗口部件排列在一个网格中。头文件<QGridLayout>。
QHBoxLayout,水平布局管理器,就是这样子:
QVBoxLayout,竖直布局管理器,就是这样子:
QGridLayout,网格布局管理器,就是这样子:
用到的函数:void QGridLayout::addWidget ( QWidget * widget, introw, intcolumn, Qt::Alignmentalignment = 0 )
函数的说明:widget指定要添加到布局管理器的对象。row和column为对象放置的位置。
QGridLayout将各个部件都添加到网格中,就像是表格,可以指定部件放在表格的哪一行哪一列。这也是一样的。
这三种布局管理器可以嵌套,可以做出一个很好看的布局。
结合C++的知识与之前所学过的Qt知识,我来随便弄一个界面吧~
#include <QApplication> #include <QPushButton> #include <QLineEdit> #include <QSlider> #include <QSpinBox> #include <QLabel> #include <QLayout> // 包含了<QLayout>就可以不用再包含以下3个头文件了 /* #include <QHBoxLayout> #include <QVBoxLayout> #include <QGridLayout> */ enum LAYOUT_TYPE { layout_H, // QHBoxLayout layout_V, // QVBoxLayout layout_G // QGridLayout }; QLayout * getLayout(LAYOUT_TYPE type); int main(int argc, char * argv[]) { QApplication app(argc, argv); QWidget * window = new QWidget; window->setWindowTitle("Hello Qt!"); /***************** 设置顶部菜单选项 ******************/ QHBoxLayout * Top = (QHBoxLayout *)getLayout(layout_H); QPushButton * btn_Menu1 = new QPushButton("Start"); QPushButton * btn_Menu2 = new QPushButton("Online"); QPushButton * btn_Menu3 = new QPushButton("Setting"); QPushButton * btn_Menu4 = new QPushButton("Exit"); Top->addWidget(btn_Menu1); Top->addWidget(btn_Menu2); Top->addWidget(btn_Menu3); Top->addWidget(btn_Menu4); /***************** 设置中部左边部件 ******************/ QVBoxLayout * midLeft = (QVBoxLayout *)getLayout(layout_V); QHBoxLayout * midLeftLayout1 = (QHBoxLayout *)getLayout(layout_H); QLabel * tip1 = new QLabel("Sound Volume"); // 可以手动设置QSlider的方向,Horizontal是水平,Vertical是垂直 QSlider * slider1 = new QSlider(Qt::Horizontal); slider1->setRange(0, 100); slider1->setValue(50); midLeftLayout1->addWidget(tip1); midLeftLayout1->addWidget(slider1); QHBoxLayout * midLeftLayout2 = (QHBoxLayout *)getLayout(layout_H); QLabel * tip2 = new QLabel("Sound Effect "); QSlider * slider2 = new QSlider(Qt::Horizontal); slider2->setRange(0, 100); slider2->setValue(50); midLeftLayout2->addWidget(tip2); midLeftLayout2->addWidget(slider2); midLeft->addLayout(midLeftLayout1); midLeft->addLayout(midLeftLayout2); /***************** 设置中部右边部件 ******************/ QVBoxLayout * midRight = (QVBoxLayout *)getLayout(layout_V); QHBoxLayout * midRightLayout1 = (QHBoxLayout *)getLayout(layout_H); QLabel * tip3 = new QLabel("Game Levels"); QSpinBox * spinBox = new QSpinBox(); spinBox->setRange(1, 10); spinBox->setValue(1); midRightLayout1->addWidget(tip3); midRightLayout1->addWidget(spinBox); QHBoxLayout * midRightLayout2 = (QHBoxLayout *)getLayout(layout_H); QLabel * tip4 = new QLabel("Player Name"); QLineEdit * Edit = new QLineEdit(); midRightLayout2->addWidget(tip4); midRightLayout2->addWidget(Edit); midRight->addLayout(midRightLayout1); midRight->addLayout(midRightLayout2); // 将中部左右边的布局管理器添加到中部主布局管理器中 QHBoxLayout * Mid = (QHBoxLayout *)getLayout(layout_H); Mid->addLayout(midLeft); Mid->addLayout(midRight); /***************** 设置底部部件 ******************/ QHBoxLayout * Bottom = (QHBoxLayout *)getLayout(layout_H); QLabel * lab = new QLabel("All right reserved."); // addStretch()用于添加分隔符,用于占位 // 就是已有的部件大小已确定为最佳的情况下, // 添加分隔符可以将多余的空位占用掉,以免部件调整自身大小以占用所有空位 // 在lab的前后加上addStretch()可以使得lab居中哦~ Bottom->addStretch(); Bottom->addWidget(lab); Bottom->addStretch(); /***************** 设置主布局管理器 ******************/ QVBoxLayout * mainLayout = (QVBoxLayout *)getLayout(layout_V); mainLayout->addLayout(Top); mainLayout->addLayout(Mid); mainLayout->addLayout(Bottom); window->setLayout(mainLayout); window->show(); return app.exec(); } QLayout * getLayout(LAYOUT_TYPE type) { QLayout * Layout; switch (type) { case layout_H: Layout = new QHBoxLayout; break; case layout_V: Layout = new QVBoxLayout; break; case layout_G: Layout = new QGridLayout; break; } return Layout; }
好吧,就总结到这里~