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

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();

Related

How to properly manage text and icon with QToolButton?

I have code snippet looks like this:
nextPageBtn = new QToolButton();
nextPageBtn->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
nextPageBtn->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
nextPageBtn->setIcon(QIcon(":/next.png"));
nextPageBtn->setText("Next");
Currently I have two problems with this.
First:
I want the text is on the left of the icon, but with the code I provide, the text is on the right like this:
Second:
When the window is enlarged, I can not figure out a way to keep the text and icon in the center of the button. It looks like this when the button gets bigger:
Edit:
This is how I manage the layout:
nextPageHLayout = new QHBoxLayout; //This is the layout for QToolButton, it has two spacers and a QToolButton
mainVLayout->addLayout(nextPageHLayout); //mainVLayout is the main layout, and I put the mainVLayout to the central widget, and it also contains a QLabel above the nextPageHLayout
QSpacerItem *leftBtnSpacer = new QSpacerItem(1, 1, QSizePolicy::Expanding, QSizePolicy::Fixed);
nextPageHLayout->addSpacerItem(leftBtnSpacer);
nextPageBtn = new QToolButton(mainWidget);
nextPageHLayout->addWidget(nextPageBtn);
nextPageBtn->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
nextPageBtn->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
nextPageBtn->setIcon(QIcon(":/next.png"));
nextPageBtn->setText("Next");
QSpacerItem *rightBtnSpacer = new QSpacerItem(1, 1, QSizePolicy::Expanding, QSizePolicy::Fixed);
nextPageHLayout->addSpacerItem(rightBtnSpacer);
You must make the following changes:
You should not change the size policy of the QToolButton, that's why it's expanding.
You must change the layoutDirection to Qt::RightToLeft.
QHBoxLayout * nextPageHLayout = new QHBoxLayout; //This is the layout for QToolButton, it has two spacers and a QToolButton
mainVLayout->addLayout(nextPageHLayout); //mainVLayout is the main layout, and it also contains a QLabel above the nextPageHLayout
QSpacerItem *leftBtnSpacer = new QSpacerItem(1, 1, QSizePolicy::Expanding, QSizePolicy::Minimum);
nextPageHLayout->addSpacerItem(leftBtnSpacer);
nextPageBtn = new QToolButton(mainWidget);
nextPageHLayout->addWidget(nextPageBtn);
nextPageBtn->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
nextPageBtn->setIcon(QIcon(":/next.png"));
nextPageBtn->setText("Next");
nextPageBtn->setLayoutDirection(Qt::RightToLeft);
QSpacerItem *rightBtnSpacer = new QSpacerItem(1, 1, QSizePolicy::Expanding, QSizePolicy::Minimum);
nextPageHLayout->addSpacerItem(rightBtnSpacer);

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);
}

How can I adjust the window size of a QDialog to its content?

I have a dialog box with a QScrollArea to show an arbitrary amount of checkboxes. How can I make the dialog box adjust its width so that the QScrollArea does not have a horizontal scroll bar (if the content is not extremely wide).
std::vector<std::string> vec_strCheckboxLabel;
vec_strCheckboxLabel.push_back("Checkbox 1");
vec_strCheckboxLabel.push_back("Checkbox 2");
vec_strCheckboxLabel.push_back("Checkbox 3 is really long and causes a horizontal scroll bar to appear");
vec_strCheckboxLabel.push_back("Checkbox 4");
vec_strCheckboxLabel.push_back("Checkbox 5");
m_pWidget = new QDialog;
m_pWidget->setWindowTitle("My Dialog");
m_pWidget->setWindowModality(Qt::ApplicationModal);
m_pWidget->setMinimumWidth(400);
QVBoxLayout * pWidgetLayout = new QVBoxLayout(m_pWidget);
QLabel * pLabel = new QLabel("Hello");
pWidgetLayout->addWidget(pLabel);
QHBoxLayout * pTopButtonsLayout = new QHBoxLayout(m_pWidget);
pWidgetLayout->addLayout(pTopButtonsLayout);
QPushButton * pButton;
pButton = new QPushButton("Select all", m_pWidget);
connect(pButton, SIGNAL(clicked()), this, SLOT(slotSelectAll()));
pTopButtonsLayout->addWidget(pButton);
pButton = new QPushButton("Select none", m_pWidget);
connect(pButton, SIGNAL(clicked()), this, SLOT(slotSelectNone()));
pTopButtonsLayout->addWidget(pButton);
// the checkboxes in a scroll area
{
QFrame * pFrameCheckboxes = new QFrame(m_pWidget);
QVBoxLayout * pCheckboxesLayout = new QVBoxLayout(pFrameCheckboxes);
// this frame takes all available space in the QDialog
pFrameCheckboxes->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
for (unsigned int i = 0, iEnd = vec_strCheckboxLabel.size(); i != iEnd; ++i)
{
QCheckBox * poCheckBox = new QCheckBox(vec_strCheckboxLabel[i].c_str());
pCheckboxesLayout->addWidget(poCheckBox);
}
// put into scroll area
QScrollArea * pScrollAreaTheCheckboxes = new QScrollArea(m_pWidget);
pWidgetLayout->addWidget(pScrollAreaTheCheckboxes);
pScrollAreaTheCheckboxes->setWidget(pFrameCheckboxes);
}
The problem is the scroll area limits its size to take available space by default; it does not demand space from the layout. You have to explicitly tell it to change that behavior.
Check out QAbstractScrollArea::SizeAdjustPolicy. You are probably looking for AdjustToContentsOnFirstShow, like so:
pScrollAreaTheCheckboxes->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContentsOnFirstShow);
Unfortunately, you cannot set different adjust policies for horizontal and vertical aspects, if this is what you are after. Judicious use of QSizePolicy and layout settings (e.g. setStretch()) can fix this.
Qt4
As a workaround for Qt4, check the viewport's sizeHint() and set the scroll area's minimum size to that.
pScrollAreaTheCheckboxes->setMinimumSize(pScrollAreaTheCheckboxes->viewport()->sizeHint());
Do this after you've initialized all of your checkboxes.

Centering a widget inside another widget in Qt

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

Qt remove margins

I am currently using a QMainWindow widget and I would like to remove margins around the widget inside. I success to remove margins for window borders but not for the widgets inside my window.
Here is my code, for example :
this->mainWidget = new QWidget(this);
this->mainLayout = new QHBoxLayout;
QLabel *foo = new QLabel("foo", this);
QLabel *bar = new QLabel("bar", this);
mainLayout->setContentsMargins(0, 0, 0, 0); // Remove margins for window borders
this->setWindowFlags(Qt::FramelessWindowHint);
foo->setStyleSheet("background-color: green");
bar->setStyleSheet("background-color: red");
foo->setContentsMargins(0, 0, 0, 0); // Has no effect
bar->setContentsMargins(0, 0, 0, 0); // Has no effect
this->mainLayout->addWidget(foo);
this->mainLayout->addWidget(bar);
this->mainWidget->setLayout(mainLayout);
this->setCentralWidget(mainWidget);
And here is what it rendered :
I would like to remove the white part between the two widgets.
Have you an idea how to make that kind of things ?
Thank you.
You simply need to set the spacing attribute of your box layout to zero:
this->mainLayout->setSpacing(0);