QSplitter(分离器或分隔符)
本文为原创文章,转载请注明出处,或注明转载自“黄邦勇帅(原名:黄勇)
本文出自本人原创著作《Qt5.10 GUI完全参考手册》网盘地址:
https://pan.baidu.com/s/1iqagt4SEC8PUYx6t3ku39Q
《C++语法详解》网盘地址:https://pan.baidu.com/s/1dIxLMN5b91zpJN2sZv1MNg
若对C++语法不熟悉,建议参阅本人所著《C++语法详解》一书,电子工业出版社出版,该书语法示例短小精悍,对查阅C++知识点相当方便,并对语法原理进行了透彻、深入详细的讲解,可确保读者彻底弄懂C++的原理,彻底解惑C++,使其知其然更知其所以然。此书是一本全面了解C++不可多得的案头必备图书。
5.4.1 QSplitter类(分离器)
QSplitter类继承自QFrame类,也就是说该类是一个带有边框的可视部件。QSplitter类实现了分离器,分离器用于分离两个部件(原理见图5-39),用户可通过拖动部件之间的分界线来调整子部件的大小。
QSplitter的实现原理(见图5-39)与QBoxLayout布局的原理类似,即QSplitter把子部件以水平或垂直的方式添加到QSplitter中,只不过在这些子部件之间多了一条分界线,另外QSplitter继承自QFrmae,因此QSplitter是有边框的。而且它可以作为容器和窗口使用,但不推荐使用QPushButton pb(&splitter)的形式向QSplitter中添加子部件。
动态调整是指移动分界线时部件大小随之动态的改变。若不是动态调整的,则在移动分界线时部件大小不会改变,当完成分界线的移动时(即松开鼠标时),部件的大小才改变。
分离器中的子部件会随着分离器大小的改变而改变,当分离器大小改变时,分离器会重新分配空间,以使其所有子部件的相对大小保持相同的比例不变。
子部件的大小策略对分离器不起作用,分离器会把子部件填充满整个空间,即使子部件的大小策略设置为Fixed,仍会被拉伸。
1、分界线(QSplitterHandle类)
分界线是由QSplitterHandle类实现的,QSplitter类本身不实现分界线。因此QSplitterHandle是一个部件,而QSplitter是另一个部件,这是两个部件,只不过这两个部件通过Qt的内部设计让他们关联在一起,产生了一定的联系。
QSplitter的分界线默认有可能是看不见的(因为颜色与QSplitter背景色相同,所以看不见),因此要使分界线可见,需设置分界线的背景色。
分界线的索引从0开始编号,分界线的数量与子部件的数量一样多。但索引为0的分界线始终是隐藏的。对于垂直分离器,索引为0的子部件上方的分界线索引为0,对于水平分离器(对于从左到右的语言),则索引为0的子部件左侧的分界线的索引为0,对于从右到左的语言,则索引为0的子部件右侧的分界线的索引为0。
2、使用QSplitter的步骤如下:
①、创建一个QSplitter。
②、使用addWidget()函数把子部件添加到QSplitter中。
③、代码如下:
3、QSplitter类的属性
4、QSplitter类的函数
示例5.18:QSplitter类(分离器)的使用
#include<QtWidgets>
int main(int argc, char *argv[]){ QApplication a(argc,argv);
QWidget w; QSplitter *ps=new QSplitter(Qt::Vertical);
QPushButton *pb=new QPushButton("AAA"); QPushButton *pb1=new QPushButton("BBB");
QPushButton *pb2=new QPushButton("CCC");
QPushButton *pb3=new QPushButton("DDD",ps); //不推荐此种方式向分离器中添加子部件
pb1->setSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); //大小策略不起作用
pb->setMaximumSize(175,55); //最大最小值仍可限制子部件
ps->addWidget(pb); ps->addWidget(pb1); ps->addWidget(pb2);
ps->addWidget(pb3); //pb3已在分离器ps中,因此把pb3移至新位置
//设置分离器的边框
ps->setFrameShadow(QFrame::Raised); ps->setFrameShape(QFrame::Box); ps->setLineWidth(5);
ps->setChildrenCollapsible(0); //子部件不可折叠
ps->setOpaqueResize(1); //动态调整子部件
ps->setStretchFactor(0,1); //设置拉伸因子,以调整初始显示时各子部件间的位置
ps->setStretchFactor(1,2); ps->setStretchFactor(2,2);
ps->setHandleWidth(5); //设置分界线的宽度
//设置分界线的背景色为蓝色,若不设置背景色,则分界线可能会不可见
ps->setStyleSheet("QSplitter::handle{background-color: blue}"); //样式表见第13章
QVBoxLayout *pv=new QVBoxLayout; pv->addWidget(ps); //把分离器ps添加到布局pv中
w.setLayout(pv); w.resize(300,200); w.show(); return a.exec(); }
运行结果及说明见图5-41
示例5.19:QSplitter综合示例(设计的界要和要求见图5-42)
//m.h文件的内容
#ifndef M_H
#define M_H
#include<QtWidgets>
#include <iostream>
using namespace std;
class B:public QSplitter{ Q_OBJECT
public: static QString ddd; //用于存储来自行编辑器输入的文本
B(Qt::Orientation o=Qt::Horizontal,QWidget* p=0):QSplitter(o,p){}
public slots:
void f(){ int j=0; //计数器
int i[3]={0}; //用于存储从文本ddd中提出取来的数字。
QString s1=ddd;
while(!s1.isEmpty()){ s1=ddd.section(",",j,j); //提取文本中以","分隔的数字
if(j>2)return; //如果文本中的数字个数大于等于3个,则退出函数。
i[j]=s1.toInt(); //把提取出来的数字赋值给数组i。
j++;}
moveSplitter(i[0],i[1]); } }; /*使用文本中输入的前两个数字设置分界线的位置。注意:这个函数是受保护的,若索引(第二个参数)超出范围,该函数会产生错误。*/
class C:public QWidget{ Q_OBJECT
public: B *ps; //分离器
QLineEdit *pe,*pe1; QLabel *pl,*pl1; QPushButton *pb,*pb1,*pb2,*pb3,*pb4,*pb5;
QByteArray b; //用于保存和恢复分离器的状态
C(QWidget* p=0):QWidget(p){ //构造函数
ps=new B(Qt::Vertical); pl=new QLabel("EnterSize"); pl1=new QLabel("pose,index");
pe=new QLineEdit; pe1=new QLineEdit;
pe->setClearButtonEnabled(1); pe1->setClearButtonEnabled(1);//显示行编辑器的清除按钮
pb=new QPushButton("AAA"); pb1=new QPushButton("BBB"); pb2=new QPushButton("CCC");
pb3=new QPushButton("save"); pb4=new QPushButton("restore");
//布置分离器ps的子部件。
ps->addWidget(pb); ps->addWidget(pb1); ps->addWidget(pb2);
//设置分离器的边框及其他属性
ps->setFrameShadow(QFrame::Raised); ps->setFrameShape(QFrame::Box);
ps->setLineWidth(5); ps->setChildrenCollapsible(0);
//设置分离器的边框样式后,重新设置分离器的大小策略,否则分离器可能不会扩展。
ps->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
//设置分界线的背景色为蓝色,若不设置背景色,则分界线可能会不可见
ps->setHandleWidth(5); ps->setStyleSheet("QSplitter::handle{background-color: blue}");
//布置主窗口的子部件
QVBoxLayout *pv=new QVBoxLayout; //主窗口使用的主布局
QFormLayout *pf=new QFormLayout; pf->addRow(pl,pe); pf->addRow(pl1,pe1);
QHBoxLayout *ph=new QHBoxLayout; ph->addWidget(pb3); ph->addWidget(pb4);
//把布局pf,ph和分离器,添加到主布局中
pv->addLayout(ph); pv->addLayout(pf); pv->addWidget(ps); setLayout(pv);
QObject::connect(pe, &QLineEdit::returnPressed, this, &C::fSet);
QObject::connect(pb3, &QPushButton::clicked, this, &C::fSave);
QObject::connect(pb4, &QPushButton::clicked, this, &C::fRestore);
QObject::connect(pe1, &QLineEdit::returnPressed, this, &C::f);
QObject::connect(pe1, &QLineEdit::returnPressed, ps, &B::f); } //构造函数结束
public slots:
void fSet(){ //使用setSizes函数设置分离器各子部件的大小
QString ss=pe->text(); //获取行编辑器pe的文本
int j=0; //计数器
QString s1=ss;
QList<int> b; //使用列表存储从文本ss中提取出来的数字
while(!s1.isEmpty()){
s1=ss.section(",",j,j); //提取以","分隔的数字。
b.append(s1.toInt()); //把提取出来的数字追到加列表b的末尾。
j++; }
if(b.size()<=3) return; //如果输入的数字个数少于3个,则退出函数。
ps->setSizes(b); } //使用列表b设置各分离器子部件的位置
void fSave(){ b=ps->saveState(); cout<<"save OK"<<endl;} //保存分离器的状态。
void fRestore(){ ps->restoreState(b); } //恢复分离器的状态
void f(){ B::ddd=pe1->text(); }}; //把行编辑器pe1输入的内容存储到静态变量B::ddd中
#endif // M_H
//m.cpp文件的内容
#include "m.h"
QString B::ddd; //初始化静态变量,注意:静态变量不应在头文件中初始化,否则会出现重定义错误。
int main(int argc, char *argv[]){ QApplication a(argc,argv);
C w; w.resize(300,500); w.show(); return a.exec(); }
运行结果及说明见图5-42
示例5.20:QSplitter的嵌套使用(实现的界面如图5-43所示)
#include
int main(int argc, char *argv[]){
QApplication a(argc,argv);
QWidget w;
QSplitter *ps=new QSplitter(Qt::Vertical);
QSplitter *ps1=new QSplitter(Qt::Vertical);
QSplitter *ps2=new QSplitter(Qt::Horizontal);
QTextEdit *pt=new QTextEdit;
QTextEdit *pt1=new QTextEdit;
QTextEdit *pt2=new QTextEdit;
//设置分界线的背景色及边框
ps->setHandleWidth(1); ps->setStyleSheet("QSplitter::handle{background-color: blue}");
ps2->setFrameShadow(QFrame::Raised); ps2->setFrameShape(QFrame::Box);
ps2->setLineWidth(2); ps2->setHandleWidth(5);
ps2->setStyleSheet("QSplitter::handle{background-color: red}");
//布局子部件
ps->addWidget(pt); ps->addWidget(pt1); ps1->addWidget(pt2);
ps2->addWidget(ps1); ps2->addWidget(ps);
QHBoxLayout *ph=new QHBoxLayout; ph->addWidget(ps2); w.setLayout(ph);
w.resize(300,200); w.show(); return a.exec(); }
5.4.2 QSplitterHandle类(分界线)
QSplitterHandle类继承自QWidget,该类主要用于实现QSplitter(分离器)的分界线,因此,通常与分离器一起使用。该类的规则请参阅QSplitter类。
QSplitterHandle类比较简单,只有如下几个公有函数
示例5.21:QSplitterHandle(分界线)的使用
//m.h文件的内容
#ifndef M_H
#define M_H
#include<QtWidgets>
class B:public QSplitter{ Q_OBJECT
public: B(Qt::Orientation o=Qt::Horizontal,QWidget* p=0):QSplitter(o,p){}
public slots:
QSplitterHandle *createHandle(){ //重新实现该虚函数,创建自定义的分界线
QSplitterHandle *ph=new QSplitterHandle(orientation(),this); //自定义的分界线
ph->setMinimumSize(22,22); //设计分界线的最小大小
return ph; }}; //返回自定义的分界线
#endif // M_H
//m.cpp文件的内容
#include "m.h"
int main(int argc, char *argv[]){ QApplication a(argc,argv);
QWidget w; B *ps=new B(Qt::Vertical);
QPushButton *pb=new QPushButton("AAA"); QPushButton *pb1=new QPushButton("BBB");
QPushButton *pb2=new QPushButton("CCC");
ps->addWidget(pb); ps->addWidget(pb1); ps->addWidget(pb2);
ps->setStyleSheet("QSplitter::handle{background-color: red}"); //设置分界线的颜色(红色)
QHBoxLayout *ph=new QHBoxLayout; ph->addWidget(ps); w.setLayout(ph);
w.resize(300,200); w.show(); return a.exec(); }
运行结果及说明见图5-44
作者:黄邦勇帅(原名:黄勇)