Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to equally distribute the width of QSplitter

Tags:

qt

qt-designer

I have a problem with adjusting width of QSplitter. I prepared UI in Qt Designer and it looks now like that:

Designer view:

enter image description here

And here is my object inspector:

enter image description here

My question is how to divide the width of QSplitter equally over the left and right area. I would like to get this effect as initial size and then the customer can do whatever he wants.

Effect which I would like to have is the following:

enter image description here

In other worlds, I am looking for a way to specify the splitter initial division of left and right area as 50%/50% of window width. Is there any option to obtain that?

Thank you for your help and please be forgiving, I have just started to learn Qt.

like image 295
drewpol Avatar asked May 07 '17 12:05

drewpol


3 Answers

Short answer

splitter->setSizes(QList<int>({INT_MAX, INT_MAX}));

Note: The fine tuning section may contain essential information if you want other ratios.

Explanation

QSpacer? No.

You do not need a QSpacer in this case. The goal of a spacer is to fill all available space.

QSplitter provides two methods to specify the size of its children:

1. QSplitter::setStretchFactor? No.

Although the stretch factor may seem to be what you are looking for to specify the relative size of the child widgets, it has the disadvantage for your case that the factors are relative to the initial size of the child widgets:

stretch is not the effective stretch factor; the effective stretch factor is calculated by taking the initial size of the widget and multiplying it with stretch.

Therefore, setting the stretch factor for both children to the same value (ex. 1) will not work well:

splitter->setStretchFactor(0, 1);
splitter->setStretchFactor(1, 1);

2. QSplitter::setSizes? Yes.

A better alternative is to use setSizes, because only the relative sizes matter:

The overall size of the splitter widget is not affected. Instead, any additional/missing space is distributed amongst the widgets according to the relative weight of the sizes.

So, one could think that setting both sizes to one will distribute the total size equally over both children:

splitter->setSizes(QList<int>({1, 1}));

No, because you should take into account that the minimal size policy will be enforced by replacing too small values with their minimal size:

The size policies of the widgets are preserved. That is, a value smaller than the minimal size hint of the respective widget will be replaced by the value of the hint.

So, you should use a value that is greater than the minimal size of your children, for example the greatest number that can be represented with an int, i.e. INT_MAX:

splitter->setSizes(QList<int>({INT_MAX, INT_MAX}));

Fine tuning

As suggested in the comments, INT_MAX may result in some overflow issues, depending on the calculations Qt does with those values. This may be especially the case if you want a non-equal distribution ratio. Therefore, a more sensible large value may be the desktop width/height.

// Horizontal splitter
int largeWidth = QGuiApplication::primaryScreen ()->virtualSize ().width ();
splitter->setSizes(QList<int>({largeWidth , largeWidth}));

// Vertical splitter
int largeHeight = QGuiApplication::primaryScreen ()->virtualSize ().height ();
splitter->setSizes(QList<int>({largeHeight , largeHeight}));

Further reading

Most of the time, Qt does a good job giving all widgets an appropriate size, but tweaking it can become very hard requiring some trial and error. Therefore I want to provide some extra resources which may be useful when working with layout management in Qt:

  • Qt documentation about layout management
  • A nice summary of layout management in Qt
  • Example: Using multiple QLayout items to draw a calculator
like image 167
m7913d Avatar answered Oct 16 '22 19:10

m7913d


Based on m7913d's

To equally divide a splitter use QSplitter::setSizes, each size in the list should be equal. Use QWidget::minimumSizeHint() to determine the size to use. Use the maximum width (for horizontal splitters) or the maximum height (for vertical splitters) of every widget you added to the splitter

// Example for a horizontal splitter
splitter = new QSplitter(Qt::Horizontal, this);
splitter->addWidget(widgetLeft);
splitter->addWidget(widgetRight);
auto equalWidth = std::max(widgetLeft->minimumSizeHint().width(), 
                           widgetRight->minimumSizeHint().width());
splitter->setSizes({ equalWidth, equalWidth });
// Example for a vertical splitter
splitter = new QSplitter(Qt::Vertical, this);
splitter->addWidget(widgetTop);
splitter->addWidget(widgetBottom);
auto equalHeight = std::max(widgetTop->minimumSizeHint().height(),
                            widgetBottom->minimumSizeHint().height());
splitter->setSizes({ equalHeight, equalHeight });
like image 5
Seamus Boyle Avatar answered Oct 16 '22 17:10

Seamus Boyle


I would suggest a further variation. The points of m7913d all hold and are important. But in my case (Qt5.13.2) I found that setting large enough sizes could still lead to some variations. I do not know why exactly but setting all the stretch factors to one additionally finally behaved like I wanted.

Also note that setting all stretch factors to one but using non-equal (but still large enough to avoid minimum size constraints) sizes with setSizes works, too! For example:

splitter->setStretchFactor(0,1);
splitter->setStretchFactor(1,1);
splitter->setSizes({static_cast<int>(10000 / 1.618), static_cast<int>(10000 - 10000 / 1.618)});

sets a golden ratio split.

like image 1
IceFire Avatar answered Oct 16 '22 18:10

IceFire