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

How to set the base size of QDockWidget?



  • I've been scratching my head on how to do this for a while and nothing seems to be working.

    I have a QDockWidget on the Designer in which I have promoted the innards to a custom class. It looks like this on the designer side:

    Object                        Class
      DockWidget                    QDockWidget
      |                              |
      -> TestPanel                   -> TestWidget
    

    The TestWidget class inherits a QWidget in which I have another class, PageLayout create the contents of the widget so it can be placed inside the TestWidget class.

    The problem seems to be whenever I am creating a new page for the QTabWidget and laying it inside the QGridLayout. Not matter what I do I cannot seem to resize it from it's base size. I have tried overriding the size hint and that hasn't worked, I have tried setting all of the widgets base size in the designer and in the code, and that doesn't work either. I am running out of options and I am not sure where to go at this point.

    Here is the problematic TestPage class (header first):

    #ifndef TESTPAGE_HPP
    #define TESTPAGE_HPP
    
    #include <QWidget>
    #include <QGridLayout>
    #include <QCheckBox>
    #include <QButtonGroup>
    #include <QLabel>
    #include <QComboBox>
    #include <QRadioButton>
    #include <QStringList>
    #include <QSpinBox>
    #include <QToolButton>
    
    #include <vector>
    #include <functional>
    
    class TestPage : public QWidget
    {
        Q_OBJECT
    public:
        TestPage();
    
    signals:
    
      private:
    
        void setButtonGroup();
        void setComboBox();
        void addRow0();
        void addRow1();
        void addRow2();
        void addRow3();
        void addRow4();
        void addRow5();
        void addRow6();
        void constructLayout();
    
        QGridLayout *gridLayout = new QGridLayout();
    
        QCheckBox *rotationCheckBox  = new QCheckBox("Rotation");
        QCheckBox *timeBatchCheckBox = new QCheckBox("Time Sequence/Batch");
    
        QButtonGroup *buttonGroup = new QButtonGroup();
    
        QRadioButton *xButton = new QRadioButton();
        QRadioButton *yButton = new QRadioButton();
        QRadioButton *zButton = new QRadioButton();
    
        QSpinBox *degreesSpinbox     = new QSpinBox();
        QSpinBox *startTimeSpinbox   = new QSpinBox();
        QSpinBox *endTimeSpinbox     = new QSpinBox();
        QSpinBox *currentTimeSpinbox = new QSpinBox();
        QSpinBox *secondsSpinbox     = new QSpinBox();
    
        QLabel *degreesLabel     = new QLabel("Degrees");
        QLabel *styleLabel       = new QLabel("Style: ");
        QLabel *currentTimeLabel = new QLabel("Current Time: ");
        QLabel *startTimeLabel   = new QLabel("Start Time: ");
        QLabel *endTimeLabel     = new QLabel("End Time: ");
        QLabel *movieLenLabel    = new QLabel("Moview Length: ");
        QLabel *secondsLabel     = new QLabel("seconds");
    
        const QStringList styleList = {
          "Linear",
          "Smooth"
        };
    
        QComboBox *styleComboBox = new QComboBox();
    
        QToolButton *minusPushbutton = new QToolButton();
        QToolButton *plusPushbutton  = new QToolButton();
    
        const std::vector<std::function<void()>> rowFuncs = {
          std::bind(&TestPage::addRow0,this),
          std::bind(&TestPage::addRow1,this),
          std::bind(&TestPage::addRow2,this),
          std::bind(&TestPage::addRow3,this),
          std::bind(&TestPage::addRow4,this),
          std::bind(&TestPage::addRow5,this),
          std::bind(&TestPage::addRow6,this)
        };
    
        virtual QSize sizeHint() const;
    };
    
    #endif // TESTPAGE_HPP
    

    Source File:

    #include "testpage.hpp"
    
    TestPage::TestPage()
    {
      setButtonGroup();
      setComboBox();
      constructLayout();
      this->setLayout(gridLayout);
      this->resize(300,200);
      this->setBaseSize(300,200);
      // I've tried setting base size to sizeHint() here, did not work.
    }
    
    void TestPage::setComboBox()
    {
      styleComboBox->addItems(styleList);
    }
    
    void TestPage::setButtonGroup()
    {
      buttonGroup->addButton(xButton);
      buttonGroup->addButton(yButton);
      buttonGroup->addButton(zButton);
    }
    
    void TestPage::addRow0()
    {
      gridLayout->addWidget(rotationCheckBox,0,0,1,2);
    }
    
    void TestPage::addRow1()
    {
      gridLayout->addWidget(xButton,1,0);
    }
    
    void TestPage::addRow2()
    {
      gridLayout->addWidget(yButton,2,0);
      gridLayout->addWidget(degreesSpinbox,2,1);
      gridLayout->addWidget(degreesLabel,2,2);
      gridLayout->addWidget(styleLabel,2,4);
      gridLayout->addWidget(styleComboBox,2,5,1,2);
    }
    
    void TestPage::addRow3()
    {
      gridLayout->addWidget(zButton,3,0);
    }
    
    void TestPage::addRow4()
    {
      gridLayout->addWidget(timeBatchCheckBox,4,0,1,3);
      gridLayout->addWidget(currentTimeLabel,4,5,1,2);
    }
    
    void TestPage::addRow5()
    {
      gridLayout->addWidget(startTimeLabel,5,0);
      gridLayout->addWidget(startTimeSpinbox,5,1);
      gridLayout->addWidget(endTimeLabel,5,2);
      gridLayout->addWidget(endTimeSpinbox,5,3);
      gridLayout->addWidget(minusPushbutton,5,5);
      gridLayout->addWidget(currentTimeSpinbox,5,6);
      gridLayout->addWidget(plusPushbutton,5,7);
    }
    
    void TestPage::addRow6()
    {
      gridLayout->addWidget(movieLenLabel,6,3,1,2);
      gridLayout->addWidget(secondsSpinbox,6,6);
      gridLayout->addWidget(secondsLabel,6,7);
    }
    
    void TestPage::constructLayout()
    {
      for(const auto &fn : rowFuncs)
        fn();
    }
    
    QSize TestPage::sizeHint() const
    {
      QSize baseSize(300,200);
      return baseSize;
    }
    
    

    This class then get's set inside the PageLayout class (Header):

    #ifndef PAGELAYOUT_HPP
    #define PAGELAYOUT_HPP
    
    #include <QGridLayout>
    #include <QTabWidget>
    #include <QString>
    
    #include "testpage.hpp"
    
    #include <utility>
    
    class PageLayout : public QGridLayout
    {
    public:
        PageLayout();
    private:
        QTabWidget *tabWidget = new QTabWidget();
    
        void constructPages();
    
        std::vector<std::pair<QWidget*,const QString>> pages = {
          {new QWidget(), "Dummy"}, //a test to see if this was a problem when TestPage is commented out.
          {new TestPage(), "Basic"}
        };
    };
    
    #endif // PAGELAYOUT_HPP
    

    Source:

    #include "pagelayout.hpp"
    
    PageLayout::PageLayout()
    {
      constructPages();
      this->addWidget(tabWidget);
    }
    
    void PageLayout::constructPages()
    {
      for(const auto &page : pages)
        tabWidget->addTab(page.first,page.second);
    }
    
    

    Which then finally get's passed to the final class TestWidget which is header only:

    #ifndef TESTWIDGET_HPP
    #define TESTWIDGET_HPP
    
    #include <QWidget>
    #include <QGroupBox>
    #include <QGridLayout>
    #include <QFrame>
    
    #include "pagelayout.hpp"
    
    class TestWidget : public QWidget
    {
        Q_OBJECT
    public:
        TestWidget()
        {
          topFrame->setLayout(pageLayout);
          frameLayout->addWidget(topFrame,0,0);
          testExportFrame->setLayout(frameLayout);
          widgetLayout->addWidget(testExportFrame);
          this->setLayout(widgetLayout);
        }
    
      private:
    
        QGroupBox *testExportFrame = new QGroupBox();
        QGridLayout *frameLayout = new QGridLayout();
        QGridLayout *widgetLayout = new QGridLayout();
    
        QFrame *topFrame = new QFrame();
    
        PageLayout *pageLayout = new PageLayout();
    
    };
    
    #endif // TESTWIDGET_HPP
    

    When the program is run, the size of the QDockWidget never changes and it is really frustrating. I can set it to a maxSize and minSize, but I want the user to be able to resize the widget whenever they would like to. The Page that I have provided seems to be the problematic one as the other pages in the QTabWidget that I have created do not seem to be a problem. I have four other pages that I have created but isolating them one by one shows that the specific page that I have provided to be the problem.

    If there is anyone that can help me out with this problem I would appreciate it.

    If you want to build this project, simply add the files that I have provided to a new project, place a QDockWidget in the designer, and simply rename them to the Object to what I have provided up top. And promote the Widget underneath the Dock Widget to a TestWidget and it should compile. Or see if this link will work: https://drive.google.com/open?id=1tP_KkIzfl48va8odluWmhDgPl4VvNjDu


  • Lifetime Qt Champion

    Hi,

    I haven't fully read your code but the PageLayout class triggers warnings when I read it. Why are you subclassing a layout to put widgets in it ?

    Since you do not do anything particular with that layout, you should rather have a widget that manages that, especially since that layout only contains a tab widget.



  • @SGaist That's a fair question and to answer that it's because on the actual dock widget itself, in the production code, there are two widgets that get placed inside the dock widget itself. The topFrame contains the layout for the QTabWidget as you have pointed out. The code that is not present, botFrame contains another QGridLayout. These two then get placed inside the QGridLayout which is the layout of QGroupBox.

    Then to answer Why am I subclassing a layout to put widgets in it? I guess this is a personal decision and can be argued either way. For now, I will say that you are correct, that the Widget should manage the way the GridLayout adds widgets to them. However, I will argue that since QGridLayout is it's own class; the Widget does not "own" the widgets, rather, the layout owns the widgets since QWidget does not have a addWidgets function in it. Therefore, QGridLayout owns and is responsible for the Widgets that it owns. Hence the decision that the QWidget is the parent, which has a QGridLayout, which the QGridLayout as the Child, has the widgets that belong inside of it.

    This is a programming decision that I made with these arguments.