下面我们以一个例子来初步了解Qt的组件定位技术,比如我们想做一个登录窗口,像下图这样,应该怎么做呢?
这还不简单嘛,在窗体上拖两个QLabel,两个QLineEdit,两个QPushButton,不就行了嘛。看起来是可以了,但是如果我们的窗口尺寸大小被改变了,那我们如何控制我们窗体上的控件的摆放始终美观合适呢?接下来让我们来学习一下Qt的布局管理器。
我们新建一个工程叫loginDlg,注意在选择基类的时候选择QDialog,而不是默认的QMainWindow,因为我们的登录窗口是个对话框嘛。
修改dialog.h头文件:
1 #ifndef DIALOG_H 2 #define DIALOG_H 3 4 #include <QtGui/QDialog> 5 6 class QLineEdit; 7 class QLabel; 8 class QPushButton; 9 10 class Dialog : public QDialog 11 { 12 Q_OBJECT 13 14 public: 15 Dialog(QWidget *parent = 0); 16 ~Dialog(); 17 private: 18 QLabel *usrLabel; 19 QLabel *pwdLabel; 20 QLineEdit *usrLineEdit; 21 QLineEdit *pwdLineEdit; 22 QPushButton *loginButton; 23 QPushButton *cancelButton; 24 }; 25 26 #endif // DIALOG_H
首先,声明四个用到的类。这里做的是前向声明,否则的话是编译不过的,因为编译器不知道这些类是否存在。简单来说,所谓前向声明就是告诉编译器,我要用这几个类,而且这几个类存在,你就不要担心它们存不存在的问题啦!
然后是我们的Dialog,继承自QDialog。
下面是一个重要的东西:Q_OBJECT。这是一个宏。凡是定义信号槽的类都必须声明这个宏。
然后是public的构造函数和析构函数声明。
然后在类的私有区(private)声明了指向QLabel,QLineEdit,QPushButton对象的指针成员。
一、水平布局管理器和垂直布局管理器
1.水平布局管理器:QHBoxLayout,按照从左到右的顺序进行添加。
2.垂直布局管理器:QVBoxLayout,安装从上到下的顺序进行添加。
使用addWidget添加好组件后,调用QWidget的setLayout把QWidget的layout设置为我们定义的这个Layout,下面结合代码来解释
dialog.cpp
1 #include "dialog.h" 2 #include <QLabel> 3 #include <QLineEdit> 4 #include <QPushButton> 5 #include <QHBoxLayout> 6 7 Dialog::Dialog(QWidget *parent) 8 : QDialog(parent) 9 { 10 usrLabel=new QLabel("UserName:"); 11 pwdLabel=new QLabel("PassWord:"); 12 usrLineEdit=new QLineEdit(); 13 pwdLineEdit=new QLineEdit(); 14 pwdLineEdit->setEchoMode(QLineEdit::Password); 15 loginButton=new QPushButton("Login"); 16 cancelButton=new QPushButton("Cancel"); 17 18 QHBoxLayout *btnLayout=new QHBoxLayout; 19 btnLayout->addWidget(usrLabel); 20 btnLayout->addWidget(pwdLabel); 21 btnLayout->addWidget(usrLineEdit); 22 btnLayout->addWidget(pwdLineEdit); 23 btnLayout->addWidget(loginButton); 24 btnLayout->addWidget(cancelButton); 25 26 setLayout(btnLayout); 27 } 28 29 Dialog::~Dialog() 30 { 31 32 }
首先包含所需的头文件
第10~16行分别创建了各个对象,调用了QLineEdit的setEchoMode方法设置了pwdLineEdit对象的内容显示方式为QLineEdit::Password,即密码显示方式。
接下来创建了一个水平布局管理器btnLayout,使用addWidget方法将之前创建的控件添加到这个布局管理器上,然后调用setLayout方法将刚刚创建的水平布局管理器添加至主窗体。运行一下:
同样如果使用垂直布局管理器的话,这些控件会从上到下排列
二、网格布局管理器
网格布局管理器:QGridLayout,顾名思义就是将窗体分隔成行和列的网格来进行排列。
1 QGridLayout *gridLayout=new QGridLayout; 2 gridLayout->addWidget(usrLabel,0,0,1,1); 3 gridLayout->addWidget(usrLineEdit,0,1,1,3); 4 gridLayout->addWidget(pwdLabel,1,0,1,1); 5 gridLayout->addWidget(pwdLineEdit,1,1,1,3);
创建一个网格布局管理器QGridLayout并将控件添加到此网格布局管理器中去,此方法参数如下:
void QGridLayout::addWidget ( QWidget * widget, int fromRow, int fromColumn, int rowSpan, int columnSpan, Qt::Alignment alignment = 0 )
第一个参数是指要将哪个组件放到该布局管理器中,第二个参数是行,第三个是列,第四个是行的跨度,第五个参数是列的跨度。如图所示:
addWidget(usrLineEdit,0,1,1,3)此句是说将账户输入框usrLineEdit放在网格布局管理器中第0行第1列中,并且占用1行3列,以此类推。
了解了这些之后,我们将这些布局管理局根据需要嵌套起来就可以实现文章开头的那个登陆界面。
我们先来分析一下刚刚那个窗口究竟用了哪些布局?
从上图可以看出,用户名和密码以及输入框采用的是网格布局管理器,而登录和取消两个按钮采用的是水平布局管理器,最后这两个布局管理器又被添加进了垂直布局管理器,这个不难理解吧?
那接下来就是见证奇迹的时刻~
完整代码如下:
dialog.cpp
1 #include "dialog.h" 2 #include <QLabel> 3 #include <QLineEdit> 4 #include <QPushButton> 5 #include <QGridLayout> 6 #include <QHBoxLayout> 7 #include <QVBoxLayout> 8 9 Dialog::Dialog(QWidget *parent) 10 : QDialog(parent) 11 { 12 //创建各个所需控件 13 usrLabel=new QLabel("UserName:"); 14 pwdLabel=new QLabel("PassWord:"); 15 usrLineEdit=new QLineEdit(); 16 pwdLineEdit=new QLineEdit(); 17 pwdLineEdit->setEchoMode(QLineEdit::Password); 18 loginButton=new QPushButton("Login"); 19 cancelButton=new QPushButton("Cancel"); 20 21 //将用户名和密码标签、用户名和密码输入框添加进网格布局管理器中 22 QGridLayout *gridLayout=new QGridLayout; 23 gridLayout->addWidget(usrLabel,0,0,1,1); 24 gridLayout->addWidget(usrLineEdit,0,1,1,3); 25 gridLayout->addWidget(pwdLabel,1,0,1,1); 26 gridLayout->addWidget(pwdLineEdit,1,1,1,3); 27 28 //将登录和取消按钮添加进水平布局管理器中,并设置水平布局管理器中内部窗口部件的间隔为60 29 QHBoxLayout *btnLayout=new QHBoxLayout; 30 btnLayout->setSpacing(60); 31 btnLayout->addWidget(loginButton); 32 btnLayout->addWidget(cancelButton); 33 34 //创建一个垂直布局管理器,设置它的边框宽带为40 35 QVBoxLayout *dlgLayout=new QVBoxLayout; 36 dlgLayout->setMargin(40); 37 dlgLayout->addLayout(gridLayout); 38 //在dlgLayout对象中加入一个大小为40的Stretch,使gridLayout和btnLayout的默认距离为40 39 dlgLayout->addStretch(40); 40 dlgLayout->addLayout(btnLayout); 41 setLayout(dlgLayout); 42 //添加信号槽连接,使得点击取消按钮程序退出 43 connect(cancelButton,SIGNAL(clicked()),this,SLOT(close())); 44 } 45 46 Dialog::~Dialog() 47 { 48 49 }