QSplitter(分离器或分隔符)

QSplitter(分离器或分隔符)

若对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中。
③、代码如下:

     QSplitter *ps = new QSplitter;    		//创建分离器,默认为水平排列子部件。
        QPushButton *pb, *pb1, *pb2; …..;  	 //创建子部件
        ……	//初始化子部件。
        ps->addwidget(pb); ps->addWidget(pb1);   //把子部件添加到分离器ps中
        …….      //添加其他子部件
ps->setStyleSheet("QSplitter::handle{background-color: blue}");  //使用样式表把QSplitter分界线的背景色设置为某颜色(这样才能使分界线可见),这是一种快速设置所有分界线背景色的方法。

3、QSplitter类的属性

①、childrenCollapsible:bool	访问函数:bool childrenCollapsible() const; void setChildrenCollapsible(bool);
	子部件是否可以被折叠(即调整到0的大小),默认为可折叠。
	若部件可折叠,即使该部件的最小大小(minimumSize())不为零,也可将其大小调整为0。
	设置该属性会作用于所有子部件上,使用函数setCollapsible()可设置单个子部件是否可折叠。
   ②、handleWidth:int	   访问函数:int handleWidth() const;   void setHandleWidth(int);
设置和获取分界线的宽度,默认取决于平台和样式。若设置为0或1,则实际抓取区域会增加到各自部件相重叠的几个像素。
   ③、opaqueResize:bool   访问函数:bool opaqueResize() const; void setOpaqueResize(bool opaque = true);
部件是否动态调整,即分界线是否是不透明的。默认为动态调整(即为true)。
   ④、orientation:Qt::Orientation 访问函数:Qt::Orientation orientation() const;void setOrientation(Qt::Orientation);
获取或设置QSplitter的方向,默认为水平方向,可取值为Qt::Horizontal和Qt::Vertical。

4、QSplitter类的函数

①、QSplitter(QWidget* parent = Q_NULLPTR);		//构造函数
QSplitter(Qt::Orientation orientation , QWidget* parent = Q_NULLPTR);
   ②、void addWidget(QWidget* widget);
       void insertWidget(int index, QWidget* widget);
把widget添加到末尾或插入到指定索引indix处,若widget已在分离器中,则将其移至新位置。注意:分离器会获得部件的所有权。
③、void setCollapsible(int index, bool collapse);
bool isCollapsible(int index) const;
设置或返回索引index处的子部件是否可折叠,要设置所有子部件都可折叠,请设置childrenCollapsible属性。
④、void setStretchFactor(int index, int stretch);		//设置索引为index的子部件的拉伸因子。
⑤、void setSizes(const QList<int>& list);
QList<int> sizes() const;
	使用列表list设置子部件的大小(以像素为单位),其规则为,若分离器是水平的,则使用列表中的值按从左到右的顺序设置每个子部件的宽度。若分离器是垂直的,则使用列表中的值按从上到下的顺序设置子部件的高度。若列表的值过少,则结果未定义,但程序仍能运行。
	若为子部件指定的大小为0,则该子部件将不可见,若指定的值小于子部件的最小大小,则使用最小大小提示的值替换。
	注意:分离器的总体大小不会受到影响,也就是说分离器的大小不会改变,仍是之前那么大,因此,当使用该函数为所有的子部件设置的值小于分离器总体的大小时,则其余多余的空间会根据设置的子部件大小的相对权重,在各子部件之间分配。
	示例:假设分离器为垂直的,且高度为150,共有3个子部件,则
QList<int> q={30,30,30};		ps->setSizes(q);
          设置之后各子部件的高度分别为50,50,50,而不是30,30,30,因为分离器剩余的空间按子部件大小的相对权重,分配给了各个子部件。
⑥、QByteArray saveState() const;
bool restoreState(const QByteArray& sate);
以上函数用于保存和恢复分离器的状态,通常应与QSettings类一起使用,也可单独使用,可以使用这两个函数来存储或恢复分离器的默认状态。
⑦、int count() const;   				//返回分离器中子部件的数量。
⑧、int indexOf(QWidget* widget) const; 	//返回widget在分离器中的索引,该函数也可用于分界线。
⑨、QWidget* widget(int index) const;   	//返回索引index处的子部件。
⑩、QWidget* replaceWidget(int index, QWidget* widget);    //qt5.9
把索引index处的子部件替换为widget,若index有效,且widget不是分离器的子部件,则返回被替换掉的子部件,否则返回null,而不会进行替换,新插入的子部件会继承被替换的子部件的属性(比如大小、可折叠装态等)。注意:widget可能不会被立即设置,需在接收到适到的事件之后才会被设置。
   ⑪、void getRange(int index, int *min, int *max) const;
返回索引为index的分界线的有效范围,并存储在*min和*max中,即获取分界线可以调整大小的范围。
   ⑫、QSplitterHandle* handle(int index) const;   	//返回索引index处的分界线。
⑬、void refresh();   						//更新分离器的状态,通常不需要调用这个函数。
   ⑭、QSplitterHandle* createHandle();   		//虚拟的,受保护的。
把返回的分界线作为分离器的分界线,该函数可在子类中重新实现,以提供自定义的分界线。
⑮、void childEvent(QChildEvent* c);    		//虚拟的,受保护的。QObject::childEvent()的重新实现
当子部件已被插入或删除时产生该事件。
⑯、void moveSplitter(int pos, int index);  		//受保护的
把索引为index的分界线的左侧(或顶边),尽可能的移至位置pos处,pos是距离分离器左侧或顶边的距离。注:对于从右到左的语言,pos是距离分离器右侧的距离。
⑰、void setRubberBand(int pos);   //受保护的
在位置pos处显示橡皮筋,若pos为负数,则移除橡
皮筋。当分离器不是动态调整,用户移动分界线时,看到
的那根线条就是橡皮筋,效果见图5-40。
⑱、void splitterMoved(int pos, int index);   //信号
当索引为index的分界线移至位置pos时,发送此信号。

在这里插入图片描述
示例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类比较简单,只有如下几个公有函数

	QSplitterHandle(Qt::Orientation orientation, QSplitter* parent);   //构造函数
	QSplitter* splitter() const;     				//获取与此分界线关联的分离器
	void setOrientation(Qt::Orientation orientation);  	//设置分界线的方向
	Qt::Orientation orientation() const;    			//返回分界线的方向
	bool opaqueResize() const;  		 		//设置是否不透明(动态调整),该值由QSplitter控制。
该类需结合QSplitter的如下两个函数使用,
	QSplitterHandle* QSplitter::handle(int index) const; 		//通过该函数可间接的修改分界线。
	QSplitterHandle* QSplitter::createHandle();   //虚拟的,受保护的。重写此函数可实现自定义的分界线。

示例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

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/hyongilfmmm/article/details/83029705