Allignment of a QLabel and a QCheckBox in a BoxLayout gives unexpected result - qt

when i add a QLabel and QCheckBoxs to either a QVBoxLayout or a QHBoxLayout i would expect them to be evenly distributed but the checkboxes will allign tight at the very bottom (in the above example) and the label will be centered on the resulting free space in the widget. How can i change this behaviour to distribute all 3 widgets evenly?
Many thanks.
This is the example code:
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
QLabel* l = new QLabel("Hi");
QCheckBox* c = new QCheckBox("Label");
QCheckBox* c2 = new QCheckBox("Label");
l->setText("Hi");
QVBoxLayout* v = new QVBoxLayout;
v->addWidget(l);
v->addWidget(c);
v->addWidget(c2);
setLayout(v);
ui->setupUi(this);
}
And this is the result:

Take a look at QSizePolicy. You need to setSizePolicy for your QLabel and QCheckBoxes to be QSizePolicy::Preferred, from the docs:
The default policy is Preferred/Preferred, which means that the widget
can be freely resized, but prefers to be the size sizeHint() returns.
Button-like widgets set the size policy to specify that they may
stretch horizontally, but are fixed vertically. The same applies to
lineedit controls (such as QLineEdit, QSpinBox or an editable
QComboBox) and other horizontally orientated widgets (such as
QProgressBar).
Currently, your QLabel has preferred height, while both of the QCheckBoxes has fixed height. That means that the QLabel will be expanded automatically to take up any additional vertical space (that can't be taken by the QCheckBoxes.
So, In order to set all your widgets to Preferred height, you need to add the following to your constructor:
l->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
c->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
c2->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
Another option, would be to add spacers around each one of the widgets, like this:
v->addStretch();
v->addWidget(l);
v->addStretch();
v->addWidget(c);
v->addStretch();
v->addWidget(c2);
v->addStretch();
setLayout(v);
This way QSpacerItems will take up all the additional space.

Related

Different alignment of widgets in QGridLayout

The following code (Qt 5, same behaviour with Qt 4.8) uses a QGridLayout to add widgets above and to the left of a QScrollArea (to serve as a kind of header later):
#include <QApplication>
#include <QMainWindow>
#include <QGridLayout>
#include <QScrollArea>
class ColoredWidget : public QWidget {
public:
ColoredWidget(const QColor& color, QWidget* parent) : QWidget(parent) {
QPalette pal;
QBrush brush(color);
brush.setStyle(Qt::SolidPattern);
pal.setBrush(QPalette::Active, QPalette::Window, brush);
setPalette(pal);
setAutoFillBackground(true);
}
};
class MainWindow : public QMainWindow {
public:
MainWindow(QWidget* parent) : QMainWindow(parent) {
resize(300, 400);
QWidget* centralwidget = new ColoredWidget(QColor(0xff, 0xf0, 0xb5), this);
QGridLayout* layout = new QGridLayout();
centralwidget->setLayout(layout);
setCentralWidget(centralwidget);
// create widget with fixed height of 20 px and maximum width of 200
QWidget* topHeader = new ColoredWidget(Qt::green, centralwidget);
topHeader->setMaximumWidth(200);
topHeader->setFixedHeight(20);
// create widget with fixed width of 20 px and maximum height of 200
QWidget* leftHeader = new ColoredWidget(Qt::blue, centralwidget);
leftHeader->setFixedWidth(20);
leftHeader->setMaximumHeight(200);
// create scroll area as main widget
QWidget* view = new QScrollArea();
layout->addWidget(topHeader, 0, 1);
layout->addWidget(leftHeader, 1, 0);
// layout->addWidget(leftHeader, 1, 0, Qt::AlignTop); // widget not displayed at all!
layout->addWidget(view, 1, 1);
}
};
int main(int argc, char ** argv) {
QApplication app( argc, argv );
MainWindow win(0);
win.show();
return app.exec();
}
The QGridLayout documentation says that "Columns and rows behave identically", thus I would expect that the two widgets are layouted the same way.
However, the left one is automatically vertically centered, while the top widget is aligned to the left within the cell (and not centered horizontally). I would like to have the left widget also at a fixed position, means aligned to the top:
Which property causes this different behaviour between the two widgets, one beeing centered, the other being at a fixed position?
How can I influence the alignment (I can probably add a flexible spacer to fix it, but ideally I would like to avoid that)? I tried with Qt::AlignTop, but that made the blue widget disappear.
Althought this question is pretty old, I will add my answer for all those that come here afterwards, like me.
Setting the alignment either with
layout->setAlignment(leftHeader, Qt::AlignHCenter | Qt::AlignTop);
or with
layout->addWidget(leftHeader, 1, 0, Qt::AlignTop);
is intuitiv and seems to be the right way. If it is setup completly it is also working as expected.
But why does the Widget vanish then?
Long story short: because leftHeader has a size of 0.
In my pretty similar situation I've setfixedHeight() and the widget reappeared, this should also work by setting a value for minimalHeight() for example.
Long Story - Details
I've put myself in position of gridLayout and tried to determine the size of leftHeader:
Outside of the layout leftHeader got a fixed width of 20 - ok, but no given height. With the defaults of QWidget this leads to a default-height of 0.
Documentation of void QGridLayout::addWidget() and void QGridLayout::addLayout() states:
... The alignment is specified by alignment. The default alignment is
0, which means that the widget fills the entire cell. ...
source
Hence for default alignment of 0 the height of leftHeader is obviously set as height of its row.
But in case a different Qt::Alignment is used, as in the question (Qt::AlignTop ), it is not that simple.
From my point of view the layout is unable to determine the correct height without further settings from the designer.
Having a quick look at the implementation of void QGridLayout::addWidget(), we can detect that a QLayoutItem(as part of QGridBox) is created inside the QGridLayout for each added widget resp. Layout.
So it seems that the QGridLayout relies on default layout mechanisms of Qt based on the settings from the added widget/Layout (like minSize, maxSize, BaseSize, Size Increment, etc ).
In combination with 1.) this implies a height of 0 for leftHeader and therefore nothing to draw resp. it seems that the widget has vanished.
Although not a minimal solution you could probably fix the alignments by adding a QHBoxLayout in the cell for the green widget and a QVBoxLayout in the cell for the blue widget. Add the green widget to the QHBoxLayout and the blue widget to the QVBoxLayout. Then apply addStretch(n) to both the QHBoxLayout and QVBoxLayout. Maybe this is what you already mentioned you could do and then we are at the same level of knowledge concerning this. I believe this is the way I have solved these kind of issues and I haven't spent more time on it.
Try this:
setAlignment(Qt::AlignHCenter | Qt::AlignTop );

