Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Layout issues within GraphicsItem
Forum Updated to NodeBB v4.3 + New Features

Layout issues within GraphicsItem

Scheduled Pinned Locked Moved Unsolved General and Desktop
7 Posts 2 Posters 451 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • S Offline
    S Offline
    szyq
    wrote on last edited by
    #1

    Hi,

    I 'm having trouble with layouts in general and was wondering if I'm just missing something or theres a bug. The setup is quite complex so I'll do my best to describe the issue.

    So I'm using QGraphicsView to create a node editor. Each node is a QGraphicsWidget that contains layouts and other QGraphicsWidgets.

    The structure of a node looks like this
    nodelayout.png

    I want node to always resize to its content - thats why I'm using layouts.

    Now, lets say theres a custom text edit that can resize based on it's content. The longer the string, the longer the widget.
    When I put this text edit into my node (in inputLayout), the node grows accordingly so it contains entire text edit BUT when the text edit shrinks, node does not. It seems like it's all depending on QSizePolicy I set on HeaderLayout.

    When Header layout (QGraphicsLinearLayout(Qt::Horizontal)) size policy is set to QSizePolicy::Preferred it has both Shrink and Grow flags but it doesnt shrink - it just grows.
    When I set header layout size policy to QSizePolic::Maximum, it works as expected - node shrinks and grows BUT second header element is no longer aligned to the right, which is what I want to achieve.

    To better illustrate the issue take a look at this
    layouts.gif
    There are two nodes on graphics view here.
    Each node has exactly the same layout - the only difference is between header size policy
    Header contains label (with size policy printed out) and two buttons used to resize underlying text edit.

    What I want is to have, is buttons in header to be right aligned (like in second node) and entire node to shrink/grow accordingly to its contents (like first node).

    Below you can find the code behind the example:

    #include "QtLayoutIssues.h"
    #include <QtWidgets/QApplication>
    #include "qpushbutton.h"
    #include "qtextedit.h"
    #include "qgraphicswidget.h"
    #include "qgraphicsproxywidget.h"
    #include "qgraphicslinearlayout.h"
    #include "qlabel.h"
    #include "qpainter.h"
    #include "qgraphicsview.h"
    #include "QStyleOptionGraphicsItem"
    
    
    class TestTextEdit : public QTextEdit
    {
    public:
    	static const int SIZE_DELTA = 25;
    
    	TestTextEdit(QWidget* parent = nullptr) : QTextEdit(parent) {}
    
    	void shrink() { updateSize({ -SIZE_DELTA, 0 }); }
    	void grow() { updateSize({ SIZE_DELTA, 0 }); }
    
    	void updateSize(QSize delta)
    	{
    		const QSize s = size();
    
    		// this doesn't work for some reason...
    		//setFixedSize(s + delta);
    		setFixedHeight(s.height() + delta.height());
    		setFixedWidth(s.width() + delta.width());
    		updateGeometry();
    	}
    };
    
    class TestItem : public QGraphicsWidget
    {
    public:
    	QGraphicsProxyWidget* MakeProxyWithContent(QWidget* content)
    	{
    		auto proxy = new QGraphicsProxyWidget(this);
    		proxy->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
    		proxy->setWidget(content);
    		return proxy;
    	}
    
    	TestItem(QSizePolicy::Policy headerSizePolicy, QGraphicsItem* parent = nullptr)
    		: QGraphicsWidget(parent)
    	{
    		setFlags(ItemIsSelectable | ItemIsMovable);
    
    		QGraphicsLinearLayout* mainLayout = new QGraphicsLinearLayout(Qt::Vertical);
    
    		QGraphicsLinearLayout* headerLayout = new QGraphicsLinearLayout(Qt::Horizontal);
    		headerLayout->setSizePolicy(headerSizePolicy, QSizePolicy::Maximum);
    
    		headerLayout->addItem(MakeProxyWithContent(new QLabel(QVariant::fromValue(headerSizePolicy).toString())));
    		headerLayout->addStretch();
    		auto minusButton = new QPushButton("-");
    		auto plusButton = new QPushButton("+");
    		headerLayout->addItem(MakeProxyWithContent(minusButton));
    		headerLayout->addItem(MakeProxyWithContent(plusButton));
    
    		mainLayout->addItem(headerLayout);
    
    		QGraphicsLinearLayout* bodyLayout = new QGraphicsLinearLayout(Qt::Horizontal);
    		bodyLayout->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
    
    		QGraphicsLinearLayout* inputLayout = new QGraphicsLinearLayout(Qt::Vertical);
    		QGraphicsLinearLayout* outputLayout = new QGraphicsLinearLayout(Qt::Vertical);
    
    		bodyLayout->addItem(inputLayout);
    		bodyLayout->addStretch();
    		bodyLayout->addItem(outputLayout);
    
    		auto textEdit = new TestTextEdit;
    		connect(minusButton, &QPushButton::clicked, textEdit, &TestTextEdit::shrink);
    		connect(plusButton, &QPushButton::clicked, textEdit, &TestTextEdit::grow);
    
    		inputLayout->addItem(MakeProxyWithContent(textEdit));
    
    		mainLayout->addItem(bodyLayout);
    		setLayout(mainLayout);
    	}
    
    	void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget = nullptr) override
    	{
    		QGraphicsWidget::paint(painter, option, widget);
    
    		painter->save();
    		painter->setBrush(Qt::darkBlue);
    		painter->setPen(Qt::black);
    		painter->drawRect(option->rect);
    		painter->setBrush(Qt::darkRed);
    		painter->drawRect(layout()->contentsRect());
    		painter->restore();
    	}
    };
    
    class GraphicsView : public QGraphicsView
    {
    public:
    
    	GraphicsView(QWidget* parent = nullptr) : QGraphicsView(parent)
    	{
    		QGraphicsScene* scene = new QGraphicsScene(this);
    		scene->setSceneRect(-200, -200, 400, 400);
    		setScene(scene);
    		scene->setBackgroundBrush(Qt::darkGray);
    
    		auto item1 = new TestItem(QSizePolicy::Maximum);
    		item1->moveBy(-300, -250);
    		scene->addItem(item1);
    
    		auto item2 = new TestItem(QSizePolicy::Preferred);
    		item2->moveBy(-300, 0);
    		scene->addItem(item2);
    	}
    };
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
    
    	GraphicsView* view = new GraphicsView;
    
        QMainWindow w;
        w.resize(800, 600);
        w.setCentralWidget(view);
        w.show();
    
        return a.exec();
    }
    
    
    

    I have tried all other size policy combinations with no luck and tbh it looks like a bug to me.

    Any help or advice is greatly appreciated!

    Cheers

    Pl45m4P 1 Reply Last reply
    0
    • S szyq

      Hi,

      I 'm having trouble with layouts in general and was wondering if I'm just missing something or theres a bug. The setup is quite complex so I'll do my best to describe the issue.

      So I'm using QGraphicsView to create a node editor. Each node is a QGraphicsWidget that contains layouts and other QGraphicsWidgets.

      The structure of a node looks like this
      nodelayout.png

      I want node to always resize to its content - thats why I'm using layouts.

      Now, lets say theres a custom text edit that can resize based on it's content. The longer the string, the longer the widget.
      When I put this text edit into my node (in inputLayout), the node grows accordingly so it contains entire text edit BUT when the text edit shrinks, node does not. It seems like it's all depending on QSizePolicy I set on HeaderLayout.

      When Header layout (QGraphicsLinearLayout(Qt::Horizontal)) size policy is set to QSizePolicy::Preferred it has both Shrink and Grow flags but it doesnt shrink - it just grows.
      When I set header layout size policy to QSizePolic::Maximum, it works as expected - node shrinks and grows BUT second header element is no longer aligned to the right, which is what I want to achieve.

      To better illustrate the issue take a look at this
      layouts.gif
      There are two nodes on graphics view here.
      Each node has exactly the same layout - the only difference is between header size policy
      Header contains label (with size policy printed out) and two buttons used to resize underlying text edit.

      What I want is to have, is buttons in header to be right aligned (like in second node) and entire node to shrink/grow accordingly to its contents (like first node).

      Below you can find the code behind the example:

      #include "QtLayoutIssues.h"
      #include <QtWidgets/QApplication>
      #include "qpushbutton.h"
      #include "qtextedit.h"
      #include "qgraphicswidget.h"
      #include "qgraphicsproxywidget.h"
      #include "qgraphicslinearlayout.h"
      #include "qlabel.h"
      #include "qpainter.h"
      #include "qgraphicsview.h"
      #include "QStyleOptionGraphicsItem"
      
      
      class TestTextEdit : public QTextEdit
      {
      public:
      	static const int SIZE_DELTA = 25;
      
      	TestTextEdit(QWidget* parent = nullptr) : QTextEdit(parent) {}
      
      	void shrink() { updateSize({ -SIZE_DELTA, 0 }); }
      	void grow() { updateSize({ SIZE_DELTA, 0 }); }
      
      	void updateSize(QSize delta)
      	{
      		const QSize s = size();
      
      		// this doesn't work for some reason...
      		//setFixedSize(s + delta);
      		setFixedHeight(s.height() + delta.height());
      		setFixedWidth(s.width() + delta.width());
      		updateGeometry();
      	}
      };
      
      class TestItem : public QGraphicsWidget
      {
      public:
      	QGraphicsProxyWidget* MakeProxyWithContent(QWidget* content)
      	{
      		auto proxy = new QGraphicsProxyWidget(this);
      		proxy->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
      		proxy->setWidget(content);
      		return proxy;
      	}
      
      	TestItem(QSizePolicy::Policy headerSizePolicy, QGraphicsItem* parent = nullptr)
      		: QGraphicsWidget(parent)
      	{
      		setFlags(ItemIsSelectable | ItemIsMovable);
      
      		QGraphicsLinearLayout* mainLayout = new QGraphicsLinearLayout(Qt::Vertical);
      
      		QGraphicsLinearLayout* headerLayout = new QGraphicsLinearLayout(Qt::Horizontal);
      		headerLayout->setSizePolicy(headerSizePolicy, QSizePolicy::Maximum);
      
      		headerLayout->addItem(MakeProxyWithContent(new QLabel(QVariant::fromValue(headerSizePolicy).toString())));
      		headerLayout->addStretch();
      		auto minusButton = new QPushButton("-");
      		auto plusButton = new QPushButton("+");
      		headerLayout->addItem(MakeProxyWithContent(minusButton));
      		headerLayout->addItem(MakeProxyWithContent(plusButton));
      
      		mainLayout->addItem(headerLayout);
      
      		QGraphicsLinearLayout* bodyLayout = new QGraphicsLinearLayout(Qt::Horizontal);
      		bodyLayout->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
      
      		QGraphicsLinearLayout* inputLayout = new QGraphicsLinearLayout(Qt::Vertical);
      		QGraphicsLinearLayout* outputLayout = new QGraphicsLinearLayout(Qt::Vertical);
      
      		bodyLayout->addItem(inputLayout);
      		bodyLayout->addStretch();
      		bodyLayout->addItem(outputLayout);
      
      		auto textEdit = new TestTextEdit;
      		connect(minusButton, &QPushButton::clicked, textEdit, &TestTextEdit::shrink);
      		connect(plusButton, &QPushButton::clicked, textEdit, &TestTextEdit::grow);
      
      		inputLayout->addItem(MakeProxyWithContent(textEdit));
      
      		mainLayout->addItem(bodyLayout);
      		setLayout(mainLayout);
      	}
      
      	void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget = nullptr) override
      	{
      		QGraphicsWidget::paint(painter, option, widget);
      
      		painter->save();
      		painter->setBrush(Qt::darkBlue);
      		painter->setPen(Qt::black);
      		painter->drawRect(option->rect);
      		painter->setBrush(Qt::darkRed);
      		painter->drawRect(layout()->contentsRect());
      		painter->restore();
      	}
      };
      
      class GraphicsView : public QGraphicsView
      {
      public:
      
      	GraphicsView(QWidget* parent = nullptr) : QGraphicsView(parent)
      	{
      		QGraphicsScene* scene = new QGraphicsScene(this);
      		scene->setSceneRect(-200, -200, 400, 400);
      		setScene(scene);
      		scene->setBackgroundBrush(Qt::darkGray);
      
      		auto item1 = new TestItem(QSizePolicy::Maximum);
      		item1->moveBy(-300, -250);
      		scene->addItem(item1);
      
      		auto item2 = new TestItem(QSizePolicy::Preferred);
      		item2->moveBy(-300, 0);
      		scene->addItem(item2);
      	}
      };
      
      int main(int argc, char *argv[])
      {
          QApplication a(argc, argv);
      
      	GraphicsView* view = new GraphicsView;
      
          QMainWindow w;
          w.resize(800, 600);
          w.setCentralWidget(view);
          w.show();
      
          return a.exec();
      }
      
      
      

      I have tried all other size policy combinations with no luck and tbh it looks like a bug to me.

      Any help or advice is greatly appreciated!

      Cheers

      Pl45m4P Offline
      Pl45m4P Offline
      Pl45m4
      wrote on last edited by Pl45m4
      #2

      @szyq

      This could be a case for a QSplitter. It will push your buttons to the right and shrink with your widget, so your buttons move left again while resizing.
      https://doc.qt.io/qt-5/qsplitter.html

      Edit:
      Place your splitter left to your buttons inside your header layout.


      If debugging is the process of removing software bugs, then programming must be the process of putting them in.

      ~E. W. Dijkstra

      1 Reply Last reply
      0
      • S Offline
        S Offline
        szyq
        wrote on last edited by szyq
        #3

        @Pl45m4 thanks for reply, unfortunately using QSplitter dosn't change anything. Buttons are kept on the right but entire node is not shrinking.

        I've tried it like this

        QGraphicsLinearLayout* headerLayout = new QGraphicsLinearLayout(Qt::Horizontal);
        headerLayout->setSizePolicy(headerSizePolicy, QSizePolicy::Maximum);
        
        auto splitter = new QSplitter(Qt::Horizontal);
        splitter->addWidget(new QLabel(QVariant::fromValue(headerSizePolicy).toString()));
        splitter->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
        
        headerLayout->addItem(MakeProxyWithContent(splitter));
        		
        auto minusButton = new QPushButton("-");
        auto plusButton = new QPushButton("+");
        
        headerLayout->addItem(MakeProxyWithContent(minusButton));
        headerLayout->addItem(MakeProxyWithContent(plusButton));
        

        and also tried to add buttons to splitter but with no luck.

        Pl45m4P 1 Reply Last reply
        0
        • S szyq

          @Pl45m4 thanks for reply, unfortunately using QSplitter dosn't change anything. Buttons are kept on the right but entire node is not shrinking.

          I've tried it like this

          QGraphicsLinearLayout* headerLayout = new QGraphicsLinearLayout(Qt::Horizontal);
          headerLayout->setSizePolicy(headerSizePolicy, QSizePolicy::Maximum);
          
          auto splitter = new QSplitter(Qt::Horizontal);
          splitter->addWidget(new QLabel(QVariant::fromValue(headerSizePolicy).toString()));
          splitter->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
          
          headerLayout->addItem(MakeProxyWithContent(splitter));
          		
          auto minusButton = new QPushButton("-");
          auto plusButton = new QPushButton("+");
          
          headerLayout->addItem(MakeProxyWithContent(minusButton));
          headerLayout->addItem(MakeProxyWithContent(plusButton));
          

          and also tried to add buttons to splitter but with no luck.

          Pl45m4P Offline
          Pl45m4P Offline
          Pl45m4
          wrote on last edited by
          #4

          What is your mainLayout's sizePolicy? You need to keep it as small as possible to make your whole widget shrink again.


          If debugging is the process of removing software bugs, then programming must be the process of putting them in.

          ~E. W. Dijkstra

          1 Reply Last reply
          0
          • S Offline
            S Offline
            szyq
            wrote on last edited by szyq
            #5

            @Pl45m4 mainLayout has default size policy so I believe its QSizePolicy::Preferred, QSizePolicy::Preferred.
            Setting it to Maximum, Maximum doesn't change anything

            The problem is that header layout shrinks when its size policy is set to Maximum (it has shrink flag on) but not when it's set to Preferred (when it has Shrink AND grow flag)

            1 Reply Last reply
            0
            • S Offline
              S Offline
              szyq
              wrote on last edited by
              #6

              Anyone? I could really use a hand with this one...

              Pl45m4P 1 Reply Last reply
              0
              • S szyq

                Anyone? I could really use a hand with this one...

                Pl45m4P Offline
                Pl45m4P Offline
                Pl45m4
                wrote on last edited by
                #7

                @szyq

                Just realized, I was mixing QSplitter and QSpacer...

                Unfortunately this wouldnt change anything, because you cant use QSpacerItems in QGraphicsLinearLayout since they are no QGraphicsLayoutItems


                If debugging is the process of removing software bugs, then programming must be the process of putting them in.

                ~E. W. Dijkstra

                1 Reply Last reply
                0

                • Login

                • Login or register to search.
                • First post
                  Last post
                0
                • Categories
                • Recent
                • Tags
                • Popular
                • Users
                • Groups
                • Search
                • Get Qt Extensions
                • Unsolved