Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

QGraphicsItemGroup in a QGraphicsLayout



  • Hi all, I am currently trying to put QGraphicsItemGroup in a QGraphicsLayout (for instance a QGraphicsLinearLayout or a QGraphicsGridLayout). I am not able to arrange properly the items.

    I have two graphics items, each inherits QGraphicsItem and QGraphicsLayoutItem. Both graphics items are instantiated in a derived class that inherits QGraphicsItemGroup. Obviously, I have overridden the virtual methods (boundingRect, paint, sizeHint and setGeometry) for both, following the Basic Graphics Layouts Example (https://doc.qt.io/qt-5/qtwidgets-graphicsview-basicgraphicslayouts-example.html).

    When I have tried to add the derived class (GraphicsItemGroup) to a graphics layout, all the grouped items stay on top of each other at the same place.

    However, when I add the graphics items without grouping them. The graphics layout arranges the items properly.

    class LayoutItem : public QGraphicsItem, public QGraphicsLayoutItem
    {
        public:
            LayoutItem(QGraphicsItem* parent, QGraphicsLayoutItem* parentLayout)
                : QGraphicsItem(parent)
                , QGraphicsLayoutItem(parentLayout)
            {
                setGraphicsItem(this);
            }
    
            QRectF boundingRect() const override;
            void paint(QPainter* painter, const QStyleOptionGraphicsItem* option,
                             QWidget* widget) override;
            void setGeometry(const QRectF& geometry) override;
            QSizeF sizeHint(Qt::SizeHint which, const QSizeF& constraint = QSizeF()) const override;
    }
    
    class LayoutItemGroup : public QGraphicsItemGroup, public QGraphicsLayoutItem
    {
        public:
            LayoutItemGroup(QGraphicsItem* parent, QGraphicsLayoutItem* parentLayout)
                 : QGraphicsItemGroup(parent),
                 , QGraphicsLayoutItem(parentLayout)
                 , m_layoutItem(std::make_unique<LayoutItem>(this, this),
                 , m_otherLayoutItem(std::make_unique<OtherLayoutItem>(m_otherLayoutItem.get(), this)
            {
                addToGroup(m_layoutItem.get());
                addToGroup(m_otherLayoutItem.get());
    
               setFlags(ItemSendsGeometryChanges);
    
                setGraphicsItem(this);
            }
    
            void setGeometry(const QRectF& geometry) override;
            QSizeF sizeHint(Qt::SizeHint which, const QSizeF& constraint = QSizeF()) const override;
    }
    

    The OtherLayoutItem class is instantiated as a child class of LayoutItem, only the paint content is different.

    class GraphicsWidget : public QGraphicsWidget
    {
        public:
            GraphicsWidget(QGraphicsItem* parent, Qt::WindowFlags wFlags)
                : QGraphicsWidget(parent, wFlags)
                , m_linearLayout(std::make_unique<QGraphicsLinearLayout>(Qt::Horizontal, this))
                , m_layoutItemGroup0(std::make_unique<LayoutItemGroup>(this, this)
                , m_layoutItemGroup1(std::make_unique<LayoutItemGroup>(this, this)
           {
                m_linearLayout->addItem(m_layoutItemGroup0.get());
                m_linearLayout->addItem(m_layoutItemGroup1.get());
                setLayout(m_linearLayout.release());
           }
    }
    

    The GraphicsWidget is then added to the QGraphicsScene.

    Is the derived class inheriting from QGraphicsItemGroup can be added to a QGraphicsLayout?


  • Lifetime Qt Champion

    Hi,

    What if you don't pass a parent to the QGraphicsLayoutItem base class ?



  • Actually it was because I have forgotten to paint depending on geometry() method... It is working now!



  • False alarm... Sorry. I have only solved the layout problem. Now the LayoutItemGroup items are placed as expected in the linear layout but I am facing another issue. The geometry changes of the parent (LayoutItemGroup) are not propagated to the child (LayoutItem). It means when the LayoutItemGroup is resized, the LayoutItem is not resized at all. I would have thought that set-up the child's parent would be sufficient.



  • Put simply, the parent of ChildLayoutItem is a LayoutItem (both inherit QGraphicsLayoutItem and QGraphicsItem). The ChildLayoutItem geometry is always { 0, 0, QSize(0, 0)) } and never changes. What can I do to fix that? It is bothering me a lot, I can not go forward without this. I really need help. Please.


  • Lifetime Qt Champion

    Can you share a minimal compilable example that shows that behaviour ?



  • @SGaist I have tried many things so there are a few comments

    Here the minimal code below:


    main.cpp:


    #include "QApplication"
    
    #include "graphicsitemgroup.h"
    #include "qgraphicslinearlayout.h"
    #include "qgraphicsscene.h"
    #include "qgraphicsview.h"
    #include "graphicswidget.h"
    
    int main(int argc, char *argv[])
    {
        QApplication app(argc, argv);
    
        auto widget = new QGraphicsWidget(nullptr, Qt::Window);
    
        auto item_0 = new GraphicsItemGroup(widget);
        auto item_1 = new GraphicsItemGroup(widget);
    
        auto linearLayout = new QGraphicsLinearLayout();
        linearLayout->addItem(item_0);
        linearLayout->addItem(item_1);
        widget->setLayout(linearLayout);
    
        QGraphicsScene scene;
        scene.addItem(widget);
    
        QGraphicsView view(&scene);
        view.setResizeAnchor(QGraphicsView::AnchorViewCenter);
        view.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
        view.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
        view.show();
    
        return app.exec();
    }
    

    graphicsitemgroup.h:


    #ifndef GRAPHICSITEMGROUP_H
    #define GRAPHICSITEMGROUP_H
    
    #include "qgraphicslayoutitem.h"
    #include "QGraphicsItemGroup"
    
    #include "qsize.h"
    
    class GraphicsItem;
    
    /**
     * @brief   Placeholder for graphics items
     */
    
    class GraphicsItemGroup : public QGraphicsLayoutItem, public QGraphicsItemGroup
    {
        public:
    	GraphicsItemGroup(QGraphicsItem* parent = nullptr);
    	virtual ~GraphicsItemGroup();
    
    	void setGeometry(const QRectF& geometry) override;
    	QSizeF sizeHint(Qt::SizeHint which, const QSizeF& constraint = QSizeF()) const override;
    //	QRectF boundingRect() const override;
    	void paint(QPainter *painter, const QStyleOptionGraphicsItem* option,
    		   QWidget* widget) override;
    
        private:
    	QSizeF m_size;
    	GraphicsItem* m_item;
    };
    
    #endif // GRAPHICSITEMGROUP_H
    

    graphicsitemgroup.cpp:


    #include "graphicsitemgroup.h"
    
    #include "graphicsitem.h"
    #include "qpainter.h"
    #include "qdebug.h"
    
    GraphicsItemGroup::GraphicsItemGroup(QGraphicsItem* parent)
        : QGraphicsItemGroup(parent)
        , m_size(QSize(100, 100))
        , m_item(new GraphicsItem(QSizeF(50, 50)))
    {
        addToGroup(m_item);
        setGraphicsItem(this);
    }
    
    GraphicsItemGroup::~GraphicsItemGroup() = default;
    
    void GraphicsItemGroup::setGeometry(const QRectF& geometry)
    {
        prepareGeometryChange();
        QGraphicsLayoutItem::setGeometry(geometry);
        setPos(geometry.topLeft());
    
        qDebug() << __PRETTY_FUNCTION__;
    }
    
    QSizeF GraphicsItemGroup::sizeHint(Qt::SizeHint which, const QSizeF& constraint) const
    {
        switch (which)
        {
    	case Qt::MinimumSize:
    	case Qt::PreferredSize:
    	    return m_size;
    	case Qt::MaximumSize:
    	default:
    	    break;
        }
    
        return constraint;
    }
    
    //QRectF GraphicsItemGroup::boundingRect() const
    //{
    //    return QRectF(QPointF(0, 0), geometry().size());
    //}
    
    void GraphicsItemGroup::paint(QPainter* painter, const QStyleOptionGraphicsItem* option,
    			      QWidget* widget)
    {
        painter->drawRect(QRectF(QPointF(0, 0), geometry().size()));
    }
    

    graphicsitem.h:


    #ifndef GRAPHICSITEM_H
    #define GRAPHICSITEM_H
    
    #include "qgraphicslayoutitem.h"
    #include "qgraphicsitem.h"
    
    #include "qsize.h"
    
    class QRectF;
    class QPainter;
    class QStyleOptionGraphicsItem;
    
    class GraphicsItem : /*public QGraphicsLayoutItem,*/ public QGraphicsItem
    {
        public:
    	GraphicsItem(QSizeF size, QGraphicsItem* parent = nullptr);
    	virtual ~GraphicsItem();
    
    //	void setGeometry(const QRectF& geometry) override;
    //	QSizeF sizeHint(Qt::SizeHint which, const QSizeF& constraint = QSizeF()) const override;
    	QRectF boundingRect() const override;
    	void paint(QPainter *painter, const QStyleOptionGraphicsItem* option,
    		   QWidget* widget) override;
    
        private:
    	QSizeF m_size;
    };
    
    #endif
    

    graphicsitem.cpp:


    #include "graphicsitem.h"
    
    #include "qpainter.h"
    #include "qrect.h"
    #include "qdebug.h"
    
    GraphicsItem::GraphicsItem(QSizeF size, QGraphicsItem* parent)
        : QGraphicsItem(parent)
        , m_size(size)
    {
    //    setGraphicsItem(this);
    }
    
    GraphicsItem::~GraphicsItem() = default;
    
    //void GraphicsItem::setGeometry(const QRectF& geometry)
    //{
    //    prepareGeometryChange();
    //    QGraphicsLayoutItem::setGeometry(geometry);
    //    setPos(geometry.topLeft());
    //
    //    qDebug() << __PRETTY_FUNCTION__;
    //}
    //
    //QSizeF GraphicsItem::sizeHint(Qt::SizeHint which, const QSizeF& constraint) const
    //{
    //    switch (which)
    //    {
    //	case Qt::MinimumSize:
    //	case Qt::PreferredSize:
    //	    return m_size;
    //	case Qt::MaximumSize:
    //	default:
    //	    break;
    //    }
    //
    //    return constraint;
    //}
    
    QRectF GraphicsItem::boundingRect() const
    {
        return QRectF(QPointF(20, 20), m_size);
    }
    
    void GraphicsItem::paint(QPainter *painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
    {
        painter->drawRect(boundingRect());
    }
    
    

    CMakeLists.txt:


    cmake_minimum_required(VERSION 3.0)
    
    project(GraphicsLayoutExample)
    
    find_package(Qt5
        COMPONENTS
            Core      REQUIRED
            Widgets   REQUIRED
            Gui       REQUIRED
    )
    
    add_executable(${CMAKE_PROJECT_NAME}
        main.cpp
        graphicsitemgroup.cpp
        graphicsitem.cpp
    )
    
    target_include_directories(${CMAKE_PROJECT_NAME} PUBLIC .)
    
    target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE Qt5::Widgets Qt5::Core Qt5::Gui)
    

    I would like to have the graphics item (here a little rectangle) to be resized depending on the a graphics item group (the latter paints another rectangle just to have a visual on what is going on). In the future, I have planned to put two graphics items (one over the other) in the group. Thanks for your help.