Resizing child widget with keeping aspect ratio when parent widget resized

I have four widgets in a QWidgets named FourWindowWidget I am trying to put these four widgets in FourWindowWidget as one at top and remaining under that while the top one should always have 70% of the size of FourWindowWidget. I tried following :
QSize size = ui->FourWindowWidget->size();
ui->View1->setFixedHeight(size.height()*0.70);
QHBoxLayout * lay = new QHBoxLayout();
lay->addWidget(ui->View2);
lay->addWidget(ui->View3);
lay->addWidget(ui->View4);
lay->setMargin(0);
lay->setContentsMargins(0,0,0,0);
QGridLayout * mainlay = new QGridLayout;
mainlay->addWidget(ui->View1,0,0);
mainlay->setContentsMargins(0,0,0,0);
mainlay->setHorizontalSpacing(0);
mainlay->setSpacing(0);
mainlay->setMargin(0);
mainlay->addLayout(lay,1,0);
delete ui->FourWindowWidget->layout();
ui->FourWindowWidget->setLayout(mainlay);
this->update();
Now the problem is now View1 have fixed size but size of FourWindowWidget is not fixed. It changes when I remove any other widget around it like closing dock widget. This resize is expected, or say I don't want to make it fixed. So when ever FourWindowWidget get resized its child widgets should be as per ratio set. But I am unable to do this cause
1. There is no any signal that inform resize so the height of internal widget will be calculated.
2. No other way I found to set 70% height of top widget rather than setFixedHeight in grid layout.
I have tried with setting QSizePolicy to setHieghtForWidth but iit is not a working solution.
Please suggest me to do this by any way.
The Question is kind of duplicat of Resizing Qt Widgets based on Window size but there nobody answered.
Setting the stretch factor for your layout should work. I'm not sure why you are using a grid layout for this, when you are adding everything in the same column, but here is an example that works:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
gridLayout = new QGridLayout;
this->centralWidget()->setLayout(gridLayout);
label1 = new QLabel("l1");
label2 = new QLabel("l2");
label3 = new QLabel("l3");
label4 = new QLabel("l4");
gridLayout->addWidget(label1, 0, 0);
gridLayout->addWidget(label2, 1, 0);
gridLayout->addWidget(label3, 2, 0);
gridLayout->addWidget(label4, 3, 0);
gridLayout->setRowStretch(0,7);
gridLayout->setRowStretch(1,1);
gridLayout->setRowStretch(2,1);
gridLayout->setRowStretch(3,1);
}
In this example label1 will take 70% of the available vertical space, while the other labels will take combined 30% of the available vertical space.

Prevent widgets stretching in QVBoxLayout and have scrollbar appear in QScrollArea?

