Qt类似于网格布局的窗口容器QGridWidget简介

3 篇文章 0 订阅
2 篇文章 0 订阅

一、概述

Qt的基本布局有水平布局(QHBoxLayout)、垂直布局(QVBoxLayout)、网格布局(QGridLayout)、表单布局(QFormLayout)等。QGridWidget作为一个类似网格布局的窗口容器,将加入到容器中的窗口按照网格布局方式排列,根据窗口的数量自动计算行数与列数。与网格布局的不同之处在于,网格布局中的某个单元格中的窗口暂时隐藏之后,空余出来的空间不会被同一行的其他窗口延伸利用,QGridWidget实现了某个网格暂时隐藏之后,同一行的其他窗口会重新分配横向上占用的空间,自动延伸,从而实现尽可能占用更多空间的功能。

QGridWidget与QBoxWidget的功能基本类似,主要区别有两点:

  1. QGridWidget的布局容器由QSplitter来实现,QBoxWidget的布局容器由水平布局(QHBoxLayout)和垂直布局(QVBoxLayout)组合实现。
  2. QGridWidget能够拖动调整单元格的占比,并能够自动记忆与恢复,也可以恢复统一的默认占比。

二、运行效果图

1. 所有窗口均显示的情形

2. 某些窗口暂时隐藏时的情形

3. 某个窗口最大化显示情形

4. 调整窗口在布局中的占比,下次启动时能够自动恢复退出时的占比,也可以按下“RestorePos”按钮恢复均匀分布的统一占比。

三、实现基本原理

根据容器中窗口的个数,先计算一行应该有多少列(nCol)“int nCol = 0.9999 + sqrt(m_vWidget.size());”,再计算应该有多少行nRow“int nRow = (m_vWidget.size() + nCol - 1) / nCol;”,然后创建nRow个水平分割窗口(QSplitter)容器,每个nCol水平分割窗口容器中加入最多nCol个窗口,最后将这些水平分割窗口容器加入到垂直分割窗口(QSplitter)容器中。

四、QGridWidget.h代码

#ifndef QGridWidget_H

#define QGridWidget_H

 

#include <QWidget>

#include <QSplitter>

#include <QVBoxLayout>

#include <vector>

 

 

class QPushButton;

 

class QCellWidget : public QWidget

{

Q_OBJECT

public:

explicit QCellWidget(QWidget *widget, QWidget *parent = nullptr, Qt::WindowFlags f = Qt::WindowFlags());

 

enum ShowType

{

ST_HIDE,

ST_MAXIMIZED

};

 

protected:

virtual void resizeEvent(QResizeEvent *event);

virtual void paintEvent(QPaintEvent *event) override;

 

signals:

void showCell(int);

 

private slots :

void ShowCell();

 

private:

QPushButton *m_pBtnHide;

QPushButton *m_pBtnMaximize;

QVBoxLayout m_LayoutV;

};

 

class QGridWidget : public QWidget

{

Q_OBJECT

public:

explicit QGridWidget(QWidget *parent = nullptr, int nMaxCol = 0);

~QGridWidget();

 

void AddWidget(QWidget *pWidget);

void DoLayout();

int FindWidget(QWidget *pWidget);

inline const QSplitter& GetLayout() const { return m_SplitterV; };

inline const std::vector<QWidget*>& GetWidgets() const { return m_vWidget; };

inline void restoreState0() { restoreState("QGridWidget0"); };

inline void ShowAll() { MaximizeWidget2(); };

inline void MaximizeWidget(QWidget *pWidget = NULL) { MaximizeWidget2(FindWidget(pWidget)); };

inline bool HideWidget(QWidget *pWidget = NULL) { return HideWidget2(FindWidget(pWidget)); };

inline void ShowWidget(QWidget *pWidget = NULL) { ShowWidget2(FindWidget(pWidget)); };

void MaximizeWidget2(int nIndex = -1);

bool HideWidget2(int nIndex = -1);

void ShowWidget2(int nIndex = -1);

 

protected:

void resizeEvent(QResizeEvent *event);

 

private:

void saveState(const QString &strName = "QGridWidget");

void restoreState(const QString &strName = "QGridWidget");

 

signals:

void hideWidget(int);

void maximizeWidget(int);

 

public slots :

void ShowCell(int);

 

private:

int m_nMaxCol;

QSplitter m_SplitterV;

std::vector<QWidget*> m_vWidget;

};

 

#endif // QGridWidget_H

 

五、QGridWidget.cpp代码

#include "qgridwidget.h"

#include <math.h>

 

#include <QPainter>

#include <QPushButton>

#include <QMouseEvent>

#include <QSettings>

 

QCellWidget::QCellWidget(QWidget *widget, QWidget *parent, Qt::WindowFlags f)

: QWidget(parent, f), m_LayoutV(this)

{

widget->setParent(parentWidget());

m_LayoutV.setMargin(0);

m_LayoutV.addWidget(widget);

 

QPixmap pix;

pix.load("max.png");

QIcon icon(pix);

m_pBtnMaximize = new QPushButton(icon, "", this);

m_pBtnMaximize->setFlat(true);

m_pBtnMaximize->setStyleSheet("margin:0px");

m_pBtnMaximize->setFixedSize(13, 13);

m_pBtnHide = new QPushButton(QStringLiteral("×"), this);

m_pBtnHide->setFlat(true);

m_pBtnHide->setStyleSheet("margin:0px;color: rgb(160, 160, 160);");

m_pBtnHide->setFixedSize(12, 12);

connect(m_pBtnMaximize, SIGNAL(clicked()), this, SLOT(ShowCell()));

  connect(m_pBtnHide, SIGNAL(clicked()), this, SLOT(ShowCell()));

}

 

