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. Getting QMainWindow to fit its central widget
QtWS25 Last Chance

Getting QMainWindow to fit its central widget

Scheduled Pinned Locked Moved Solved General and Desktop
14 Posts 3 Posters 9.5k Views
  • 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.
  • H Offline
    H Offline
    Harry123
    wrote on last edited by Harry123
    #1

    This question was already asked in various forms, but I cannot find a solution to my particular case.

    I am trying to create a QWidget top window that has an initial size and is resizable. The complication comes from these two facts :

    1. The widget needs a menu bar
    2. The widget cannot have a layout, because parts of it are painted, so its children need to be positioned by absolute x-y coordinates.

    To solve the first point, I have embedded the widget in the center of a QMainWindow, but am now incapable of making the QMainWindow honor the initial size requirement. I would like to avoid calculating an initial size for the QMainWindow, because I'm not sure how portable will these calculations be.

    Setting the central widget to a fixed size solves the initial size problem, but then the QMainWindow can no longer be resized. Setting a minimum size also solves it, but then it cannot be resized below that size.

    After a few hours of wrestling with the problem and trying various combinations, can someone help whose understanding exceeds mine as regarding size policies in this case ?

    1 Reply Last reply
    0
    • mrjjM Offline
      mrjjM Offline
      mrjj
      Lifetime Qt Champion
      wrote on last edited by
      #2

      hi
      Im not 100% sure about
      "making the QMainWindow honor the initial size requirement"

      Normally it would be the other way around. Making the
      widget follow size of mainwindow.

      So im not sure why you cannot add a layout to mainwindow
      and add a widget to that. so it follow mainwindow
      then in this widget u can use paintevent for drawing and also
      direct x,y pos since it has no layout inside.

      like this:
      https://www.dropbox.com/s/qsqmcyy977kidwu/harry.zip?dl=0

      the green widget would be your own widget doing drawing.

      H 1 Reply Last reply
      0
      • mrjjM mrjj

        hi
        Im not 100% sure about
        "making the QMainWindow honor the initial size requirement"

        Normally it would be the other way around. Making the
        widget follow size of mainwindow.

        So im not sure why you cannot add a layout to mainwindow
        and add a widget to that. so it follow mainwindow
        then in this widget u can use paintevent for drawing and also
        direct x,y pos since it has no layout inside.

        like this:
        https://www.dropbox.com/s/qsqmcyy977kidwu/harry.zip?dl=0

        the green widget would be your own widget doing drawing.

        H Offline
        H Offline
        Harry123
        wrote on last edited by Harry123
        #3

        @mrjj

        Thanks for answering and for the example.

        I know that QMainWindow has a layout and that is not my problem. The problem is that it resizes the widget. It is the widget that has no layout (or I wouldn't need QMainWindow).

        I would like the widget to start with a size that is determined when creating it - it is not always the same size like in your example, and the painted part is not identical for all invocations. I am forced to embed it in a QMainWindow, because otherwise having a menu is too complicated. But I wish the widget to start initially with a size that is determined at the time of its creation and force the QMainWindow to give the widget that exact size. For future resizes by the user, enlarging or reducing, the QMainWindow may do its stuff in the normal way.

        1 Reply Last reply
        0
        • mrjjM Offline
          mrjjM Offline
          mrjj
          Lifetime Qt Champion
          wrote on last edited by mrjj
          #4

          but its still not clear to me why you cannot let the widget follow mainwindow
          and then just set mainwindow to size that allow the size of the widget you want?
          If u set
          ui->IMSELFPAINTED->setMinimumSize(800,600);
          i get green area of that size. and mainwindow somewhat bigger.
          You cannot do like that?

          then later, maybe in showevent, call
          ui->IMSELFPAINTED->setMinimumSize(0,0);
          to allow any resize.

          H 1 Reply Last reply
          1
          • mrjjM mrjj

            but its still not clear to me why you cannot let the widget follow mainwindow
            and then just set mainwindow to size that allow the size of the widget you want?
            If u set
            ui->IMSELFPAINTED->setMinimumSize(800,600);
            i get green area of that size. and mainwindow somewhat bigger.
            You cannot do like that?

            then later, maybe in showevent, call
            ui->IMSELFPAINTED->setMinimumSize(0,0);
            to allow any resize.

            H Offline
            H Offline
            Harry123
            wrote on last edited by Harry123
            #5

            @mrjj

            I currently do use setMinimumSize as a stop-gap measure while developing.

            The setMinimumSize(0,0) solution is certainly much simpler than all my monkeying with size policies.

            Question: Is showEvent for the central widget safe enough, I mean is it done after all size adjustments were already set (at least until some future resize) ?

            mrjjM 1 Reply Last reply
            0
            • H Harry123

              @mrjj

              I currently do use setMinimumSize as a stop-gap measure while developing.

              The setMinimumSize(0,0) solution is certainly much simpler than all my monkeying with size policies.

              Question: Is showEvent for the central widget safe enough, I mean is it done after all size adjustments were already set (at least until some future resize) ?

              mrjjM Offline
              mrjjM Offline
              mrjj
              Lifetime Qt Champion
              wrote on last edited by
              #6

              @Harry123
              well it would be showEvent for mainwindow.
              Normally its safe yes. All sizes set and layouts resolved.

              H 1 Reply Last reply
              1
              • mrjjM mrjj

                @Harry123
                well it would be showEvent for mainwindow.
                Normally its safe yes. All sizes set and layouts resolved.

                H Offline
                H Offline
                Harry123
                wrote on last edited by
                #7

                @mrjj

                Many thanks for the idea - I will be trying that later and will report if problems.

                mrjjM 1 Reply Last reply
                0
                • H Harry123

                  @mrjj

                  Many thanks for the idea - I will be trying that later and will report if problems.

                  mrjjM Offline
                  mrjjM Offline
                  mrjj
                  Lifetime Qt Champion
                  wrote on last edited by
                  #8

                  @Harry123
                  Good luck.
                  Note.
                  I just added layout to mainwindow and then a widget. ( the green one)
                  So its not directly on centralwidget.

                  H 1 Reply Last reply
                  0
                  • Chris KawaC Online
                    Chris KawaC Online
                    Chris Kawa
                    Lifetime Qt Champion
                    wrote on last edited by Chris Kawa
                    #9

                    You don't need all this toying around. The default size policy is QSizePolicy::Preferred, which means it uses size hint of the widget when it is shown.

                    As for the menu bar - the easiest way is add it to the layout. You don't have to use that layout for any other children. It can be there just for the menu bar and you can place other children manually. Here's a demo:

                    #include <QApplication>
                    #include <QPushButton>
                    #include <QMenuBar>
                    #include <QVBoxLayout>
                    
                    struct Foo : public QWidget {
                        QSize sizeHint() const override { return QSize(400,400); }
                    };
                    
                    int main(int argc, char *argv[]) {
                        QApplication a(argc, argv);
                    
                        Foo foo;
                        foo.setLayout(new QVBoxLayout()); //use a layout for menu bar
                        foo.layout()->setMenuBar(new QMenuBar());
                        foo.layout()->menuBar()->addAction(new QAction("Hi!", &foo));
                    
                        QPushButton* p = new QPushButton(&foo); //don't use layout, place it manually
                        p->move(100,100);
                    
                        foo.show();
                    
                        return a.exec();
                    }
                    

                    If you really don't want the layout for some reason here's the version with main window wrapper, but it's not really necessary:

                    #include <QApplication>
                    #include <QPushButton>
                    #include <QMenuBar>
                    
                    struct Foo : public QWidget {
                        QSize sizeHint() const override { return QSize(400,400); }
                    };
                    
                    int main(int argc, char *argv[])
                    {
                        QApplication a(argc, argv);
                    
                        QMainWindow w;
                        w.setMenuBar(new QMenuBar()); //use the built-in layout for menu bar
                        w.menuBar()->addAction("Hi!");
                        w.setCentralWidget(new Foo); //place the widget in built-in layout
                    
                        QPushButton* p = new QPushButton(w.centralWidget());  //place the child manually
                        p->move(100,100);
                    
                        w.show();
                    
                        return a.exec();
                    }
                    
                    H 1 Reply Last reply
                    1
                    • Chris KawaC Chris Kawa

                      You don't need all this toying around. The default size policy is QSizePolicy::Preferred, which means it uses size hint of the widget when it is shown.

                      As for the menu bar - the easiest way is add it to the layout. You don't have to use that layout for any other children. It can be there just for the menu bar and you can place other children manually. Here's a demo:

                      #include <QApplication>
                      #include <QPushButton>
                      #include <QMenuBar>
                      #include <QVBoxLayout>
                      
                      struct Foo : public QWidget {
                          QSize sizeHint() const override { return QSize(400,400); }
                      };
                      
                      int main(int argc, char *argv[]) {
                          QApplication a(argc, argv);
                      
                          Foo foo;
                          foo.setLayout(new QVBoxLayout()); //use a layout for menu bar
                          foo.layout()->setMenuBar(new QMenuBar());
                          foo.layout()->menuBar()->addAction(new QAction("Hi!", &foo));
                      
                          QPushButton* p = new QPushButton(&foo); //don't use layout, place it manually
                          p->move(100,100);
                      
                          foo.show();
                      
                          return a.exec();
                      }
                      

                      If you really don't want the layout for some reason here's the version with main window wrapper, but it's not really necessary:

                      #include <QApplication>
                      #include <QPushButton>
                      #include <QMenuBar>
                      
                      struct Foo : public QWidget {
                          QSize sizeHint() const override { return QSize(400,400); }
                      };
                      
                      int main(int argc, char *argv[])
                      {
                          QApplication a(argc, argv);
                      
                          QMainWindow w;
                          w.setMenuBar(new QMenuBar()); //use the built-in layout for menu bar
                          w.menuBar()->addAction("Hi!");
                          w.setCentralWidget(new Foo); //place the widget in built-in layout
                      
                          QPushButton* p = new QPushButton(w.centralWidget());  //place the child manually
                          p->move(100,100);
                      
                          w.show();
                      
                          return a.exec();
                      }
                      
                      H Offline
                      H Offline
                      Harry123
                      wrote on last edited by Harry123
                      #10

                      @Chris-Kawa

                      I tested and this works, but there is a problem with the menubar now obscuring the upper part of the widget.

                      First, this would require modifying all paint functions using absolute coordinates to add a vertical offset equal to the height of the menubar, which is not a simple a job.

                      Second, it requires manually increasing the height of the widget.

                      These entail the kind of assumptions on my part regarding the GUI which I try to avoid. I prefer to let Qt do this kind of calculations, for portability.

                      1 Reply Last reply
                      0
                      • Chris KawaC Online
                        Chris KawaC Online
                        Chris Kawa
                        Lifetime Qt Champion
                        wrote on last edited by
                        #11

                        Ok then, you can use the second variant. QMainWindow will do the calculations for you, but...

                        First, this would require modifying all paint functions (...) which is not a simple a job.

                        Actually it's a one-liner:

                        void Widget:: paintEvent(QPaintEvent* evt) {
                            QPainter p(this);
                            p.setTransform(QTransform::fromTranslate(0, layout()->menuBar()->height()));
                            //paint as usual
                        }
                        

                        Second, it requires manually increasing the height of the widget. These entail the kind of assumptions on my part regarding the GUI which I try to avoid.

                        No assumptions needed:

                        QSize sizeHint() const override { return QSize(400, 400 + layout()->menuBar()->height()); }
                        

                        If you're extra paranoid you can also check layout and menubar for nullpointers, but that's not really necessary here.

                        H 1 Reply Last reply
                        2
                        • Chris KawaC Chris Kawa

                          Ok then, you can use the second variant. QMainWindow will do the calculations for you, but...

                          First, this would require modifying all paint functions (...) which is not a simple a job.

                          Actually it's a one-liner:

                          void Widget:: paintEvent(QPaintEvent* evt) {
                              QPainter p(this);
                              p.setTransform(QTransform::fromTranslate(0, layout()->menuBar()->height()));
                              //paint as usual
                          }
                          

                          Second, it requires manually increasing the height of the widget. These entail the kind of assumptions on my part regarding the GUI which I try to avoid.

                          No assumptions needed:

                          QSize sizeHint() const override { return QSize(400, 400 + layout()->menuBar()->height()); }
                          

                          If you're extra paranoid you can also check layout and menubar for nullpointers, but that's not really necessary here.

                          H Offline
                          H Offline
                          Harry123
                          wrote on last edited by Harry123
                          #12

                          @Chris-Kawa

                          I'm learning a lot from your answers, but regarding "No assumptions needed", there is one big assumption here - that the menubar is part of the widget and is displayed on top.

                          I never programmed on the Mac or Android, but I'm not too sure that this assumption will hold there or on all other platforms where Qt was or will be ported.

                          1 Reply Last reply
                          0
                          • Chris KawaC Online
                            Chris KawaC Online
                            Chris Kawa
                            Lifetime Qt Champion
                            wrote on last edited by
                            #13

                            @Harry123 said:

                            there is one big assumption here

                            Right. I'm not an expert on other platforms either. I think the menu can indeed not be a part of the window at least on Mac.
                            Ok then. The wrapper option should still be valid in these scenarios.

                            1 Reply Last reply
                            0
                            • mrjjM mrjj

                              @Harry123
                              Good luck.
                              Note.
                              I just added layout to mainwindow and then a widget. ( the green one)
                              So its not directly on centralwidget.

                              H Offline
                              H Offline
                              Harry123
                              wrote on last edited by
                              #14

                              @mrjj

                              You solution works, and works beautifully. And what's more, is probably almost guaranteed to work on all future versions of Qt.

                              So it's a hack, but who cares, as long as it works so well and is so easy to implement.

                              1 Reply Last reply
                              0
                              • N n__c referenced this topic on

                              • Login

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