Centering a widget inside another widget in Qt - c++

I'm trying to center a QWidget localized inside a QTabWidget. When one resizes the inner QWidget I want it to be placed in the center always.
How can I do this?

1/ Create a layout in your QTabWidget: a QBoxLayout for example.
2/ Set your QWidget in it, with the desired alignment.
QTabWidget* tabwid = new QTabWidget(this);
QBoxLayout* layout = new QBoxLayout(QBoxLayout::LeftToRight, tabwid);
//if you want to set margins : layout->setContentsMargins(5, 5, 5, 5);
QWidget* widget = new QWidget();
layout->addWidget(widget, Qt::AlignCenter); // center alignment

Related

Is possible to have a widget that doesnt scroll in a QScrollArea?

Given this example:
Suppose A and B are QWidgets
Is it possible to keep everything starting from B static when the QScrollArea widget is scrolled?
The QScrollArea occupies the entire GUI, B is inside it to let the vertical ScrollBar closer to the right border of the GUI, or it would look like this:
What I can do in this case?
It is possible. You have to make use of the scrollbar being a widget of its own.
Here is the method:
Change your window in Qt Designer to be: spacer, QScrollArea (that will contain widget A), spacer, widget B, spacer; everything is in a QGridLayout (or QHBoxLayout but please read until the end).It is because widget B is outside the scroll area that it will not move during scrolling.
In your widget constructor, after ui->setupUi(); reparent and move the vertical scrollbar of your QScrollArea with these lines of code:
scrollArea->verticalScrollBar()->setParent(w);
layout->addWidget(sa->verticalScrollBar()); //Adds the scrollbar to the right of the layout.
Note about the margins:Obviously, you can easily push the scrollbar to the very right of your window by setting the layout right margin to 0.
If you also want it to cover the entire height of your window, while keeping some space between the other widgets and the window's border, that is where a QHBoxLayout will not suffice and you need a QGridLayout instead, set its top and bottom margin to 0 and add spacers (fixed size) to obtain the same visual result.
The C++ code for such a window would be:
QWidget* widget = new QWidget();
QGridLayout* layout = new QGridLayout(widget);
layout->setSpacing(0);
layout->setContentsMargins(9, 0, 0, 0);
widget->setLayout(layout);
QScrollArea* scrollArea = new QScrollArea(widget);
scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
QWidget* widgetB = new QLabel("Widget B", widget);
//Creates the spacer that will "simulate" the top and bottom margins
QSpacerItem* topSpacer = new QSpacerItem(0, 9, QSizePolicy::Minimum, QSizePolicy::Fixed),
* bottomSpacer = new QSpacerItem(0, 9, QSizePolicy::Minimum, QSizePolicy::Fixed);
layout->addItem(topSpacer, 0, 0);
layout->addWidget(scrollArea, 1, 0);
layout->addItem(bottomSpacer, 2, 0);
layout->addWidget(widgetB, 1, 1);
//Moves the scrollbar outside the scroll area
scrollArea->verticalScrollBar()->setParent(widget);
layout->addWidget(scrollArea->verticalScrollBar(), 0, 2, 3, 1);
QLabel* innerLabel = new QLabel("Some big label to force the scrolling");
scrollArea->setWidget(innerLabel);
innerLabel->setMinimumHeight(500);
widget->show();

Custom widgets in scroll area not respecting minimum?

