QSplitter是分割窗口控件,并且可以拖动窗口来改变窗口的大小,是主界面显示时经常用到,本篇介绍它的交互操作。
QSplitter可以容纳多个Widget,具有布局的特点,并且可以动态调整各个Widget的大小。
QSplitter布局有两种方式:垂直和水平
Qt::Orientation::Vertical
Qt::Orientation::Horizontal
下面介绍一个垂直的伸缩示例:
首先我们有3个子部件,
现在的需求是只能显示两个子部件,第一个子部件一直显示,第2个子部件显示时,第3个子部件就隐藏,
而当第3个子部件显示时第2个子部件就隐藏。
部件1代码:
#ifndef CONTENTSHOW_H
#define CONTENTSHOW_H
#include <QWidget>
namespace Ui {
class ContentShow;
}
class ContentShow : public QWidget
{
Q_OBJECT
public:
explicit ContentShow(QWidget *parent = nullptr);
~ContentShow();
private:
Ui::ContentShow *ui;
};
#endif // CONTENTSHOW_H
#include "contentshow.h"
#include "ui_contentshow.h"
ContentShow::ContentShow(QWidget *parent) :
QWidget(parent),
ui(new Ui::ContentShow)
{
ui->setupUi(this);
}
ContentShow::~ContentShow()
{
delete ui;
}
部件2输入面板
#ifndef INPUTPANEL_H
#define INPUTPANEL_H
#include <QWidget>
namespace Ui {
class InputPanel;
}
class InputPanel : public QWidget
{
Q_OBJECT
public:
explicit InputPanel(QWidget *parent = nullptr);
~InputPanel();
signals:
void siganlToContralPanel();
public slots:
void slotToContralPanel();
private:
Ui::InputPanel *ui;
};
#endif // INPUTPANEL_H
#include "ui_inputpanel.h"
InputPanel::InputPanel(QWidget *parent) :
QWidget(parent),
ui(new Ui::InputPanel)
{
ui->setupUi(this);
connect(ui->pushButton_change, SIGNAL(clicked()), this, SLOT(slotToContralPanel()));
}
InputPanel::~InputPanel()
{
delete ui;
}
void InputPanel::slotToContralPanel()
{
emit siganlToContralPanel();
}
部件3控制面板
#ifndef CONTRALPANEL_H
#define CONTRALPANEL_H
#include <QWidget>
namespace Ui {
class ContralPanel;
}
class ContralPanel : public QWidget
{
Q_OBJECT
public:
explicit ContralPanel(QWidget *parent = nullptr);
~ContralPanel();
signals:
void siganlToInputPanel();
public slots:
void slotToInputPanel();
private:
Ui::ContralPanel *ui;
};
#endif // CONTRALPANEL_H
#include "contralpanel.h"
#include "ui_contralpanel.h"
ContralPanel::ContralPanel(QWidget *parent) :
QWidget(parent),
ui(new Ui::ContralPanel)
{
ui->setupUi(this);
connect(ui->pushButton_exit, SIGNAL(clicked()), this, SLOT(slotToInputPanel()));
}
ContralPanel::~ContralPanel()
{
delete ui;
}
void ContralPanel::slotToInputPanel()
{
emit siganlToInputPanel();
}
主窗口
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
struct MainWindowPrivate;
class ContentShow;
class InputPanel;
class ContralPanel;
class QSplitter;
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
void initView();
public slots:
void slotToContralPanel();
void slotToInputPanel();
void slotSplitterMoved(int pos, int index);
private:
Ui::MainWindow *ui;
QSplitter *m_splitter;
ContentShow *m_contentShow;
InputPanel *m_inputPanel;
ContralPanel *m_contralPanel;
};
#endif // MAINWINDOW_H
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "inputpanel.h"
#include "contentshow.h"
#include "contralpanel.h"
#include <QSplitter>
#include <QVBoxLayout>
#include <QDebug>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
initView();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::initView()
{
m_splitter = new QSplitter(Qt::Vertical, ui->widget);
m_contentShow = new ContentShow(ui->widget);
m_inputPanel = new InputPanel(ui->widget);
m_contralPanel = new ContralPanel(ui->widget);
connect(m_inputPanel, SIGNAL(siganlToContralPanel()), this, SLOT(slotToContralPanel()));
connect(m_contralPanel, SIGNAL(siganlToInputPanel()), this, SLOT(slotToInputPanel()));
m_contentShow->setMinimumHeight(260);
m_inputPanel->setMinimumHeight(190);
m_contralPanel->setMinimumHeight(190);
m_splitter->setSizePolicy(QSizePolicy::Policy::Expanding, QSizePolicy::Policy::Expanding);
m_splitter->addWidget(m_contentShow);
m_splitter->addWidget(m_inputPanel);
m_splitter->addWidget(m_contralPanel);
m_splitter->setHandleWidth(1);
QList<int> heightList;
heightList.append(360);
heightList.append(200);
heightList.append(200);
m_splitter->setSizes(heightList);
//不允许折叠
m_splitter->setChildrenCollapsible(false);
m_splitter->setStyleSheet("");
m_contralPanel->hide();
QVBoxLayout *layout = new QVBoxLayout(ui->widget);
layout->setMargin(0);
layout->addWidget(m_splitter);
layout->setStretchFactor(m_splitter, 1);
ui->widget->setLayout(layout);
}
void MainWindow::slotToContralPanel()
{
m_inputPanel->hide();
m_contralPanel->show();
}
void MainWindow::slotToInputPanel()
{
m_inputPanel->show();
m_contralPanel->hide();
}
主函数文件:
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
运行效果:
从上面可以看出当托动第2个部件时再点转换按钮,第3个部件的在大没没有随2个部件的大小而改变,显示的是原来的初始化大小,有点不协调。
那么如果让第3个部件显示时大小为第2个部件的大小呢。
思路1:当拖动时更新第3个部件的大小,拖动第3个部件时更新第2个部件的大小,例如
connect(m_splitter, SIGNAL(splitterMoved(int, int)), this, SLOT(slotSplitterMoved(int, int)));
void MainWindow::slotSplitterMoved(int pos, int index)
{
if(1 == index) {
QSize size = m_inputPanel->size();
m_contralPanel->resize(size);
}
else if(2 == index) {
QSize size = m_contralPanel->size();
m_inputPanel->resize(size);
}
}
但是上面这段代码没有作用,拖动第2个部件修复第3个部件大小,这时再显示第3个部件时还没原来的大小。
思路2:每次设置qsplitter的Sizes,通过setSizes函数设置
void MainWindow::slotToContralPanel()
{
QList<int> splitter = m_splitter->sizes();
qDebug() << "MainWindow::slotToContralPanel===splitter=" << splitter
<< " line= " << __LINE__;
splitter.swap(1,2);
m_splitter->setSizes(splitter);
m_inputPanel->hide();
m_contralPanel->show();
}
void MainWindow::slotToInputPanel()
{
QList<int> splitter = m_splitter->sizes();
qDebug() << "MainWindow::slotToInputPanel===splitter=" << splitter
<< " line= " << __LINE__;
splitter.swap(1,2);
m_splitter->setSizes(splitter);
m_inputPanel->show();
m_contralPanel->hide();
}
这样每次都更新了分隔块的大小。
以上看出转换部件时,就显示流畅很多了,与上一个部件大小一样。