在Qt中把QWidget窗体三等分,我想实现QWidget中的三等分窗口能够像QDockWidget类一样用鼠标拖动这三等分窗体边缘使屏占比改变。一般我们会直接使用QDockWidget,但是我们这里只想鼠标拖拽,不需要窗体停靠的功能。
QDockWidget类提供了一个特殊的窗口部件,它可以是被锁在QMainWindow窗口内部或者是作为顶级窗口悬浮在桌面上。QDockWidget可以移动、悬浮,在许多工程软件中,都是使用dock布局窗口,用户可以自由组合窗口界面。
我们可以使用QSplitter控件,布局器中控件大小是根据窗口大小自动调整,用户能拉伸窗口但是不能直接拉伸界面内部的某个控件
先看一下效果
一个QSplitter是一个可以包含其他控件的控件,这些控件被一个分隔条隔开,托拽这个分隔条,可以改变splitter的子控件的大小。
QSplitter控件经常做为布局管理器使用,给用户提供更多的界面控制。
默认情况下,QSplitter动态调整子节点的大小,也即是鼠标按下拖动的时候,控件大小也随着变,如果希望QSplitter只在调整大小操作结束时调整子节点的大小,也即是鼠标按下拖动的时候不调整大小,释放鼠标之后,也即是调整结束后才调整大小,用setOpaqueResize(false) 来设置。
控件之间的初始大小分布由初始大小与拉伸因子相乘确定。还可以使用 setSizes() 来设置所有 控件的大小。函数 sizes() 返回用户设置的大小。或者,我们以分别使用 saveState() 和restoreState() 从QByteArray保存和恢复 之前控件的大小状态,等下一次启动的时候把这个状态再恢复就好啦。
当我们 hide() 一个子节点控件时,它的空间将被分配给其他的子节点。当我们 show() 它时,它将被恢复。
1.QSplitter的构造方法:
QSplitter *splitterMain=new QSplitter(Qt::Horizontal,0);
第一个参数通过Qt::Horizontal 和 Qt::Vertical来设定为水平分割或垂直分割。第二个设定0代表是主窗口,无父窗口。
不过子splitter设置的
new QSplitter(Qt::Vertical,splitterMain);
代表主窗口是splitterMain。则子splitter就被添加到splitterMain中。
添加时为从左至右(或从上至下)添加;
#ifndef PROJECTWIN_H
#define PROJECTWIN_H
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "FileMonitorMgr.h"
namespace Ui {
class ProjectWin;
}
const QString styles = "QTreeView\
{\
background-color: #5B677A;\
font-size:17px;\
color: white;\
}\
QTreeView::item:hover\
{\
background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #e7effd, stop: 1 #cbdaf1);\
border: 1px solid #bfcde4;\
}\
QTreeView::item:hover\
{\
background: rgb(69, 187, 217);\
}\
QTreeView::item:selected:active\
{\
background: rgb(255, 62, 150);\
}\
QTreeView::item:selected:!active\
{\
background: rgb(63, 147, 168);\
}\
QTreeView::branch\
{\
background:#5B677A;\
}\
QTreeView::branch:has-children:!has-siblings:closed,QTreeView::branch:closed:has-children:has-siblings\
{\
border-image: none;\
background:#5B677A;\
image: url(image/Folder-1.png);\
}\
QTreeView::branch:open:has-children:!has-siblings,QTreeView::branch:open:has-children:has-siblings\
{\
border-image: none;\
background:#5B677A;\
image: url(image/Open-Folder.png);\
}";
class ProjectWin : public QWidget
{
Q_OBJECT
public:
static ProjectWin* getInstance();
~ProjectWin();
FileMonitorMgr *m_fileMgr;
QString m_paraFolder;
private:
QTreeWidget* m_picTree;
// QTreeWidget* m_paraTree;
QWidget* m_naviWgt;
private:
void initWidget();
void initPicTree();
void readParaFile(QString filePath);
private:
Ui::ProjectWin *ui;
QGridLayout* m_grid;
QWidget* m_centralWidget;
QTabWidget* m_tabWidget;
QTabWidget* m_tabWidgetPara;
QTabWidget* m_tabWidgetNavi;
QTextEdit* m_paraText;
QVBoxLayout* m_mainLayout;
static ProjectWin* m_pInstance;
private:
explicit ProjectWin(QWidget *parent = nullptr);
static void destroyInstance();
public:
Q_SIGNALS:
void sigShowImageBorder(const QString &imageName);
// void appendText(const QString &text);
public Q_SLOTS:
void slotPicTree(QVector<QString> lst, QString path);
void slotNavi(const QString& file);
void onItemClicked(QTreeWidgetItem *item, int column);
void slotParaInfo(QString imageName);
void slotImageSelectNode(QString imageName);
void slotUpdatePicTree(const QStringList& fileList);
};
#endif // PROJECTWIN_H
#include "ProjectWin.h"
#include "ui_ProjectWin.h"
#pragma execution_character_set("utf-8")
ProjectWin* ProjectWin::m_pInstance = nullptr;
ProjectWin* ProjectWin::getInstance()
{
if(!m_pInstance)
{
m_pInstance = new ProjectWin();
atexit(destroyInstance);
}
return m_pInstance;
}
void ProjectWin::destroyInstance()
{
if(m_pInstance)
{
delete m_pInstance;
m_pInstance = nullptr;
}
}
ProjectWin::~ProjectWin()
{
delete ui;
}
ProjectWin::ProjectWin(QWidget *parent) :
QWidget(parent),
ui(new Ui::ProjectWin)
{
ui->setupUi(this);
//图像列表
m_tabWidget = new QTabWidget();
// m_tabWidget->setStyleSheet("border: 0; background: transparent");
// m_tabWidget->setStyleSheet("border: 0");
m_picTree = new QTreeWidget();
// m_picTree->setStyleSheet("border: 0; background: transparent");
m_picTree->hide();
m_picTree->setStyleSheet("border: 1");
m_picTree->setContextMenuPolicy(Qt::CustomContextMenu);
m_picTree->setColumnCount(1);
m_picTree->setHeaderHidden(true);
connect(m_picTree, &QTreeWidget::itemClicked, this, &ProjectWin::onItemClicked);
//图像参数
m_tabWidgetPara = new QTabWidget();
m_paraText = new QTextEdit();
m_tabWidgetPara->addTab(m_paraText, u8"分裂器中间的窗体"/*u8"图像参数数据"*/);
m_tabWidgetPara->setStyleSheet("border: 1");
m_paraText->setStyleSheet("border: 1");
// m_tabWidgetPara->setTabText(0, u8"图像参数数据");
//导航
m_tabWidgetNavi = new QTabWidget();
m_naviWgt = new QWidget();
m_tabWidgetNavi->addTab(m_naviWgt, u8"分裂器最下面的窗体"/*u8"导航"*/);
//创建三个部件组
QWidget* picGroup = new QWidget();
QWidget* paraGroup = new QWidget();
QWidget* naviGroup = new QWidget();
// 只设置QWidget的边框为0,不影响子元素
picGroup->setStyleSheet("QWidget { border: 0px }");
paraGroup->setStyleSheet("QWidget { border: 0px }");
naviGroup->setStyleSheet("QWidget { border: 0px }");
QSplitter* splitter= new QSplitter(Qt::Vertical, this);
splitter->addWidget(picGroup);
splitter->addWidget(paraGroup);
splitter->addWidget(naviGroup);
QList<int> sizes;
sizes << this->height() / 3 << this->height() / 3 << this->height() / 3;
splitter->setSizes(sizes);
// 设置拉伸比例,其中1、1、1表示三个窗口的初始尺寸比例都是1,即相等
splitter->setStretchFactor(0, 1);
splitter->setStretchFactor(1, 1);
splitter->setStretchFactor(2, 1);
QVBoxLayout* picLayout = new QVBoxLayout();
picLayout->setMargin(0);
picLayout->setSpacing(0);
picLayout->addWidget(m_tabWidget);
picLayout->addWidget(m_picTree);
picGroup->setLayout(picLayout);
QVBoxLayout* paraLayout = new QVBoxLayout();
paraLayout->setMargin(0);
paraLayout->setSpacing(0);
paraLayout->addWidget(m_tabWidgetPara);
// paraLayout->addWidget(m_paraText);
paraGroup->setLayout(paraLayout);
QVBoxLayout* naviLayout = new QVBoxLayout();
naviLayout->setMargin(0);
naviLayout->setSpacing(0);
naviLayout->addWidget(m_tabWidgetNavi);
naviGroup->setLayout(naviLayout);
// 设置窗口的主布局
QVBoxLayout* mainLayout = new QVBoxLayout();
mainLayout->setMargin(0);
mainLayout->setSpacing(0);
// mainLayout->addWidget(picGroup);
// mainLayout->addWidget(paraGroup);
// mainLayout->addWidget(naviGroup);
mainLayout->addWidget(splitter);
this->setLayout(mainLayout);
// connect(this, &ProjectWin::appendText, m_paraText, &QTextEdit::append);
}
void ProjectWin::onItemClicked(QTreeWidgetItem *item, int column)
{
QString imageName = item->text(0);
emit sigShowImageBorder(imageName);
}
void ProjectWin::initWidget()
{
// m_picTree->header()->hide();//设置隐藏头
}
void ProjectWin::initPicTree()
{
}
void ProjectWin::readParaFile(QString filePath)
{
if (!m_paraText) {
qDebug() << "m_paraText is null!";
return;
}
m_paraText->clear();
QString txtFile = filePath.left(filePath.size() -3);
txtFile += "txt";
QFile file(txtFile);
if(!file.open(QIODevice::ReadOnly)) {
qDebug() << file.errorString();
return;
}
QTextStream in(&file);
in.setCodec("UTF-8"); // 设置编码为UTF-8
while(!in.atEnd()) {
QString line = in.readLine();
// emit appendText(line); // 使用信号来添加文本
m_paraText->append(line);
// 这里处理每一行
qDebug() << line;
}
file.close();
}
void ProjectWin::slotPicTree(QVector<QString> lst, QString path)
{
m_paraFolder = path;
m_picTree->show();
QTreeWidgetItem* topItem = new QTreeWidgetItem(m_picTree);
topItem->setText(0, path);
topItem->setCheckState(0, Qt::Checked);
m_picTree->addTopLevelItem(topItem);
int count = lst.size();
//添加顶层节点
if (lst.size() > 0)
{
for (int i = 0; i < lst.size(); i++)
{
//int size = lst.at(i).size();
//int pos = lst.at(i).lastIndexOf("/");
//QString temp = lst.at(i).right(size - pos - 1);
QTreeWidgetItem* item = new QTreeWidgetItem(topItem);
item->setText(0, lst.at(i));
item->setCheckState(0, Qt::Checked);
}
}
m_picTree->expandAll();
// m_grid = new QGridLayout(this);
// m_grid->addWidget(m_picTree);
m_picTree->setStyleSheet(styles);
// this->setLayout(m_grid);
m_tabWidget->addTab(m_picTree, u8"彩C");
}
void ProjectWin::slotParaInfo(QString imageName)
{
QString fullPath = m_paraFolder + "/" + imageName;
readParaFile(fullPath);
}
void ProjectWin::slotImageSelectNode(QString imageName)
{
QList<QTreeWidgetItem *> items = m_picTree->findItems(imageName, Qt::MatchExactly | Qt::MatchRecursive);
if(!items.empty()){
m_picTree->setCurrentItem(items.at(0));
}
}
void ProjectWin::slotUpdatePicTree(const QStringList &fileList)
{
for(const QString& str : fileList)
{
QTreeWidgetItem* item = new QTreeWidgetItem(m_picTree);
item->setText(0, str);
item->setCheckState(0, Qt::Checked);
}
}
void ProjectWin::slotNavi(const QString& file)
{
m_tabWidgetNavi->addTab(m_naviWgt, u8"导航");
}
主要是看ProjectWin的构造函数
ProjectWin::ProjectWin(QWidget *parent) :
QWidget(parent),
ui(new Ui::ProjectWin)
{
ui->setupUi(this);
//图像列表
m_tabWidget = new QTabWidget();
// m_tabWidget->setStyleSheet("border: 0; background: transparent");
// m_tabWidget->setStyleSheet("border: 0");
m_picTree = new QTreeWidget();
// m_picTree->setStyleSheet("border: 0; background: transparent");
m_picTree->hide();
m_picTree->setStyleSheet("border: 1");
m_picTree->setContextMenuPolicy(Qt::CustomContextMenu);
m_picTree->setColumnCount(1);
m_picTree->setHeaderHidden(true);
connect(m_picTree, &QTreeWidget::itemClicked, this, &ProjectWin::onItemClicked);
//图像参数
m_tabWidgetPara = new QTabWidget();
m_paraText = new QTextEdit();
m_tabWidgetPara->addTab(m_paraText, u8"分裂器中间的窗体"/*u8"图像参数数据"*/);
m_tabWidgetPara->setStyleSheet("border: 1");
m_paraText->setStyleSheet("border: 1");
// m_tabWidgetPara->setTabText(0, u8"图像参数数据");
//导航
m_tabWidgetNavi = new QTabWidget();
m_naviWgt = new QWidget();
m_tabWidgetNavi->addTab(m_naviWgt, u8"分裂器最下面的窗体"/*u8"导航"*/);
//创建三个部件组
QWidget* picGroup = new QWidget();
QWidget* paraGroup = new QWidget();
QWidget* naviGroup = new QWidget();
// 只设置QWidget的边框为0,不影响子元素
picGroup->setStyleSheet("QWidget { border: 0px }");
paraGroup->setStyleSheet("QWidget { border: 0px }");
naviGroup->setStyleSheet("QWidget { border: 0px }");
QSplitter* splitter= new QSplitter(Qt::Vertical, this);
splitter->addWidget(picGroup);
splitter->addWidget(paraGroup);
splitter->addWidget(naviGroup);
QList<int> sizes;
sizes << this->height() / 3 << this->height() / 3 << this->height() / 3;
splitter->setSizes(sizes);
// 设置拉伸比例,其中1、1、1表示三个窗口的初始尺寸比例都是1,即相等
splitter->setStretchFactor(0, 1);
splitter->setStretchFactor(1, 1);
splitter->setStretchFactor(2, 1);
QVBoxLayout* picLayout = new QVBoxLayout();
picLayout->setMargin(0);
picLayout->setSpacing(0);
picLayout->addWidget(m_tabWidget);
picLayout->addWidget(m_picTree);
picGroup->setLayout(picLayout);
QVBoxLayout* paraLayout = new QVBoxLayout();
paraLayout->setMargin(0);
paraLayout->setSpacing(0);
paraLayout->addWidget(m_tabWidgetPara);
// paraLayout->addWidget(m_paraText);
paraGroup->setLayout(paraLayout);
QVBoxLayout* naviLayout = new QVBoxLayout();
naviLayout->setMargin(0);
naviLayout->setSpacing(0);
naviLayout->addWidget(m_tabWidgetNavi);
naviGroup->setLayout(naviLayout);
// 设置窗口的主布局
QVBoxLayout* mainLayout = new QVBoxLayout();
mainLayout->setMargin(0);
mainLayout->setSpacing(0);
// mainLayout->addWidget(picGroup);
// mainLayout->addWidget(paraGroup);
// mainLayout->addWidget(naviGroup);
mainLayout->addWidget(splitter);
this->setLayout(mainLayout);
// connect(this, &ProjectWin::appendText, m_paraText, &QTextEdit::append);
}