I'm getting closer to getting a QScrollArea working, but it's still shrinking my custom widgets as they are added. Everything is resizing fluidly, and if the scroll area is too small, then the scroll bar appears, so it clearly has some idea of a minimum size.
At start, with two custom widgets in the scroll area, you can see some shrinking:
Here's the same window below the critical point. The text is now completely gone, but it won't shrink the QLineEdit, so it finally adds a scrollbar. (the scroll area has a blue background, the content widget is the purple)
I started in Design, but everything below the scroll area's widget is in code, as I was having trouble getting the vertical layout to work right using design.
Here's the starting point:
There's a page in a StackWidget that has two elements in a vertical layout. The scroll area has a QWidget. The constructor for MainWindow defines a vertical layout, assigning it to the member scrollWidgetLayout, and giving that layout to the scroll area's widget:
scrollWidgetLayout = new QVBoxLayout(ui->scrollAreaWidgetContents);
ui->scrollAreaWidgetContents->setLayout(scrollWidgetLayout);
The app starts on the first page of the stack widget, the user logs in, and the app runs off to fetch records from the server. Each record is turned into a widget:
RecordFolderWidget::RecordFolderWidget(Record *r, QWidget *parent) : QWidget(parent)
{
record = r;
//setSizePolicy(QSizePolicy::Expanding, QSizePolicy::MinimumExpanding);
QGridLayout *layout = new QGridLayout();
pathLineEdit = new QLineEdit();
finderButton = new QPushButton("...");
QLabel *nameLabel = new QLabel(record->name);
layout->setSpacing(5);
layout->setMargin(3);
layout->addWidget(nameLabel, 0, 0, 0, 1, Qt::AlignCenter);
layout->addWidget(pathLineEdit, 1, 0);
layout->addWidget(finderButton, 1, 1);
setLayout(layout);
//setMinimumHeight(sizeHint().height());
}
Note that there are some lines commented out, these are things I have been playing with to try to get it to work. The sizeHint, btw, appears to be correct, and does not change.
Once that Widget is created, it gets added to the scroll area's widget:
RecordFolderWidget *rf = new RecordFolderWidget(record);
rf->setParent(ui->scrollAreaWidgetContents);
scrollWidgetLayout->addWidget(rf);
I tried here to also resize the scroll areas contents, with no luck:
ui->scrollAreaWidgetContents->resize(rfSize.width(), rfSize.height() * records.count());
where rfSize was pulled from the custom widget's sizeHint after it was created, and this line was called once after the loop to create/add all of the widgets.
Other than the setMinimumHeight and resize above, I've tried changing the SizePolicy for the scrollAreaWidgetContents from preferred to expanding to minimumexpanding and did not see any difference. I'm sure I've missed something trivial, but just can't find it.
The problem that I see in your code is when adding the QLabel you are setting the rowSpan to 0, I have changed it and I can observe it correctly. In the next part I show my test code and the result:
QVBoxLayout *scrollWidgetLayout = new QVBoxLayout(ui->scrollAreaWidgetContents);
for(int i=0; i<10; i++){
QWidget *widget = new QWidget;
QGridLayout *layout = new QGridLayout(widget);
QLineEdit *pathLineEdit = new QLineEdit;
QPushButton *finderButton = new QPushButton("...");
QLabel *nameLabel = new QLabel(QString("name %1").arg(i));
layout->setSpacing(5);
layout->setMargin(3);
layout->addWidget(nameLabel, 0, 0, 1, 1, Qt::AlignCenter);
layout->addWidget(pathLineEdit, 1, 0);
layout->addWidget(finderButton, 1, 1);
scrollWidgetLayout->addWidget(widget);
}

Qt layouts, difference between passing and not passing QWidget as parent

I have created a simple QHBoxLayout (horizontal) that is pushed to the bottom of the QVBoxLayout (Vertical) and it contains two buttons. See code:
QWidget* create_ver_and_horizontal_box() {
QWidget* temp = new QWidget();
// Add buttons to the horizontal box
QHBoxLayout* hbox = new QHBoxLayout();
QPushButton *ok = new QPushButton("OK");
QPushButton *cancel = new QPushButton("Cancel");
hbox->addWidget(ok);
hbox->addWidget(cancel);
// Create a vertical box and add the horizontal box to
// the end of it
QVBoxLayout* vbox = new QVBoxLayout();
vbox->addStretch(1);
vbox->addLayout(hbox);
// set the layout and return
temp->setLayout(vbox);
return temp;
}
and the resulting UI is the following.
But when I add the QWidget temp to be the parent of the QHBoxLayout, like so:
// Add buttons to the horizontal box
QHBoxLayout* hbox = new QHBoxLayout(temp);
This is what I get:
I want to understand what is going on here. And in which cases I want the QWidget to be the parent of a layout or any other QWidget(s) and in which cases I don't the containing QWidget to be the parent of the containing QWidgets. For example, I could've added temp to be the parent of the two Push buttons but I didn't. What is the implication of not adding vs adding.
Thanks,
QHBoxLayout* hbox = new QHBoxLayout(temp);
is equivalent to
QHBoxLayout* hbox = new QHBoxLayout();
temp->setLayout(hbox);
I.e. you are making the horizontal layout responsible for temp.
The call to setLayout(vbox) should have generated a runtime warning message, that temp already has a layout, hinting at that.
Since you want the vertical layout to be responsible for that widget, either keep the temp->setLayout(vbox) or pass temp to the constructor of QVBoxLayout.

