1. 程式人生 > >Qt之流式佈局QFlow

Qt之流式佈局QFlow

Qt沒有像網頁那種能根據視窗大小改變的佈局,但是我們可以利用繼承QLayout 自己編寫

環境

Qt5.6.2+VS2013

程式碼

FlowLayout.h

#ifndef FLOWLAYOUT_H
#define FLOWLAYOUT_H

#include <QLayout>
#include <QRect>
#include <QStyle>

#include <QLayout>
#include <QRect>
#include <QStyle>

class QFlowLayout : public QLayout
{
public:
	explicit QFlowLayout(QWidget *parent, int margin = -1, int hSpacing = -1, int vSpacing = -1);
	explicit QFlowLayout(int margin = -1, int hSpacing = -1, int vSpacing = -1);
	~QFlowLayout();

	void addItem(QLayoutItem *item) Q_DECL_OVERRIDE;
	int horizontalSpacing() const;
	int verticalSpacing() const;
	Qt::Orientations expandingDirections() const Q_DECL_OVERRIDE;
	bool hasHeightForWidth() const Q_DECL_OVERRIDE;
	int heightForWidth(int) const Q_DECL_OVERRIDE;
	int count() const Q_DECL_OVERRIDE;
	QLayoutItem *itemAt(int index) const Q_DECL_OVERRIDE;
	QSize minimumSize() const Q_DECL_OVERRIDE;
	void setGeometry(const QRect &rect) Q_DECL_OVERRIDE;
	QSize sizeHint() const Q_DECL_OVERRIDE;
	QLayoutItem *takeAt(int index) Q_DECL_OVERRIDE;

private:
	int doLayout(const QRect &rect, bool testOnly) const;
	int smartSpacing(QStyle::PixelMetric pm) const;

private:
	QList<QLayoutItem *> x_itemList;
	int x_hSpace;
	int x_vSpace;
};
#endif

FlowLayout.cpp

#include "FlowLayout.h"

#include <algorithm>
#include <QWidget>

QFlowLayout::QFlowLayout(QWidget *parent, int margin, int hSpacing, int vSpacing)
	: QLayout(parent),
	x_hSpace(hSpacing),
	x_vSpace(vSpacing)
{
	setContentsMargins(margin, margin, margin, margin);
}

QFlowLayout::QFlowLayout(int margin, int hSpacing, int vSpacing)
	: x_hSpace(hSpacing),
	x_vSpace(vSpacing)
{
	setContentsMargins(margin, margin, margin, margin);
}

QFlowLayout::~QFlowLayout()
{
	QLayoutItem *item;
	while ((item = takeAt(0)))
		delete item;
}

void QFlowLayout::addItem(QLayoutItem *item)
{
	x_itemList.append(item);
}

int QFlowLayout::horizontalSpacing() const
{
	if (x_hSpace >= 0) 
	{
		return x_hSpace;
	}
	else 
	{
		return smartSpacing(QStyle::PM_LayoutHorizontalSpacing);
	}
}

int QFlowLayout::verticalSpacing() const
{
	if (x_vSpace >= 0) {
		return x_vSpace;
	}
	else {
		return smartSpacing(QStyle::PM_LayoutVerticalSpacing);
	}
}

int QFlowLayout::count() const
{
	return x_itemList.size();
}

QLayoutItem *QFlowLayout::itemAt(int index) const
{
	return x_itemList.value(index);
}

QLayoutItem *QFlowLayout::takeAt(int index)
{
	if (index >= 0 && index < x_itemList.size())
		return x_itemList.takeAt(index);
	else
		return 0;
}

Qt::Orientations QFlowLayout::expandingDirections() const
{
	return 0;
}

bool QFlowLayout::hasHeightForWidth() const
{
	return true;
}

int QFlowLayout::heightForWidth(int width) const
{
	int height = doLayout(QRect(0, 0, width, 0), true);
	return height;
}

void QFlowLayout::setGeometry(const QRect &rect)
{
	QLayout::setGeometry(rect);
	doLayout(rect, false);
}

QSize QFlowLayout::sizeHint() const
{
	return minimumSize();
}

QSize QFlowLayout::minimumSize() const
{
	QSize size;
	QLayoutItem *item;
	foreach(item, x_itemList)
		size = size.expandedTo(item->minimumSize());

	size += QSize(2 * margin(), 2 * margin());
	return size;
}

int QFlowLayout::doLayout(const QRect &rect, bool testOnly) const
{
	int left, top, right, bottom;
	getContentsMargins(&left, &top, &right, &bottom);
	QRect effectiveRect = rect.adjusted(+left, +top, -right, -bottom);
	int x = effectiveRect.x();
	int y = effectiveRect.y();
	int lineHeight = 0;

	QLayoutItem *item;
	foreach(item, x_itemList) {
		QWidget *wid = item->widget();
		int spaceX = horizontalSpacing();
		if (spaceX == -1)
			spaceX = wid->style()->layoutSpacing(
			QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Horizontal);
		int spaceY = verticalSpacing();
		if (spaceY == -1)
			spaceY = wid->style()->layoutSpacing(
			QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Vertical);

		int nextX = x + item->sizeHint().width() + spaceX;
		if (nextX - spaceX > effectiveRect.right() && lineHeight > 0) {
			x = effectiveRect.x();
			y = y + lineHeight + spaceY;
			nextX = x + item->sizeHint().width() + spaceX;
			lineHeight = 0;
		}

		if (!testOnly)
			item->setGeometry(QRect(QPoint(x, y), item->sizeHint()));

		x = nextX;
		lineHeight = qMax(lineHeight, item->sizeHint().height());
	}
	return y + lineHeight - rect.y() + bottom;
}

int QFlowLayout::smartSpacing(QStyle::PixelMetric pm) const
{
	QObject *parent = this->parent();
	if (!parent) {
		return -1;
	}
	else if (parent->isWidgetType()) {
		QWidget *pw = static_cast<QWidget *>(parent);
		return pw->style()->pixelMetric(pm, 0, pw);
	}
	else {
		return static_cast<QLayout *>(parent)->spacing();
	}
}

使用

#include "FlowLayout.h"

QFlowLayout* _pFlowLayout = new QFlowFlayout();

_pFlowLayout FlowLayout->addWidget(new QPushButton("1"));
_pFlowLayout ->addWidget(new QPushButton("2"));
_pFlowLayout ->addWidget(new QPushButton("3"));
_pFlowLayout ->addWidget(new QPushButton("4444444444444444"));
_pFlowLayout ->addWidget(new QPushButton("55"));
_pFlowLayout ->addWidget(new QPushButton("6"));

setLayout(x_pFlowLayout);

效果在這裡插入圖片描述