基本图形布局示例
演示如何创建基本的图形布局。
“基本图形布局”示例展示了如何使用QGraphicsView 中的布局类:QGraphicsLinearLayout 和QGraphicsGridLayout 。此外,它还展示了如何编写您自己的自定义布局项。

窗口类定义
Window 类是QGraphicsWidget 类的子类。它有一个构造函数,其参数为QGraphicsWidget 的parent 。
class Window : public QGraphicsWidget
{
Q_OBJECT
public:
Window(QGraphicsWidget *parent = nullptr);
};Window 类的实现
Window 的构造函数会实例化一个QGraphicsLinearLayout 对象windowLayout ,并将其方向设为垂直。我们还实例化了另一个QGraphicsLinearLayout 对象linear ,其父对象为windowLayout 。接下来,我们创建一个LayoutItem 对象item ,并通过addItem() 函数将其添加到linear 中。此外,我们还为item 提供了stretchFactor 。
QGraphicsLinearLayout *windowLayout = new QGraphicsLinearLayout(Qt::Vertical);
QGraphicsLinearLayout *linear = new QGraphicsLinearLayout(windowLayout);
LayoutItem *item = new LayoutItem;
linear->addItem(item);
linear->setStretchFactor(item, 1);我们重复该过程:
- 创建一个新的
LayoutItem, - 添加项
linear,并 - 指定一个拉伸因子。
item = new LayoutItem;
linear->addItem(item);
linear->setStretchFactor(item, 3);
windowLayout->addItem(linear);随后,我们将linear 添加到windowLayout 中,嵌套两个QGraphicsLinearLayout 对象。除了QGraphicsLinearLayout 之外,我们还使用了一个QGraphicsGridLayout 对象grid ,这是一个4x3的网格,其中部分单元格跨行延伸。
我们创建了七个LayoutItem 对象,并使用addItem()函数将它们放置到grid 中,如下面的代码片段所示:
QGraphicsGridLayout *grid = new QGraphicsGridLayout(windowLayout);
item = new LayoutItem;
grid->addItem(item, 0, 0, 4, 1);
item = new LayoutItem;
item->setMaximumHeight(item->minimumHeight());
grid->addItem(item, 0, 1, 2, 1, Qt::AlignVCenter);
item = new LayoutItem;
item->setMaximumHeight(item->minimumHeight());
grid->addItem(item, 2, 1, 2, 1, Qt::AlignVCenter);
item = new LayoutItem;
grid->addItem(item, 0, 2);
item = new LayoutItem;
grid->addItem(item, 1, 2);
item = new LayoutItem;
grid->addItem(item, 2, 2);
item = new LayoutItem;
grid->addItem(item, 3, 2);
windowLayout->addItem(grid);我们添加到grid 中的第一个元素位于左上角单元格,横跨四行。 接下来的两个项目被放置在第二列,并横跨两行。每个项目的maximumHeight()和minimumHeight()均被设置为相等,以防止其垂直扩展。因此,这些项目在垂直方向上无法完全适应其单元格。于是,我们使用Qt::AlignVCenter 指定它们应在单元格内垂直居中。
最后,将grid 本身添加到windowLayout 中。与QGridLayout::addItem() 不同,QGraphicsGridLayout::addItem() 需要行和列作为参数,以指定该项目应定位在哪个单元格中。此外,如果省略rowSpan 和columnSpan 参数,它们将默认为 1。
请注意,我们无需为构建的每个LayoutItem 指定父元素,因为所有这些项都会被添加到windowLayout 中。当我们将一个项添加到布局时,它会自动被重新关联到安装该布局的控件上。
setLayout(windowLayout);
setWindowTitle(tr("Basic Graphics Layouts Example"));现在我们已经创建了grid 并将其添加到windowLayout 中,接下来使用QGraphicsWidget::setLayout()将windowLayout 安装到窗口对象上,并设置窗口标题。
LayoutItem 类定义
LayoutItem 类是QGraphicsLayoutItem 和QGraphicsItem 的子类。它具有一个构造函数、一个析构函数以及一些必需的重写方法。 由于它继承了QGraphicsLayoutItem ,因此必须重写 {QGraphicsLayoutItem::setGeometry()}{setGeometry()} 和 {QGraphicsLayoutItem::sizeHint()}{sizeHint()}。此外,它还继承了QGraphicsItem ,因此必须重写 {QGraphicsItem::boundingRect()}{boundingRect()} 和 {QGraphicsItem::paint()}{paint()}。
class LayoutItem : public QGraphicsLayoutItem, public QGraphicsItem
{
public:
LayoutItem(QGraphicsItem *parent = nullptr);
// Inherited from QGraphicsLayoutItem
void setGeometry(const QRectF &geom) override;
QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint = QSizeF()) const override;
// Inherited from QGraphicsItem
QRectF boundingRect() const override;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override;
private:
QPixmap m_pix;
};LayoutItem 类还包含QPixmap 的私有实例,m_pix 。
LayoutItem类的实现
在LayoutItem 的构造函数中,会实例化m_pix ,并将block.png 图像加载到其中。
LayoutItem::LayoutItem(QGraphicsItem *parent)
: QGraphicsLayoutItem(), QGraphicsItem(parent),
m_pix(QPixmap(QLatin1String(":/images/block.png")))
{
setGraphicsItem(this);
}我们使用Q_UNUSED() 宏来防止编译器因未使用的参数而生成警告。
void LayoutItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
QWidget *widget)
{
Q_UNUSED(widget);
Q_UNUSED(option);
QRectF frame(QPointF(0, 0), geometry().size());
const QSize pmSize = m_pix.size();
QGradientStops stops;paint() 函数的设计思路是先绘制背景矩形,然后在位图周围绘制一个矩形。
// paint a background rect (with gradient)
QLinearGradient gradient(frame.topLeft(), frame.topLeft() + QPointF(200,200));
stops << QGradientStop(0.0, QColor(60, 60, 60));
stops << QGradientStop(frame.height() / 2 / frame.height(), QColor(102, 176, 54));
//stops << QGradientStop(((frame.height() + h)/2 )/frame.height(), QColor(157, 195, 55));
stops << QGradientStop(1.0, QColor(215, 215, 215));
gradient.setStops(stops);
painter->setBrush(QBrush(gradient));
painter->drawRoundedRect(frame, 10.0, 10.0);
// paint a rect around the pixmap (with gradient)
QPointF pixpos = frame.center() - (QPointF(pmSize.width(), pmSize.height()) / 2);
QRectF innerFrame(pixpos, pmSize);
innerFrame.adjust(-4, -4, 4, 4);
gradient.setStart(innerFrame.topLeft());
gradient.setFinalStop(innerFrame.bottomRight());
stops.clear();
stops << QGradientStop(0.0, QColor(215, 255, 200));
stops << QGradientStop(0.5, QColor(102, 176, 54));
stops << QGradientStop(1.0, QColor(0, 0, 0));
gradient.setStops(stops);
painter->setBrush(QBrush(gradient));
painter->drawRoundedRect(innerFrame, 10.0, 10.0);
painter->drawPixmap(pixpos, m_pix);
}boundingRect() 的重写将左上角设置为 (0,0),其大小即为布局项geometry() 的大小。这就是我们进行绘制的区域。
setGeometry() 的重写版本仅调用其基类的实现。但是,由于这会改变 boundingRect,因此我们还必须调用prepareGeometryChange()。最后,我们根据geom.topLeft() 移动该项。
void LayoutItem::setGeometry(const QRectF &geom)
{
prepareGeometryChange();
QGraphicsLayoutItem::setGeometry(geom);
setPos(geom.topLeft());
}由于我们不希望项的大小小于位图,因此必须确保返回的大小提示大于 `m_pix`。我们还会在周围留出一些额外空间,用于稍后绘制的边框。 或者,您也可以缩放像素图,以防止项目尺寸小于像素图。首选尺寸应与最小尺寸提示相同,而最大尺寸则应设置为一个较大的数值
QSizeF LayoutItem::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
{
switch (which) {
case Qt::MinimumSize:
case Qt::PreferredSize:
// Do not allow a size smaller than the pixmap with two frames around it.
return m_pix.size() + QSize(12, 12);
case Qt::MaximumSize:
return QSizeF(1000,1000);
default:
break;
}
return constraint;
}© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.