PDA

View Full Version : question about size hints and size policies



Spooky
6th April 2011, 14:10
The documentation of the QWidget (http://doc.qt.nokia.com/latest/qwidget.html) states
When implementing a new widget, it is almost always useful to reimplement sizeHint() to provide a reasonable default size for the widget and to set the correct size policy with setSizePolicy().

By default, composite widgets which do not provide a size hint will be sized according to the space requirements of their child widgets.but I am not sure what the second statement actually means.

Imagine if I have 2 QWidgets. The first QWidget will be set with a Horizontal SizePolicy of QSizePolicy::Maximum. Inside the first QWidget a QTabWidget for instance is created, as a child of that QWidget and new Tabs are added.

The above statement seems to indicate that, if the custom QWidget (in my case the one that simply creates a TabWidget inside) does not reimplement sizeHint(), the sizeHint will depend on its children, i.e. the TabWidget? However, this does not seem to be the case.

If I put these 2 QWidgets, the one with the TabWidget inside and its Horizontal SizePolicy of QSizePolicy::Maximum, and an arbitrary other QWidget, with default QSizePolicy, in a QHBoxLayout, the first QWidget will not be visible, since its sizeHint().width() is 0 (or -1?).

When I implement the sizeHint() of the custom widget, e.g.
QSize sizeHint() const
{
return m_tabWidget->size();
}everything works of course, but shouldn't this be done automatically?

Added after 1 32 minutes:

It looks like the automatic behavior can be achieved by putting the Widget inside the Widget in a Layout.

However, I am having trouble achieving the same thing for Widgets that use a form from a .ui file.

Spooky
7th April 2011, 09:23
Maybe I should provide an example to make it more clear what I mean. Consider this simple Qt App with 2 Widgets. The left widget should only ever be as big as it needs to be while the right Widget should fill the rest of the space (without having to manually screw around with minimum sizes and sizeHint() implementations etc.).
MyQtApp::MyQtApp( QWidget *parent, Qt::WFlags flags )
: QMainWindow(parent, flags)
{
// create central widget
QWidget* cw = new QWidget( this );
this->setCentralWidget( cw );

// create left widget
QWidget* left = new QWidget( cw );
Ui::MyWidgetForm ui; ui.setupUi( left );

// create right widget
QWidget* right = new QWidget( cw );
right->setStyleSheet( "background-color:#FF00FF;" );

// create layout in central widget
QHBoxLayout* mainLayout = new QHBoxLayout( cw );
mainLayout->addWidget( left );
mainLayout->addWidget( right );
}The .ui file (Ui::MyWidgetForm) has only 2 changes: its horizontal Size Policy changed to Maximum and an added QTabWidget: 6198

This results in the right widget taking up all of the space, since the sizeHint of the left Widget is invalid or zero: 6202

If, on the other hand, I create the UI manually and make a Layout for the left Widget, in which the other Widgets will be stored (in this case just a bare QTabWidget):
MyQtApp::MyQtApp( QWidget *parent, Qt::WFlags flags )
: QMainWindow(parent, flags)
{
// create central widget
QWidget* cw = new QWidget( this );
this->setCentralWidget( cw );

// create left widget
QWidget* left = new QWidget( cw );
left->setSizePolicy( QSizePolicy::Maximum, QSizePolicy::Preferred );
QTabWidget* tabWidget = new QTabWidget( left );
tabWidget->addTab( new QWidget, "Tab1" );
tabWidget->addTab( new QWidget, "Tab2" );
QHBoxLayout* leftLayout = new QHBoxLayout( left );
leftLayout->addWidget( tabWidget );

// create right widget
QWidget* right = new QWidget( cw );
right->setStyleSheet( "background-color:#FF00FF;" );

// create layout in central widget
QHBoxLayout* mainLayout = new QHBoxLayout( cw );
mainLayout->addWidget( left );
mainLayout->addWidget( right );
}the sizeHint of the left Widget will be correct and the left Widget will be visible: 6203
and not expand when its parent Widget gets more space (horizontally): 6201
Without the added Layout it would be the same behavior as with the .ui version, naturally.


So, my question is: how can I achieve this with .ui files too? Adding a Layout in the .ui file does not work, since the uic generates a separate QWidget that acts as a parent for the Layout.

MarekR22
7th April 2011, 10:02
1. If widget is complex (has widget children). Widget sizeHint is calculated automatically if you are using a layout. Layout will do calculation of sizeHint based on sizeHint of children.
2. sizeHint should be implemented only when widget has defined own content (no children). For example QLabel has sizeHint value depending on text it contains.

Spooky
7th April 2011, 10:10
1. If widget is complex (has widget children). Widget sizeHint is calculated automatically if you are using a layout. Layout will do calculation of sizeHint based on sizeHint of children.
2. sizeHint should be implemented only when widget has defined own content (no children). For example QLabel has sizeHint value depending on text it contains.Yep, that's what I figured out now through trial and error. But what about user interfaces that are created via the Qt Designer? As described in my previous post, uic does not generate a generic layout for the content of the Widget. And if you define a Layout manually in the .ui, uic will create another QWidget as the parent of that Layout. And this Widget then has my actual Widget as parent, without being in a Layout and thus, sizeHint will not be calculated anymore, since the Widget created by the uic is not in a Layout.

MarekR22
7th April 2011, 10:39
You can use layout in designer. Problem is assign a layout to a widget. This can be done but bit tricky because of terrible UI concept of designer in this matter. I don't have Qt creator on this machine so I can't say now what is the correct way for attaching layout to a widget in designer.

Spooky
7th April 2011, 12:00
You can use layout in designer. Problem is assign a layout to a widget. This can be done but bit tricky because of terrible UI concept of designer in this matter. I don't have Qt creator on this machine so I can't say now what is the correct way for attaching layout to a widget in designer.I don't think there is any special way to do it. Simply drag & drop a Layout and then drag & drop a Widget into the Layout. For instance:

6204

But the problem is, that the UI compiler generates this code (from that .ui file):
class Ui_MyWidgetForm
{
public:
QWidget *verticalLayoutWidget;
QVBoxLayout *verticalLayout;
QTabWidget *tabWidget;
QWidget *tab;
QWidget *tab_2;

void setupUi(QWidget *MyWidgetForm)
{
[...]

verticalLayoutWidget = new QWidget(MyWidgetForm);
verticalLayoutWidget->setObjectName(QString::fromUtf8("verticalLayoutWidget"));
verticalLayoutWidget->setGeometry(QRect(0, 0, 160, 80));
verticalLayout = new QVBoxLayout(verticalLayoutWidget);
verticalLayout->setObjectName(QString::fromUtf8("verticalLayout"));
verticalLayout->setContentsMargins(0, 0, 0, 0);
tabWidget = new QTabWidget(verticalLayoutWidget);
tabWidget->setObjectName(QString::fromUtf8("tabWidget"));
tab = new QWidget();
tab->setObjectName(QString::fromUtf8("tab"));
tabWidget->addTab(tab, QString());
tab_2 = new QWidget();
tab_2->setObjectName(QString::fromUtf8("tab_2"));
tabWidget->addTab(tab_2, QString());

verticalLayout->addWidget(tabWidget);

[...]
} // setupUi

[...]
};It creates a unique QWidget *verticalLayoutWidget that acts as a parent for the Layout, instead of making the QWidget *MyWidgetForm the parent of the Layout. Even though in the .ui file, the QWidget *MyWidgetForm is clearly the parent of the Layout.

So instead of something like this:

6207


It is doing something like this:

6208


And thus the sizeHint() of MyWidgetForm will not be calculated, since its children (which is the QWidget* verticalLayoutWidget) are not in a layout.

Added after 54 minutes:

Aaah, hang on, now I got what you mean :). You have to make your main Widget "layouted". Instead of manually adding a Layout, you have to add your Widget(s) into the Widget and then right click on the Main Widget, go to Lay out and select an appropriate Layout from there.

6210 6209

Now it works as expected, thx!


This is indeed a little bit tricky, but it's just something you need to know, in order for everything to work as you expect.