Qt size policy and stretch factors

Woltan picture Woltan · Jun 7, 2016 · Viewed 8.3k times · Source

How do the options size policy and stretch factors influence the size of a widget?

The image below shows previews of three differently arranged windows. For all three windows (W1-W3) the widget on the right is a QFrame widget with the horizontal and vertical size policies set to Preferred (this is the default setting). The horizontal stretch factor is set to 2. The widget on the left is a QListView widget which also has the size policies set to Preferred (by default this would be Expanding) and the horizontal stretch factor set to 1.

Different layouts

The three windows differ in the way the two widget are layout against each other.

  1. (W1) The window on the left in the image above has a central widget set to a horizontal layout resulting in a size ratio of 2/3 of the widgets that I would expect because of the stretch factors set to 2 and 1.
  2. (W2) The two widget are "connected" with each other through a QSplitter widget. The central widget is set to t horizontal layout. The results of the size of the widgets differ from W1 and are not in the ratio of 2/3.
  3. (W3) The right window "connects" the two widget also with a QSplitter like in window W2. Howevert, The QListView widget is child to a QVBoxLayout. So the QSplitter has the QFrame and a QVBoxLayout as its children.

In detail the setup for the three different windows is shown in the image below:

enter image description here

I have the following questions:

  • Why do the ratios of the two widgets differ between W1, W2 and W3?
  • The ratio in W2 seems to be affected by the stretch factors, however not with the results expected. But W3 does not seem to be influenced by the stretch factors at all. Why is that the case?

Answer

  1. The behavior of the splitter with relation to stretch factors is documented to be different than the behavior of a layout: you shouldn't expect them to look the same.

  2. The W2 & W3 should look identical if implemented as you claim. Your ui file has a mistake in it.

Here's a test case that doesn't use a .ui file:

screenshot of the example

// https://github.com/KubaO/stackoverflown/tree/master/questions/layout-stretch-triad-37680657
#include <QtWidgets>

struct Window : public QMainWindow {
   QWidget central;
   QHBoxLayout layout{&central};
   QListView view;
   QFrame frame;
   Window(const QString & title) {
      setWindowTitle(title);
      setCentralWidget(&central);
      view.resize(300, 300);
      view.setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
      frame.resize(300, 300);
      frame.setLineWidth(3);
      frame.setFrameStyle(QFrame::Box);
      resize(500, 200);
      show();
   }
};

struct Window1 : Window {
   Window1() : Window("W1") {
      layout.addWidget(&view, 1);
      layout.addWidget(&frame, 2);
   }
};

struct Window2 : Window {
   QSplitter splitter;
   Window2() : Window("W2") {
      layout.addWidget(&splitter);
      splitter.addWidget(&view);
      splitter.addWidget(&frame);
      splitter.setStretchFactor(0, 1);
      splitter.setStretchFactor(1, 2);
   }
   ~Window2() { frame.setParent(0); view.setParent(0); }
};

struct Window3 : Window {
   QSplitter splitter;
   QWidget leftWidget;
   QVBoxLayout leftLayout{&leftWidget};
   Window3() : Window("W3") {
      layout.addWidget(&splitter);
      splitter.addWidget(&leftWidget);
      splitter.addWidget(&frame);
      splitter.setStretchFactor(0, 1);
      splitter.setStretchFactor(1, 2);
      leftLayout.setMargin(0);
      leftLayout.addWidget(&view);
   }
   ~Window3() { frame.setParent(0); view.setParent(0); }
};

int main(int argc, char ** argv) {
   QApplication app{argc, argv};
   Window1 w1;
   Window2 w2;
   Window3 w3;
   w2.move(w1.pos() + QPoint(0, 75));
   w3.move(w2.pos() + QPoint(0, 75));
   return app.exec();
}