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

Nested box layouts giving unexpected results



  • I have created a base class which I want to use as a default widget template for the layout of each page within my window. I have nested 3 horizontal box layouts top/middle/bottom and I have set them inside a vertical layout.

    Unfortunately I am getting unexpected results when I run my application and I am unable to workout what the issue is.

    Below is a mockup of what I want to achieve, a screenshot of the actual output and then the relevant source code.

    Thank you.

    0_1544630803240_mockup.PNG
    0_1544630816002_Qt Window template.PNG

    CertTool.cpp

    CertTool::CertTool() :
              QMainWindow()
    {
      pLayout = new QHBoxLayout(this);
      pContainer = new QWidget(this);
      pContainer->setLayout(pLayout);
    
      pPageOne = new PageOne();
      pPageTwo = new PageTwo(this);
      pPageThree = new PageThree(this);
    
      pStackedWidget = new QStackedWidget(this);
    
      // Add pages to stacked widget
      pStackedWidget->addWidget(pPageOne);
      pStackedWidget->addWidget(pPageTwo);
      pStackedWidget->addWidget(pPageThree);
    
      // Set Page One as start page
      pStackedWidget->setCurrentWidget(pPageOne);
    
      pLayout->addWidget(pStackedWidget);
      setCentralWidget(pContainer);
    
      // Window settings
      window()->setWindowTitle("App");
      window()->setMinimumSize(600,450);
    
      // Connect pages to CertTool to allow changing of stacked widget index
      connect(pPageOne, SIGNAL(setPage(int)), this, SLOT(setPage(int)));
      connect(pPageTwo, SIGNAL(setPage(int)), this, SLOT(setPage(int)));
      connect(pPageThree, SIGNAL(setPage(int)), this, SLOT(setPage(int)));
    }
    
    

    windowlayout.cpp (base class)

    WindowLayout::WindowLayout(QWidget *pParent) :
                  QWidget(pParent)
    {
      //Initialise nested layout
      pTopLayout = new QHBoxLayout(this);
      pMiddleLayout = new QHBoxLayout(this);
      pBottomLayout = new QHBoxLayout(this);
      pMainLayout = new QVBoxLayout(this);
    
      pContainer = new QWidget(this);
    
      // Initialise top layout variables
      pTitle = new QLabel(tr("Title"), this);
    
      // Initialise middle layout variables
    
    
      // Initialise bottom layout variables
      pBackButton = new QPushButton(tr("Back"), this);
      pNextButton = new QPushButton(tr("Next"), this);
      pCancelButton = new QPushButton(tr("Cancel"), this);
      pCertificateButton = new QPushButton(tr("View Certificates"), this);
    
      // Add widgets to top layout
      pTopLayout->addWidget(pTitle);
    
      // Add widgets to bottom layout
      pBottomLayout->addWidget(pCertificateButton);
      pBottomLayout->addWidget(pBackButton);
      pBottomLayout->addWidget(pNextButton);
      pBottomLayout->addWidget(pCancelButton);
    
      pMainLayout->addLayout(pTopLayout);
      pMainLayout->addLayout(pMiddleLayout);
      pMainLayout->addLayout(pBottomLayout);
    
      pContainer->setLayout(pMainLayout);
    }
    

    pageone.cpp (derived class)

    PageOne::PageOne(WindowLayout *pParent) :
             WindowLayout(pParent)
    {
      QHBoxLayout *pLayout = new QHBoxLayout(this);
    
      pMainText = new QLabel(tr("Body text"), this);
      pLayout->addWidget(pMainText);
    
      pMiddleLayout->addLayout(pLayout);
    }
    

  • Qt Champions 2017

    @AaronKelsey said in Nested box layouts giving unexpected results:

    WindowLayout

    1. WindowLayout constructor is constructing the entire UI. While constructing the four layout you are passing the parent as this. Just pass the parent only for pMainLayout. Don't pass for the rest.
     pTopLayout = new QHBoxLayout;
     pMiddleLayout = new QHBoxLayout;
     pBottomLayout = new QHBoxLayout;
     pMainLayout = new QVBoxLayout(this);
    

    You are not adding anything for pMiddleLayout in the constructor. So it is empty.

    1. After this you are constructing something more in PageOne.
    QHBoxLayout *pLayout = new QHBoxLayout(this);
    

    Don't pass this again here.

    1. Why are creating the QWidget(this) and setting the mainLayout. Again one more confusion. Set the top layout to your top widget.

    Question for you -

    Is the PageOne is your top widget ?



  • @dheerendra

    1. I have adjusted my code with what you have said here

    2. I have not added anything in pMiddleLayout in the WindowLayout constructor as this intended to be left empty. In page one I have added a text label into pMiddleLayout as each page will add their own content to the middle layout.

    QHBoxLayout *pLayout = new QHBoxLayout(this); <- This is intended to be the main layout for each page which will then be added to pMiddleLayout, is this not the correct way to do this?

    1. Sorry but I do not understand what you mean by this point?

    I am also unclear on this question, PageOne is the widget that will be used within pMiddleLayout and be a content filler.


  • Qt Champions 2017

    You are doing too many layouts, widgets etc. Passing so many things everywhere. It is very difficult to explain. Please provide us the complete compilable code. We can modify and tell you.

    Now I have just modified your code to do something like follows.

    CertTool::CertTool(QWidget *parent)
        : QMainWindow(parent)
    {
        pPageOne = new PageOne();
        pPageTwo = new PageTwo(this);
        pPageThree = new PageThree(this);
    
        pStackedWidget = new QStackedWidget(this);
    
        // Add pages to stacked widget
        pStackedWidget->addWidget(pPageOne);
        pStackedWidget->addWidget(pPageTwo);
        pStackedWidget->addWidget(pPageThree);
    
        // Set Page One as start page
        pStackedWidget->setCurrentWidget(pPageOne);
    
        setCentralWidget(pStackedWidget);
    
        // Window settings
        window()->setWindowTitle("App");
        window()->setMinimumSize(600,450);
    
        // Connect pages to CertTool to allow changing of stacked widget index
        connect(pPageOne, SIGNAL(setPage(int)), this, SLOT(setPage(int)));
        connect(pPageTwo, SIGNAL(setPage(int)), this, SLOT(setPage(int)));
        connect(pPageThree, SIGNAL(setPage(int)), this, SLOT(setPage(int)));
    }
    
    WindowLayout::WindowLayout(QWidget *parent) : QWidget(parent)
    {
    
        //Initialise nested layout
          pTopLayout = new QHBoxLayout;
          pMiddleLayout = new QHBoxLayout;
          pBottomLayout = new QHBoxLayout;
          pMainLayout = new QVBoxLayout;
    
          // Initialise top layout variables
          pTitle = new QLabel(tr("Title"), this);
    
          // Initialise middle layout variables
    
          // Initialise bottom layout variables
          pBackButton = new QPushButton(tr("Back"), this);
          pNextButton = new QPushButton(tr("Next"), this);
          pCancelButton = new QPushButton(tr("Cancel"), this);
          pCertificateButton = new QPushButton(tr("View Certificates"), this);
    
          // Add widgets to bottom layout
          pBottomLayout->addWidget(pCertificateButton);
          pBottomLayout->addWidget(pBackButton);
          pBottomLayout->addWidget(pNextButton);
          pBottomLayout->addWidget(pCancelButton);
    
          pMainLayout->addWidget(pTitle);
          pMainLayout->addLayout(pMiddleLayout);
          pMainLayout->addLayout(pBottomLayout);
    
          this->setLayout(pMainLayout);
    }
    
    PageOne::PageOne(WindowLayout *pParent):WindowLayout(pParent)
    {  
        pMainText = new QLabel(tr("Body text"), this);
        pMiddleLayout->addLayout(pMainText);
    }
    

    Since I don't have complete code, I cannot guarantee the above code compilation.



  • @dheerendra
    Here is the complete code

    Full source code here

    My intended outcome for this code is to inherit each page from WindowLayout, and be able to navigate between each page using the buttons located in the BottomLayout.


  • Lifetime Qt Champion

    Hi,

    Just to be sure, are you not re-implementing QWizard ?


  • Qt Champions 2017

    Let us do one-by-one. Otherwise it is very difficult to fix your issue.

    1. Let us take only windowlayout class.
    2. Constructor- Remove all the code.
    3. Just create only buttons.
    4. Add all these buttons to horizontal layout(pBottomLayout).
    5. this.setLayout(pBottomLayout).
    6. Create the object of WindowLayout in main.cpp
    7. Display it.
    8. If you see all the buttons in the horizontal manner, then your first step is complete.

    If are able to do this, then we can get into next step.

    Also consider @SGaist suggestion on using the Wizard as well.



  • @dheerendra
    I have reduced my code and I have been able to add 4 QPushButtons to a QHBoxLayout and display them horizontally. I have then added the layout to a QFrame widget and it display on the screen at 0,0 of the window. I have then added the frame widget to a QVBoxLayout but it just will not be added to it. when I use pMainLayout->addWidget(pBottomFrame) I expected it to be put inside the vetical layout but nothing happens.

    #include "windowlayout.h"
    
    WindowLayout::WindowLayout(QWidget *pParent) :
                  QWidget(pParent)
    {
      pBottomLayout = new QHBoxLayout();
      pMainLayout = new QVBoxLayout();
    
      QFrame* pBottomFrame = new QFrame(this);
      pBottomFrame->setFrameStyle(QFrame::Panel | QFrame::Raised);
      pBottomFrame->setLineWidth(2);
    
      pBackButton = new QPushButton(tr("Back"), this);
      pNextButton = new QPushButton(tr("Next"), this);
      pCancelButton = new QPushButton(tr("Cancel"), this);
      pCertificateButton = new QPushButton(tr("View Certificates"), this);
    
      // Add widgets to bottom layout
      pBottomLayout->addWidget(pCertificateButton);
      pBottomLayout->addWidget(pBackButton);
      pBottomLayout->addWidget(pNextButton);
      pBottomLayout->addWidget(pCancelButton);
    
      pBottomFrame->setLayout(pBottomLayout);
      //pBottomFrame->move(50,50);
    
      pMainLayout->addWidget(pBottomFrame);
    
      //QLabel* pLabel = new QLabel("Label");
      //pMainLayout->addWidget(pLabel);
    }
    
    

  • Qt Champions 2017

    Hang on. Don't do too many things. Just add buttons, horizontal layout and set layout. Then show it. Does it show the 4 buttons. Confirm this first .


  • Qt Champions 2017

    Just do this in constructor. Show only WindowLayout object. See how does it go.

      pBottomLayout = new QHBoxLayout();
      pBackButton = new QPushButton(tr("Back"), this);
      pNextButton = new QPushButton(tr("Next"), this);
      pCancelButton = new QPushButton(tr("Cancel"), this);
      pCertificateButton = new QPushButton(tr("View Certificates"), this);
    
      // Add widgets to bottom layout
      pBottomLayout->addWidget(pCertificateButton);
      pBottomLayout->addWidget(pBackButton);
      pBottomLayout->addWidget(pNextButton);
      pBottomLayout->addWidget(pCancelButton);
      this->setLayout(pBottomLayout);
    


  • @dheerendra said in Nested box layouts giving unexpected results:

    pBottomLayout = new QHBoxLayout();
    pBackButton = new QPushButton(tr("Back"), this);
    pNextButton = new QPushButton(tr("Next"), this);
    pCancelButton = new QPushButton(tr("Cancel"), this);
    pCertificateButton = new QPushButton(tr("View Certificates"), this);

    // Add widgets to bottom layout
    pBottomLayout->addWidget(pCertificateButton);
    pBottomLayout->addWidget(pBackButton);
    pBottomLayout->addWidget(pNextButton);
    pBottomLayout->addWidget(pCancelButton);
    this->setLayout(pBottomLayout);

    I can confirm that this code works and shows on the screen.


  • Qt Champions 2017

    Now let us add the title in the constructor.

    QLabel *title  = new QLabel("AaronKelsey");
    QVBoxLayout *topLyt = new QVBoxLayout;
    topLyt->addWidget(title);
    topLyt->addLayout(pBottomLayout);
    this->setLayout(topLyt).
    /* this->setLayout(pBottomLayout)*/
    

    Now your final layout is topLyt. So remove So
    this->setLayout(pBottomLayout) & do like the above.



  • @dheerendra I have implemented this code and the title displays correctly, will it be difficult to set page 1/2/3 etc as the middle layout in the vertical box layout?


  • Qt Champions 2017

    Nothing is difficult. We have to apply the concept one by one. Now do the following

    QLabel *title  = new QLabel("AaronKelsey");
    QLabel  *centerContent = new QLabel("MidContent");
    QVBoxLayout *topLyt = new QVBoxLayout;
    topLyt->addWidget(title);
    topLyt->addWidget(centerContent);
    topLyt->addLayout(pBottomLayout);
    this->setLayout(topLyt).
    

    Now tell me what happens. With this you should be able to understand how things work.



  • @dheerendra
    This is the result so far:

    0_1544710484176_Capture.PNG

    I am understanding how this pieces together by adding widgets. I would like each page to use a vertical layer and for that to be added as the center content, how would you go about this?


  • Qt Champions 2017

    This is where your QStackWidget comes. Now create the instance of WindowLayout objects in your CertTool. Do the rest of the stuff as shown below.

    pPageOne = new WindowLayout
    pPageTwo = new WindowLayout
    pPageThree = new WindowLayout
    
    pStackedWidget = new QStackedWidget(this);
    
    // Add pages to stacked widget
    pStackedWidget->addWidget(pPageOne);
    pStackedWidget->addWidget(pPageTwo);
    pStackedWidget->addWidget(pPageThree);
    
    // Set Page One as start page
    pStackedWidget->setCurrentWidget(pPageOne);
    
    setCentralWidget(pStackedWidget);
    
    // Window settings
    window()->setWindowTitle("App");
    window()->setMinimumSize(600,450);
    
    // Connect pages to CertTool to allow changing of stacked widget index
    connect(pPageOne, SIGNAL(setPage(int)), this, SLOT(setPage(int)));
    connect(pPageTwo, SIGNAL(setPage(int)), this, SLOT(setPage(int)));
    connect(pPageThree, SIGNAL(setPage(int)), this, SLOT(setPage(int)));
    

Log in to reply