基本的なグラフィックレイアウトの例

基本的なグラフィックス・レイアウトの作成方法を示します。

基本的なグラフィック・レイアウトの例では、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 をインスタンス化します。windowLayout を親とする別のQGraphicsLinearLayout オブジェクトlinear をインスタンス化します。次に、LayoutItem オブジェクトitem を作成し、addItem() 関数でlinear に追加します。また、itemstretchFactor を追加します。

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

次に、linearwindowLayout に追加し、2つのQGraphicsLinearLayout オブジェクトを入れ子にします。QGraphicsLinearLayout とは別に、QGraphicsGridLayout オブジェクト、grid も使います。これは4x3のグリッドで、いくつかのセルは他の行にまたがっています。

以下のコード・スニペットに示すように、LayoutItem オブジェクトを7つ作成し、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 に追加した最初の項目は、左上のセルに配置され、4行にまたがる。次の2つの項目は2列目に配置され、2行にわたります。各項目のmaximumHeight() とminimumHeight() は、縦に展開しないように等しく設定されています。その結果、これらの項目はセルに垂直に収まりません。そこで、Qt::AlignVCenter を使って、セルの中央に縦に並ぶように指定する。

最後に、grid 自身がwindowLayout に追加される。QGridLayout::addItem() と異なり、QGraphicsGridLayout::addItem() は引数に行と列を必要とし、どのセルにアイテムを配置するかを指定する。また、rowSpancolumnSpan の引数が省略された場合、デフォルトで1になります。

これらのアイテムはすべてwindowLayout に追加されるため、作成するLayoutItem それぞれに親を指定しないことに注意してください。アイテムをレイアウトに追加すると、レイアウトがインストールされているウィジェットに自動的にリペアレントされます。

    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 のコンストラクタでは、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() 関数の背後にある考え方は、背景の矩形を描画し、その後、pixmap の周囲に矩形を描画することです。

    // 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());
}

アイテムのサイズをpixmapより小さくしたくないので、m_pix より大きいサイズヒントを返すようにします。また、アイテムがpixmapより小さくならないように、pixmapを拡大縮小することもできます。好ましいサイズは最小サイズのヒントと同じですが、最大サイズは大きな値に設定します。

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. 本文書に含まれる文書の著作権は、それぞれの所有者に帰属します。 ここで提供されるドキュメントは、Free Software Foundation が発行したGNU Free Documentation License version 1.3に基づいてライセンスされています。 Qtおよびそれぞれのロゴは、フィンランドおよびその他の国におけるThe Qt Company Ltd.の 商標です。その他すべての商標は、それぞれの所有者に帰属します。