How to make widgets automatically stretch to the parent widget's size in Qt Designer

I need to add a TabWidget control to the MainWindow and place TableWidget in every tab it has. The problem is that I need to make them automatically stretch to the parent widget's size (TabWidget to the window's size, TableWidget's to the TabWidget's size).
What is the easiest way to achieve it via Qt Designer?
You should use Qt layouts.
In designer you have to select the widget you want to have its children laid out properly, then choose Form -> Lay Out Vertically/Horizontally/... shortcuts: Ctrl+1...6
Below is an example program that will create a view as you needed. Logic is Mainwindow-> Central Widget-> Add Vertical Layout-> Add Tab Widget
->Add Tab 1->Add V Box Layout -> Add Table 1 (5 X 5)
->Add Tab 2->Add V Box Layout -> Add Table 1 (5 X 5)
Code comment will explain in detail.
void MainWindow::fnInit()
{
//Layout to the MainWindow
QVBoxLayout *vLayoutMain;
QTabWidget *Tab;
QWidget *Widget1;
//Layout to the Tab1
QVBoxLayout *vLayoutTab1;
QTableWidget *Table1;
QWidget *Widget2;
//Layout to the Tab2
QVBoxLayout *vLayoutTab2;
QTableWidget *Table2;
//Set Vertical Box Layout to the main Window (central widget)
vLayoutMain = new QVBoxLayout(this->centralWidget());
Tab = new QTabWidget(this->centralWidget());
Widget1 = new QWidget();
//Set the Vertical Box Layout to the Widget 1 (holds the tab1)
vLayoutTab1 = new QVBoxLayout(Widget1);
Table1 = new QTableWidget(5,5,Widget1);
vLayoutTab1->addWidget(Table1);
Tab->addTab(Widget1, QString("Tab 1"));
Widget2 = new QWidget();
//Set the Vertical Box Layout to the Widget 2 (holds the tab2)
vLayoutTab2 = new QVBoxLayout(Widget2);
Table2 = new QTableWidget(5,5,Widget2);
vLayoutTab2->addWidget(Table2);
Tab->addTab(Widget2, QString("Tab 2"));
//Adding the Tab widget to the main layout
vLayoutMain->addWidget(Tab);
Tab->setCurrentIndex(0);
}

QGridLayout with different size of cells

I'm trying to set a QGridLayout with four widget as in the image below:
however what I've managed with QGridLayout as of now is:
I don't see how I can set the size of the row different for column 0 and 1. Maybe QGridLayout is not the right way of doing it but I don't know of any other widget that would do the trick.
Does anyone have any idea how to achieve this?
I would use vertical and horizontal layouts instead of the grid layout. So you need two vertical layouts and horizontal one:
// Left side
QLabel *lbl1 = new QLabel(this);
QTableWidget *t = new QTableWidget(this);
QVBoxLayout *vl1 = new QVBoxLayout;
vl1->addWidget(lbl1);
vl1->addWidget(t);
// Right side
// QImage is not a widget, so it should be a label with image
QLabel *lbl2 = new QLabel(this);
QCustomPlot *pl = new QCustomPlot(this);
QVBoxLayout *vl2 = new QVBoxLayout;
vl2->addWidget(lbl2);
vl2->addWidget(pl);
// Create and set the main layout
QHBoxLayout mainLayout = new QHBoxLayout(this);
mainLayout->addLayout(vl1);
mainLayout->addLayout(vl2);
I don't think grids are the way to go here indeed...
You could try making a horizontal layout of 2 QFrames, in which you set a vertical layout each with the two widgets of that "column"