基本图形布局示例

演示如何创建基本图形布局。

基本图形布局示例显示了如何使用 QGraphicsView 中的布局类:QGraphicsLinearLayoutQGraphicsGridLayout。此外,它还显示了如何编写自己的自定义布局项。

Screenshot of the Basic Layouts Example

窗口类定义

Window 类是 QGraphicsWidget 的子类。它有一个构造函数,其参数为 QGraphicsWidget parent

class Window : public QGraphicsWidget
{
    Q_OBJECT
public:
    Window(QGraphicsWidget *parent = nullptr);

};

窗口类实现

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() 需要为其参数指定行和列,指明项目应该放置在哪个单元格中。另外,如果省略了 rowSpancolumnSpan 参数,它们将默认为 1。

请注意,我们没有为每个构建的 LayoutItem 指定父对象,因为所有这些项都将添加到 windowLayout 中。当我们向布局中添加项时,它将被自动重新父化到布局设置的部件上。

    setLayout(windowLayout);
    setWindowTitle(tr("Basic Graphics Layouts Example"));

现在我们已经设置了 grid 并将其添加到 windowLayout 中,我们使用 QGraphicsWidget::setLayout() 将 windowLayout 安装到窗口对象上,并设置窗口标题。

LayoutItem 类定义

LayoutItem 类是 QGraphicsLayoutItemQGraphicsItem 的子类。它有一个构造函数、一个析构函数和几个必需的重实现。由于它继承了 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 的构造函数中,使用 block.png 图像将其实例化为 m_pix

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() 的大小。这是我们绘制的区域。

QRectF LayoutItem::boundingRect() const
{
    return QRectF(QPointF(0, 0), geometry().size());
}

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;
}

示例项目 @ code.qt.io

© 2024 The Qt Company Ltd。包含在此处的文档贡献是各自所有者的版权。所提供的文档是根据自由软件基金会发布的 GNU 自由文档许可证版本 1.3 的条款许可的。Qt 和相关标志在芬兰以及世界各地的其他国家是 The Qt Company Ltd 的商标。所有其他商标均为各自所有者的财产。