Border Layout Example
演示如何沿边框排列子小部件。
BorderLayout实现了一种布局,它将子窗口小部件安排在主区域周围。
main.cpp
#include <QApplication>
#include "window.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
Window window;
window.show();
return app.exec();
}
Window.h
#ifndef WINDOW_H
#define WINDOW_H
#include <QWidget>
QT_BEGIN_NAMESPACE
class QLabel;
QT_END_NAMESPACE
class Window : public QWidget
{
Q_OBJECT
public:
Window();
private:
QWidget *createWidget(const QString &text);
};
#endif // WINDOW_H
Window.cpp
#include "borderlayout.h"
#include "window.h"
#include <QTextBrowser>
#include <QLabel>
#include <QPushButton>
/*Window类的构造函数创建一个QTextBrowser对象,其中添加了一个名为layout的BorderLayout。
* BorderLayout类的声明在本文末尾引用。*/
Window::Window()
{
QTextEdit *centralWidget = new QTextEdit;
centralWidget->setPlainText(tr("Central widget"));
BorderLayout *layout = new BorderLayout;
// 几个带标签的小部件被添加到布局中,方向为:中心、北、西、东1、东2和南。
layout->addWidget(centralWidget, BorderLayout::Center);
layout->addWidget(createWidget("North1"), BorderLayout::North);
layout->addWidget(createWidget("North2"), BorderLayout::North);
layout->addWidget(createWidget("West1"), BorderLayout::West);
layout->addWidget(createWidget("West2"), BorderLayout::West);
layout->addWidget(createWidget("East 1"), BorderLayout::East);
layout->addWidget(createWidget("East 2") , BorderLayout::East);
layout->addWidget(createWidget("South1"), BorderLayout::South);
layout->addWidget(createWidget("South2"), BorderLayout::South);
layout->setMargin (15);
layout->setSpacing (3);
setLayout(layout);
setWindowTitle(tr("Border Layout"));
}
/* 类窗口中的createLabel() 设置标记小部件的文本和样式。*/
QWidget *Window::createWidget(const QString &text)
{
auto *widget = new QLabel(text);
widget->setFrameStyle(QFrame::Panel | QFrame::Plain);
widget->setAlignment (Qt::AlignCenter);
return widget;
}
BorderLayout.h
#ifndef BORDERLAYOUT_H
#define BORDERLAYOUT_H
#include <QLayout>
#include <QRect>
/*
类BorderLayout包含格式化它包含的小部件的所有实用函数。
*/
class BorderLayout : public QLayout
{
public:
enum Position { West, North, South, East, Center };
explicit BorderLayout(QWidget *parent, const QMargins &margins = QMargins(), int spacing = -1);
BorderLayout(int spacing = -1);
~BorderLayout();
void addItem(QLayoutItem */*item*/) override{}; //[pure virtual]
int count() const override; //[pure virtual]
QLayoutItem *takeAt(int index) override; //[pure virtual]
QLayoutItem *itemAt(int index) const override; //[pure virtual]
void addWidget(QWidget *widget, Position position);
void add(QLayoutItem *item, Position position);
// Qt::Orientations expandingDirections() const override;
// bool hasHeightForWidth() const override;
QSize minimumSize() const override;
void setGeometry(const QRect &rect) override;
QSize sizeHint() const override;
private:
struct ItemWrapper
{
ItemWrapper(QLayoutItem *i, Position p) {
item = i;
position = p;
}
QLayoutItem *item;
Position position;
};
enum SizeType { MinimumSize, SizeHint };
QSize calculateSize(SizeType sizeType) const;
QList<ItemWrapper *> list; // 使用list管理布局的项目
};
#endif // BORDERLAYOUT_H
BorderLayout.cpp
#include "borderlayout.h"
BorderLayout::BorderLayout(QWidget *parent, const QMargins &margins, int spacing)
: QLayout(parent)
{
setContentsMargins(margins); // 设置页边距
setSpacing(spacing); // 设置间隔
}
BorderLayout::BorderLayout(int spacing)
{
setSpacing(spacing); // 设置间隔
}
BorderLayout::~BorderLayout()
{
QLayoutItem *l;
while ((l = takeAt(0)))
delete l;
}
/* 增加项目 没有用到 [pure virtual] */
//void BorderLayout::addItem(QLayoutItem */*item*/)
//{}
/* 加入项目管理器list */
void BorderLayout::addWidget(QWidget *widget, Position position)
{
add(new QWidgetItem(widget), position); // 加入项目管理器list
}
/* 设置可扩展方向 */
//Qt::Orientations BorderLayout::expandingDirections() const
//{
// return Qt::Horizontal | Qt::Vertical; // 水平方向和垂直方向都可扩展
//}
/* 布局的首选高度是否取决于其宽度 */
//bool BorderLayout::hasHeightForWidth() const
//{
// return false; // 默认false
//}
/* 返回布局项目的总数量 [pure virtual] */
int BorderLayout::count() const
{
return list.size();
}
/* 根据索引返回布局项目指针 [pure virtual] */
QLayoutItem *BorderLayout::itemAt(int index) const
{
ItemWrapper *wrapper = list.value(index);
return wrapper ? wrapper->item : nullptr;
}
/*返回最小尺寸 */
QSize BorderLayout::minimumSize() const
{
return calculateSize(MinimumSize);
}
void BorderLayout::setGeometry(const QRect &rect)
{
ItemWrapper *center = nullptr;
int eastWidth = 0;
int westWidth = 0;
int northHeight = 0;
int southHeight = 0;
int centerHeight = 0;
int i;
QLayout::setGeometry(rect);
QRect rect0 = rect.adjusted (contentsMargins ().left (),contentsMargins ().top (),
-contentsMargins ().right (),-contentsMargins ().bottom ());
for (i = 0; i < list.size(); ++i) {
ItemWrapper *wrapper = list.at(i);
QLayoutItem *item = wrapper->item;
Position position = wrapper->position;
if (position == North) {
item->setGeometry(QRect(rect0.x (), rect0.y () + northHeight,
rect0.width(),
item->sizeHint().height()));
northHeight += item->geometry().height() + spacing();
}
else if (position == South) {
item->setGeometry(QRect(item->geometry().x(),
item->geometry().y(),
rect0.width(),
item->sizeHint().height()));
southHeight += item->geometry().height() + spacing();
item->setGeometry(QRect(rect0.x(),
rect0.y() + rect0.height() - southHeight + spacing(),
item->geometry().width(),
item->geometry().height()));
} else if (position == Center) {
center = wrapper;
}
}
centerHeight = rect0.height() - northHeight - southHeight;
for (i = 0; i < list.size(); ++i) {
ItemWrapper *wrapper = list.at(i);
QLayoutItem *item = wrapper->item;
Position position = wrapper->position;
if (position == West) {
item->setGeometry( QRect(
rect0.x() + westWidth,
rect0.y () + northHeight,
item->sizeHint().width(),
centerHeight));
westWidth += item->geometry().width() + spacing();
} else if (position == East) {
item->setGeometry( QRect(
item->geometry().x(),
item->geometry().y(),
item->sizeHint().width(),
centerHeight));
eastWidth += item->geometry().width() + spacing();
item->setGeometry(QRect(
rect0.x() + rect0.width() - eastWidth + spacing(),
rect0.y()+northHeight,
item->geometry().width(),
item->geometry().height()));
}
}
if (center)
center->item->setGeometry(QRect(
rect0.x ()+westWidth,
rect0.y ()+northHeight+1,
rect0.width() - eastWidth - westWidth,
centerHeight - 1));
}
QSize BorderLayout::sizeHint() const
{
return calculateSize(SizeHint);
}
// 按索引移除项目 [pure virtual]
QLayoutItem *BorderLayout::takeAt(int index)
{
if (index >= 0 && index < list.size()) {
ItemWrapper *layoutStruct = list.takeAt(index);
return layoutStruct->item;
}
return nullptr;
}
// 添加项目
void BorderLayout::add(QLayoutItem *item, Position position)
{
list.append(new ItemWrapper(item, position));
}
QSize BorderLayout::calculateSize(SizeType sizeType) const
{
QSize totalSize;
for (int i = 0; i < list.size(); ++i) {
ItemWrapper *wrapper = list.at(i);
Position position = wrapper->position;
QSize itemSize;
if (sizeType == MinimumSize)
itemSize = wrapper->item->minimumSize();
else // (sizeType == SizeHint)
itemSize = wrapper->item->sizeHint();
if (position == North || position == South || position == Center)
totalSize.rheight() += itemSize.height();
if (position == West || position == East || position == Center)
totalSize.rwidth() += itemSize.width();
}
totalSize.rwidth () += contentsMargins ().left () + contentsMargins ().right ();
totalSize.rheight () += contentsMargins ().top () + contentsMargins ().bottom ();
return totalSize;
}
总结
边界布局,自己写写挺好玩的。