c++qtqt5qgraphicssceneqgraphicswidget

How do I scroll all the contents of my custom QGraphicsWidgets?


I have a custom QGraphicsWidget called "TestContentArea" which is added to a QGraphicsScene. In my custom QGraphicsWidget, I am adding a number of children QGraphicsWidgets added to its layout. The problem I have is the contents of custom QGraphicsWidget extends beyond the area the user can scroll. Attached below is a minimum example that shows this. Only 11 rectangles are visible out of a 100. How can I scroll all 100 children widgets in this example?

MainWindow.h:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QGraphicsScene>
#include <QGraphicsView>

#include "TestContentArea.h"

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    //Constructor
    explicit MainWindow(QWidget *parent = nullptr);
    //Deconstructor
    ~MainWindow();

private:
    //Private members
    Ui::MainWindow *ui;
    QGraphicsScene * m_scene;
    QGraphicsView * m_view;
    TestContentArea * m_testContentArea;
};

#endif // MAINWINDOW_H

MainWindow.cpp:

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    m_scene = new QGraphicsScene(0, 0, 880, 630, this);

    m_view = new QGraphicsView(m_scene, this);
    m_view->setAlignment(Qt::AlignLeft | Qt::AlignTop);

    m_testContentArea = new TestContentArea();
    m_scene->addItem(m_testContentArea);

    setCentralWidget(m_view);
}

MainWindow::~MainWindow()
{
    delete ui;
}

TestContentArea.h:

#ifndef TESTCONTENTAREA_H
#define TESTCONTENTAREA_H

#include <QGraphicsWidget>
#include <QGraphicsLinearLayout>


class TestContentArea: public QGraphicsWidget
{
public:
    //Constructor
    TestContentArea(QGraphicsWidget* parent = nullptr);

private:
    //Private members
    QGraphicsLinearLayout * m_layout;

};

#endif // TESTCONTENTAREA_H


TestContentArea.cpp:

#include "TestContentArea.h"

#include <QGraphicsLinearLayout>
#include <QGraphicsRectItem>
#include "RectangleWidget.h"

TestContentArea::TestContentArea(QGraphicsWidget* parent)
{
    Q_UNUSED(parent);

    setAcceptHoverEvents(true);

    m_layout = new QGraphicsLinearLayout(Qt::Vertical, this);
    m_layout->setContentsMargins(30, 30, 0, 0);

    for(int i= 0; i< 100; i++)
    {
        RectangleWidget* rect = new RectangleWidget(this);
        m_layout->addItem(rect);

    }

    setLayout(m_layout);

}

RectangleWidget.h:

#ifndef Rectangle_H
#define Rectangle_H

#include <QGraphicsWidget>
#include <QJsonObject>
#include <QGraphicsLinearLayout>
#include <QGraphicsProxyWidget>
#include <QPushButton>

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

    // Overriding functions
    QRectF boundingRect() const override;
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override;

private:
    //Private member variables
    QGraphicsLinearLayout * m_layout;
    QPushButton * m_button;


};

#endif // Rectangle_H

RectangleWidget.cpp:

#include "RectangleWidget.h"
#include <QPainter>

RectangleWidget::RectangleWidget(QGraphicsWidget *parent)
{

}

void RectangleWidget::paint(QPainter *painter,
    const QStyleOptionGraphicsItem *option, QWidget *widget /*= 0*/)
{
    Q_UNUSED(widget);
    Q_UNUSED(option);

    //Draw border
    painter->drawRoundedRect(boundingRect(), 0.0, 0.0);
}

QRectF RectangleWidget::boundingRect() const
{

    return QRectF(QPointF(0,0), geometry().size());
}

Only 11 rectangles visible out of 100


Solution

  • The problem is caused because you are defining a very small sceneRect compared to what it should be, and that is that the QScrollBar take as references the SceneRect to establish its range. So the solution is simple, do not set any sceneRect so that Qt calculates it by itself, for it changes:

    m_scene = new QGraphicsScene(0, 0, 880, 630, this);
    

    to:

    m_scene = new QGraphicsScene(this);