基本图形布局示例
演示如何创建基本图形布局。
基本图形布局示例显示了如何使用 QGraphicsView 中的布局类:QGraphicsLinearLayout 和 QGraphicsGridLayout。此外,它还显示了如何编写自己的自定义布局项。
窗口类定义
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() 需要为其参数指定行和列,指明项目应该放置在哪个单元格中。另外,如果省略了 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
的构造函数中,使用 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() 的大小。这是我们绘制的区域。
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; }
© 2024 The Qt Company Ltd。包含在此处的文档贡献是各自所有者的版权。所提供的文档是根据自由软件基金会发布的 GNU 自由文档许可证版本 1.3 的条款许可的。Qt 和相关标志在芬兰以及世界各地的其他国家是 The Qt Company Ltd 的商标。所有其他商标均为各自所有者的财产。