QT开发(二十一)——QT布局管理器
一、布局管理器简介
QT中使用绝对定位的布局方式无法自适应窗口的变化。
QT中提供了对界面组件进行布局管理的类,用于对界面组件进行管理,能够自动排列窗口中的界面组件,窗口大小变化后自动更新界面组件的大小。
QLayout是QT中布局管理器的抽象基类,通过对QLayout的继承,实现了功能各异且互补的布局管理器。
布局管理器不是界面组件,而是界面组件的定位策略。
任意容器类型的组件都可以指定布局管理器。
同一个布局管理器管理中的组件拥有相同的父组件,在设置布局管理器的同时已经隐式指定了父子关系。
二、QBoxLayout布局管理器
QBoxLayout以垂直或水平的方式管理界面组件。
QBoxLayout有两个子类:QHBoxLayout和QVBoxLayput。
1、QBoxLayout使用
A、QVBoxLayout使用
void Widget::VBoxLayout(){ QVBoxLayout *vLayout = new QVBoxLayout(); //设置组件间隔 vLayout->setSpacing(20); //设置组件的标签 button1.setText("button1"); button2.setText("button2"); button3.setText("button3"); button4.setText("button4"); //设置每个组件的尺寸策略 button1.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); button2.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); button3.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); button4.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); //设置组件的最小尺寸 button1.setMinimumSize(60,30); button2.setMinimumSize(60,30); button3.setMinimumSize(60,30); button4.setMinimumSize(60,30); //添加组件到布局管理器 vLayout->addWidget(&button1); vLayout->addWidget(&button2); vLayout->addWidget(&button3); vLayout->addWidget(&button4); //设置窗口的布局管理器 setLayout(vLayout);}
B、QHBoxLayout使用
void Widget::HBoxLayout(){ QHBoxLayout *hLayout = new QHBoxLayout(); //设置组件间隔 hLayout->setSpacing(20); //设置组件的标签 button1.setText("button1"); button2.setText("button2"); button3.setText("button3"); button4.setText("button4"); //设置每个组件的尺寸策略 button1.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); button2.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); button3.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); button4.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); //设置组件的最小尺寸 button1.setMinimumSize(60,30); button2.setMinimumSize(60,30); button3.setMinimumSize(60,30); button4.setMinimumSize(60,30); //添加组件到布局管理器 hLayout->addWidget(&button1); hLayout->addWidget(&button2); hLayout->addWidget(&button3); hLayout->addWidget(&button4); //设置窗口的布局管理器 setLayout(hLayout);}
2、QBoxLayout嵌套使用
布局管理器可以相互嵌套,形成复杂的布局管理方式。
QBoxLayout布局管理器的嵌套使用实例如下:
void Widget::HVBoxLayout(){ QHBoxLayout *hLayout1 = new QHBoxLayout(); QHBoxLayout *hLayout2 = new QHBoxLayout(); //button1、buuton2使用水平布局管理器hLayout1管理 hLayout1->setSpacing(20); button1.setText("button1"); button2.setText("button2"); button1.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); button2.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); button1.setMinimumSize(60,30); button2.setMinimumSize(60,30); hLayout1->addWidget(&button1); hLayout1->addWidget(&button2); //button3、buuton4使用水平布局管理器hLayout2管理 hLayout2->setSpacing(20); button3.setText("button3"); button4.setText("button4"); button3.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); button4.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); button3.setMinimumSize(60,30); button4.setMinimumSize(60,30); hLayout2->addWidget(&button3); hLayout2->addWidget(&button4); //水平布局管理器hLayout1、hLayout2使用垂直布局管理器vLayout管理 QVBoxLayout *vLayout = new QVBoxLayout(); vLayout->setSpacing(20); vLayout->addLayout(hLayout1); vLayout->addLayout(hLayout2); //设置窗口的布局管理器为vLayout setLayout(vLayout);}
3、QBoxLayout布局管理器比例系数设置
QBoxLayout中比例系数的设置:
void (int index, int stretch)
bool (QWidget * widget, int stretch)
bool (QLayout * layout, int stretch)
vLayout->setStretch(0,1);
vLayout->setStretch(1,0.5);
vLayout->setStretch(2,1);
vLayout->setStretch(3,2);
vLayout->setStretchFactor(&button1, 1);
vLayout->setStretchFactor(&button2, 1);
vLayout->setStretchFactor(hLayout1, 1);
vLayout->setStretchFactor(hLayout2, 2);
界面组件的初始大小是独立于布局管理器设置的,比例系数只有在窗口变化的时候才会生效。
三、QGridLayout布局管理器
QGridLayout布局管理器以网格的方式管理界面组件。
QGridLayout布局管理器比例系数设置函数:
void (int column, int stretch)
void (int row, int stretch)
1、QGridLayout布局管理器使用
void Widget::GridLayout(){ QGridLayout *gLayout = new QGridLayout(); //设置组件间隔 gLayout->setSpacing(20); //设置组件的标签 button1.setText("button1"); button2.setText("button2"); button3.setText("button3"); button4.setText("button4"); //设置每个组件的尺寸策略 button1.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); button2.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); button3.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); button4.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); //设置组件的最小尺寸 button1.setMinimumSize(60,30); button2.setMinimumSize(60,30); button3.setMinimumSize(60,30); button4.setMinimumSize(60,30); //添加组件到网格布局管理器 gLayout->addWidget(&button1, 0, 0); gLayout->addWidget(&button2, 0, 1); gLayout->addWidget(&button3, 1, 0); gLayout->addWidget(&button4, 1, 1); //设置行和列的比例系数 gLayout->setColumnStretch(0, 1); gLayout->setColumnStretch(1, 2); gLayout->setRowStretch(0, 1); gLayout->setRowStretch(1, 2); //设置窗口的布局管理器 setLayout(gLayout);}
2、界面组件在QGridLayout中跨网格使用
void Widget::HVGridLayout(){ QGridLayout *gLayout = new QGridLayout(); //设置组件间隔 gLayout->setSpacing(20); //设置组件的标签 button1.setText("button1"); button2.setText("button2"); button3.setText("button3"); button4.setText("button4"); //设置每个组件的尺寸策略 button1.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); button2.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); button3.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); button4.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); //设置组件的最小尺寸 button1.setMinimumSize(60,30); button2.setMinimumSize(60,30); button3.setMinimumSize(60,30); button4.setMinimumSize(60,30); //添加组件到网格布局管理器,放置的位置,占用的行和列 gLayout->addWidget(&button1, 0, 0, 1, 1); gLayout->addWidget(&button2, 0, 1, 1, 1); gLayout->addWidget(&button3, 1, 0, 1, 2); gLayout->addWidget(&button4, 2, 0, 3, 1); //设置窗口的布局管理器 setLayout(gLayout);}
QGridLayout布局管理器支持嵌套使用。
四、QFormLayout布局管理器
QFormLayout布局管理器使用表单的方式管理界面组件,表单中的标签和组件是相互对应的关系,支持嵌套使用。
1、QFormLayout布局管理器使用
void (QWidget * label, QWidget * field)
void (QWidget * label, QLayout * field)
void (const QString & labelText, QWidget * field)
void (const QString & labelText, QLayout * field)
void Widget::FormLayout() { //创建组件和表单布局管理器 QLineEdit *nameEdit = new QLineEdit(); QLineEdit *mailEdit = new QLineEdit(); QLineEdit *addrEdit = new QLineEdit(); QFormLayout *fLayout = new QFormLayout(); fLayout->setSpacing(20); fLayout->setLabelAlignment(Qt::AlignRight); //添加组件到表单布局管理器 fLayout->addRow("name:", nameEdit); fLayout->addRow("mail:", mailEdit); fLayout->addRow("addr:", addrEdit); //设置窗口标题 setWindowTitle("FTP"); //设置表单布局管理器到窗口 setLayout(fLayout); }
2、QFormLayout布局管理器嵌套
void Widget::FormLayout() { //创建组件和表单布局管理器 QLineEdit *nameEdit = new QLineEdit(); QLineEdit *mailEdit = new QLineEdit(); QLineEdit *addrEdit1 = new QLineEdit(); QLineEdit *addrEdit2 = new QLineEdit(); QFormLayout *fLayout = new QFormLayout(); //添加addrEdit1、addrEdit2到QVBoxLayout QVBoxLayout *vLayout = new QVBoxLayout(); vLayout->addWidget(addrEdit1); vLayout->addWidget(addrEdit2); vLayout->setSpacing(6); fLayout->setSpacing(20); //添加组件到表单布局管理器 fLayout->addRow("name:", nameEdit); fLayout->addRow("mail:", mailEdit); fLayout->addRow("address:", vLayout); //设置对齐 fLayout->setLabelAlignment(Qt::AlignRight); fLayout->setFormAlignment(Qt::AlignLeft); //设置窗口标题 setWindowTitle("FTP"); //设置表单布局管理器到窗口 setLayout(fLayout); }
3、QFormLayout样式函数
void (RowWrapPolicy policy)
void (Qt::Alignment alignment)
五、QStackedLayout栈式布局管理器
QStackedLayout栈式布局管理器管理的所有组件在垂直于屏幕的方向上,每次只有一个界面组件会显示在屏幕上,只要最顶层的界面组件会被显示。
QStackedLayout栈式布局管理器的特点如下:
A、组件大小一致,且充满父组件的显示区
B、不能直接嵌套其它布局管理器
C、能够自由切换需要显示的组件
D、每次仅能显示一个界面组件
1、QStackedLayout栈式布局管理器使用
void Widget::StackedLayout() { //创建组件并设置显示标签 QPushButton *button1 = new QPushButton(); QPushButton *button2 = new QPushButton(); QPushButton *button3 = new QPushButton(); QPushButton *button4 = new QPushButton(); button1->setText("1st"); button2->setText("2rd"); button3->setText("3th"); button4->setText("4th"); //创建栈式布局管理器并添加组件 QStackedLayout *sLayout = new QStackedLayout(); sLayout->addWidget(button1); sLayout->addWidget(button2); sLayout->addWidget(button3); sLayout->addWidget(button4); //设置当前栈顶显示的组件 sLayout->setCurrentIndex(0); //设置栈式布局管理器到窗口 setLayout(sLayout); }
2、QStackedLayout栈式布局管理器嵌套
QStackedLayout栈式布局管理器不能直接嵌套其他布局管理器,但可以间接嵌套使用其他布局管理器。
void Widget::StackedLayout() { //创建组件并设置显示标签 QPushButton *button1 = new QPushButton(); QPushButton *button2 = new QPushButton(); QPushButton *button3 = new QPushButton(); QPushButton *button4 = new QPushButton(); button1->setText("1st"); button2->setText("2rd"); button3->setText("3th"); button4->setText("4th"); //创建要嵌套的QVBoxLayout布局管理器 QVBoxLayout * vbLayout = new QVBoxLayout(); //创建中间对象并将需要嵌套布局管理管理的组件的父组件设置为中间对象 QWidget * qwidget = new QWidget(); button2->setParent(qwidget); button3->setParent(qwidget); //设置组件的QVBoxLayout布局管理器 vbLayout->addWidget(button2); vbLayout->addWidget(button3); //设置中间对象的布局管理器为要嵌套的QVBoxLayout布局管理器 qwidget->setLayout(vbLayout); //创建栈式布局管理器并添加组件 QStackedLayout *sLayout = new QStackedLayout(); sLayout->addWidget(button1); sLayout->addWidget(qwidget); sLayout->addWidget(button4); //设置当前栈顶显示的组件 sLayout->setCurrentIndex(1); //设置栈式布局管理器到窗口 setLayout(sLayout); }
3、QStackedLayout实用函数
int (QWidget * widget)
QWidget *() const
void (int index)
int () const
六、QTimer计时器
QT中提供了预定义的定时器类QTimer,用于每隔一定时间触发一个消息,触发的计时器消息会被转化为函数调用。
QTimer的使用如下:
A、编写计时器消息处理函数
B、创建计时器对象
C、连接计时器消息和消息处理函数
D、设置计时器计时间隔并启动计时器
void Widget::StackedLayout() { //创建组件并设置显示标签 QPushButton *button1 = new QPushButton(); QPushButton *button2 = new QPushButton(); QPushButton *button3 = new QPushButton(); QPushButton *button4 = new QPushButton(); button1->setText("1st"); button2->setText("2rd"); button3->setText("3th"); button4->setText("4th"); //创建要嵌套的QVBoxLayout布局管理器 QVBoxLayout * vbLayout = new QVBoxLayout(); //创建中间对象并将需要嵌套布局管理管理的组件的父组件设置为中间对象 QWidget * qwidget = new QWidget(); button2->setParent(qwidget); button3->setParent(qwidget); //设置组件的QVBoxLayout布局管理器 vbLayout->addWidget(button2); vbLayout->addWidget(button3); //设置中间对象的布局管理器为要嵌套的QVBoxLayout布局管理器 qwidget->setLayout(vbLayout); //创建栈式布局管理器并添加组件 QStackedLayout *sLayout = new QStackedLayout(); sLayout->addWidget(button1); sLayout->addWidget(qwidget); sLayout->addWidget(button4); //设置当前栈顶显示的组件 sLayout->setCurrentIndex(1); //设置栈式布局管理器到窗口 setLayout(sLayout); //创建QTimer对象 QTimer *timer = new QTimer(this); //绑定定时器消息到消息处理函数 connect(timer, SIGNAL(timeout()), this, SLOT(timer())); //启动定时器,设定间隔 timer->start(2000); }//定时器消息处理函数 void Widget::timer() { //获取当前窗口布局管理器并转换为栈式布局管理器 QStackedLayout *sLayout = dynamic_cast(layout()); if(sLayout != NULL) { int index = (sLayout->currentIndex() + 1) % sLayout->count(); //设置栈顶显示的组件 sLayout->setCurrentIndex(index); } }
七、布局管理器综合实例
用户向导界面开发需求:
A、在同一个界面显示不同的向导页面
B、通过上一步和下一步按钮进行页面切换
界面设计:
栈式布局管理器显示不同页面
Widget.h源码:
#ifndef WIDGET_H#define WIDGET_H#include#include #include #include #include class Widget : public QWidget{ Q_OBJECT private: QPushButton preButton; QPushButton nextButton; QStackedLayout sLayout;//第一页组件private: QLabel label1; QLabel label2; QLabel label3; QLabel label4;//第二页组件private: QLineEdit edit;//第三页组件private: QPushButton button1; QPushButton button2; QPushButton button3; QPushButton button4;private: QWidget * get1stPage(); QWidget * get2ndPage(); QWidget * get3rdPage();private slots: void pre(); void next();public: Widget(QWidget *parent = 0); ~Widget();};#endif // WIDGET_H
Widget.cpp源码:
#include "Widget.h"#include#include #include #include Widget::Widget(QWidget *parent) : QWidget(parent){ QVBoxLayout* vbLayout = new QVBoxLayout(); QHBoxLayout* hbLayout = new QHBoxLayout(); preButton.setText("Pre"); preButton.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); preButton.setMinimumSize(80, 30); nextButton.setText("Next"); nextButton.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); nextButton.setMinimumSize(80, 30); connect(&preButton, SIGNAL(clicked()), this, SLOT(pre())); connect(&nextButton, SIGNAL(clicked()), this, SLOT(next())); hbLayout->addWidget(&preButton); hbLayout->addWidget(&nextButton); sLayout.addWidget(get1stPage()); sLayout.addWidget(get2ndPage()); sLayout.addWidget(get3rdPage()); vbLayout->addLayout(&sLayout); vbLayout->addLayout(hbLayout); setLayout(vbLayout);}Widget::~Widget(){ }QWidget * Widget::get1stPage(){ QWidget * ret = new QWidget(); QGridLayout *gLayout = new QGridLayout(); label1.setText("Hello"); label2.setText("word"); label3.setText("This is"); label4.setText("1st page"); gLayout->addWidget(&label1, 0, 0); gLayout->addWidget(&label2, 0, 1); gLayout->addWidget(&label3, 1, 0, 1, 2); gLayout->addWidget(&label4, 2, 0, 1, 2); ret->setLayout(gLayout); return ret;}QWidget * Widget::get2ndPage(){ QWidget * ret = new QWidget(); QFormLayout *fLayout = new QFormLayout(); fLayout->addRow("username:", &edit); edit.setText("hello world"); ret->setLayout(fLayout); return ret;}QWidget * Widget::get3rdPage(){ QWidget * ret = new QWidget(); QVBoxLayout *vbLayout = new QVBoxLayout(); button1.setText("hello"); button2.setText("world"); button3.setText("3rd"); button4.setText("page"); vbLayout->addWidget(&button1); vbLayout->addWidget(&button2); vbLayout->addWidget(&button3); vbLayout->addWidget(&button4); ret->setLayout(vbLayout); return ret;}void Widget::pre(){ int index = ((sLayout.currentIndex() - 1) + 3) % 3; sLayout.setCurrentIndex(index);}void Widget::next(){ int index = (sLayout.currentIndex() + 1) % 3; sLayout.setCurrentIndex(index);}