Making my way up the Qt learning curve, I've seen many questions about dynamic layouts but the solutions aren't working for me or I don't quite understand them.
Reference questions:: Qt Scroll Area does not add in scroll bars, How can i make widgets overflow to make a scrollbar appear in Qt?
Question:: I want to have a dynamic layout of a set of widgets within a QScrollArea. I've been able to do this manually in Qt Creator and now I am trying to do it through code.
How do I prevent the widgets from stretching/force the area to scroll?
How do I have the added widgets start from the top? I have a vertical spacer in my QVBoxLayout but that pushes everything to the bottom.
Simple test code::
void MainWindow::on_pushButton_clicked()
{
ui->myScroll->setWidgetResizable(true); //making sure this is set
QPushButton *b = new QPushButton(this);
b->setText(QString("Hello Button"));
QHBoxLayout *h = new QHBoxLayout();
h->addWidget(b,0);
ui->myVBoxLayout->addLayout(h,0);
}
Result:: Left side squished (dynamic) – Right side Ok (set up manually)
Qt Creator Setup:: Left side: dynamic – Right side set up manually
Properties::
You can set use setMinimumHeight() on your buttons for preventing squished buttons. The layout can be configured with setContentsMargin() for space between item-border and item-content (QtDesigner has all four directions set to 9 IIRC) and setSpacing() for space between items (QtDesigner uses a default of 6). Also setWidgetResizable(true) allows your scrollarea to resize the view widgeth inside the area (this is where your layout and children are being placed).
This works for me:
In constructor or code set scrollArea->widget() to hold the QVBoxLayout:
v = new QVBoxLayout;
ui->scrollArea->widget()->setLayout(v);
In Button Slot:
void MainWindow::pushButtonPressed()
{
ui->scrollArea->setWidgetResizable(true);
QPushButton *b = new QPushButton(this);
b->setText(QString("Hello Button"));
QHBoxLayout *h = new QHBoxLayout();
h->addWidget(b,0);
v->addLayout(h);
}

Create Qt layout with fixed height

I want to create a Qt window that contains two layouts, one fixed height that contains a list of buttons at the top and one that fills the remaning space with a layout that centers a widget vertically and horizontally as per the image below.
How should i be laying out my layouts/widgets. Ive tried a few options with nested horizontal and vertical layouts to no avail
Try making the pink box a QWidget with a QHBoxLayout (rather than just making it a layout). The reason is that QLayouts don't provide functionality to make fixed sizes, but QWidgets do.
// first create the four widgets at the top left,
// and use QWidget::setFixedWidth() on each of them.
// then set up the top widget (composed of the four smaller widgets):
QWidget *topWidget = new QWidget;
QHBoxLayout *topWidgetLayout = new QHBoxLayout(topWidget);
topWidgetLayout->addWidget(widget1);
topWidgetLayout->addWidget(widget2);
topWidgetLayout->addWidget(widget3);
topWidgetLayout->addWidget(widget4);
topWidgetLayout->addStretch(1); // add the stretch
topWidget->setFixedHeight(50);
// now put the bottom (centered) widget into its own QHBoxLayout
QHBoxLayout *hLayout = new QHBoxLayout;
hLayout->addStretch(1);
hLayout->addWidget(bottomWidget);
hLayout->addStretch(1);
bottomWidget->setFixedSize(QSize(50, 50));
// now use a QVBoxLayout to lay everything out
QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->addWidget(topWidget);
mainLayout->addStretch(1);
mainLayout->addLayout(hLayout);
mainLayout->addStretch(1);
If you really want to have two separate layouts--one for the pink box and one for the blue box--the idea is basically the same except you'd make the blue box into its own QVBoxLayout, and then use:
mainLayout->addWidget(topWidget);
mainLayout->addLayout(bottomLayout);

QSplitter does not correctly set sizes

I have a horizontal QSplitter with two widgets. I want to replace the right hand widget with a new one in a way that the proportions the user has set are maintained. Below is a simplified version of the code I currently have:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
splitter = new QSplitter(this);
splitter->setOrientation(Qt::Horizontal);
leftWidget = new QPushButton("left", splitter);
rightWidget = new QPushButton("right", splitter);
splitter->addWidget(leftWidget);
splitter->addWidget(rightWidget);
setCentralWidget(splitter);
}
void MainWindow::swapLayout()
{
QList<int> sizes = splitter->sizes();
rightWidget->deleteLater();
splitter->update();
rightWidget = new QPushButton("new right", splitter);
splitter->addWidget(rightWidget);
splitter->setSizes(sizes);
}
swapLayout() saves the sizes, removes the right widget, adds a new right hand widget and attempts to reset the sizes. However the left hand widget occupies 100% of the space. Without trying to restore the sizes the widgets both take up 50% of the space.
I think the actual order of operations is:
saving sizes of 2 widgets;
adding 3rd widget.
setting size for 3 widgets (and sizes.at(2) is 0 by default.
Deleting 2nd widget.
It caused by the fact that deleteLater() only schedules deleting, and actual deleting is processed after you exit swapLayout() method. Try delete rightWidget; instead of rightWidget->deleteLater(); if it possible. Or process events between deleting rightWidget and adding new one.

Resources