void QCellWidget::resizeEvent(QResizeEvent *event)

{

QRect rc = rect();

m_pBtnHide->move(rc.right() - 12, 1);

m_pBtnMaximize->move(rc.right() - 28, 0);

}

 

void QCellWidget::paintEvent(QPaintEvent *event)

{

QRect rc = rect();

QPainter p(this);

p.setPen(QColor(224, 224, 224));

p.drawRect(rc.left(), rc.top(), rc.width() - 1, rc.height() - 1);

}

 

void QCellWidget::ShowCell()

{

if (sender() == m_pBtnMaximize)

{

emit showCell(ST_MAXIMIZED);

}

else

{

emit showCell(ST_HIDE);

}

}

 

QGridWidget::QGridWidget(QWidget *parent, int nMaxCol) : QWidget(parent), m_SplitterV(Qt::Vertical, this)//此处必须加this

{

m_nMaxCol = nMaxCol;

m_SplitterV.setHandleWidth(0);

}

 

QGridWidget::~QGridWidget()

{

saveState();

}

 

void QGridWidget::AddWidget(QWidget *pWidget)

{

if (pWidget != NULL)

{

QCellWidget *pCW = new QCellWidget(pWidget, this);

connect(pCW, SIGNAL(showCell(int)), this, SLOT(ShowCell(int)));

m_vWidget.push_back(pCW);

}

}

 

void QGridWidget::DoLayout()

{

int nCol = 0.9999 + sqrt(m_vWidget.size());

if (m_nMaxCol > 0 && nCol > m_nMaxCol)

{

nCol = m_nMaxCol;

}

int nRow = (m_vWidget.size() + nCol - 1) / nCol;

 

int i;

for (i = m_vWidget.size() - 1; i >= 0; i--)

{

m_vWidget[i]->setParent(this);

}

while (m_SplitterV.count())

{

delete m_SplitterV.widget(0);

}

 

for (i = 0; i < nRow; i++)

{

QSplitter *pSplitter = new QSplitter(&m_SplitterV);

for (int j = 0; j < nCol; j++)

{

int nIndex = i*nCol + j;

if (nIndex < m_vWidget.size())

{

pSplitter->addWidget(m_vWidget[nIndex]);

}

}

pSplitter->setHandleWidth(0);

}

saveState("QGridWidget0");

restoreState();

}

 

int QGridWidget::FindWidget(QWidget *pWidget)

{

if (pWidget != NULL)

{

for (int i = m_vWidget.size() - 1; i >= 0; i--)

{

if (m_vWidget[i] == pWidget)

{

return i;

}

}

}

return -1;

}

 

void QGridWidget::MaximizeWidget2(int nIndex /*= -1*/)

{

int i;

if (nIndex < 0 || nIndex >= m_vWidget.size())

{

for (i = m_vWidget.size() - 1; i >= 0; i--)

{

m_vWidget[i]->show();

}

}

else

{

for (i = m_vWidget.size() - 1; i >= 0; i--)

{

m_vWidget[i]->setVisible(i == nIndex);

}

}

m_SplitterV.update();

}

 

bool QGridWidget::HideWidget2(int nIndex /*= -1*/)

{

int nShow = 0;

for (int i = m_vWidget.size() - 1; i >= 0; i--)

{

if (m_vWidget[i]->isVisible())

{

nShow++;

}

}

 

if (nShow <= 1)

{

return false;

}

 

if (nIndex >= 0 && nIndex < m_vWidget.size())

{

m_vWidget[nIndex]->hide();

m_SplitterV.update();

}

 

return true;

}

 

void QGridWidget::ShowWidget2(int nIndex /*= -1*/)

{

if (nIndex >= 0 && nIndex < m_vWidget.size())

{

m_vWidget[nIndex]->show();

}

}

 

void QGridWidget::resizeEvent(QResizeEvent *event)

{

m_SplitterV.resize(size());

}

 

void QGridWidget::saveState(const QString &strName /*= "QGridWidget"*/)

{

QSettings settings("TIAF", strName);

settings.setValue("windowState", m_SplitterV.saveState());

for (int i = 0; i < m_SplitterV.count(); i++)

{

char szBuf[32];

sprintf(szBuf, "windowState%02d", i);

settings.setValue(szBuf, ((QSplitter*)m_SplitterV.widget(i))->saveState());

}

}

 

void QGridWidget::restoreState(const QString &strName /*= "QGridWidget"*/)

{

QSettings settings("TIAF", strName);

m_SplitterV.restoreState(settings.value("windowState").toByteArray());

for (int i = 0; i < m_SplitterV.count(); i++)

{

char szBuf[32];

sprintf(szBuf, "windowState%02d", i);

((QSplitter*)m_SplitterV.widget(i))->restoreState(settings.value(szBuf).toByteArray());

}

}

 

void QGridWidget::ShowCell(int nType)

{

QWidget *pWidget = (QWidget*)sender();

int nIndex = FindWidget(pWidget);

if (nType == QCellWidget::ST_MAXIMIZED)

{

MaximizeWidget(pWidget);

emit maximizeWidget(nIndex);

}

else if (nType == QCellWidget::ST_HIDE)

{

if (HideWidget(pWidget))

{

emit hideWidget(nIndex);

}

}

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值