QGroupBox, QScrollArea, QFormLayout
-
@SPlatten
Does not sound right. I am not the right person to ask about this, but....... That does not sound at all like I understood
QScrollArea
to work. Look at https://doc.qt.io/qt-5/qscrollarea.html#details and examples elsewhere. My understanding is:QWidget *yourWidget; // put whatever you like on your widget, set your `QFormLayout` there QScrollArea *scrollArea; scrollArea->setWidget(yourWidget);
@JonB , I think the problem is I want to scroll a QVBoxLayout which isn't a widget. Here is the code and a screenshot of the results:
mpvbloErrors = new QVBoxLayout(this); QWidget* pobjErrorPadding(new QWidget(this)); mpsaErrors = new QScrollArea(this); mpsaErrors->setWidget(pobjErrorPadding); mpfrmloErrors = new QFormLayout(pobjErrorPadding); mpvbloErrors->addWidget(pobjErrorPadding); pobjErrorPadding->setLayout(mpfrmloErrors); mpsaErrors->setFixedHeight(100); // Just a fiddle to see what happens QPushButton* pbtnAck(new QPushButton(tr("&Clear Errors"))); QObject::connect(pbtnAck, &QPushButton::clicked, [this, pbtnAck, pobjErrorPadding] { pbtnAck->setVisible(false); pobjErrorPadding->setVisible(false); } ); mpvbloErrors->addWidget(pbtnAck, 1);
cid:ii_kvb2bvn50
The empty box at the top left is the scroll area and using the scroll bars does move the image under it. I also want to limit the height of the text rows under to say two rows and scroll vertically to the rest. -
@SPlatten said in QGroupBox, QScrollArea, QFormLayout:
mpsaErrors->setWidget(pobjErrorPadding);
...
mpvbloErrors->addWidget(pobjErrorPadding);
It's only doing what you ask for - pobjErrorPadding is a child of mpvbloErrors and not mpsaErrors after this.
-
@SPlatten said in QGroupBox, QScrollArea, QFormLayout:
mpsaErrors->setWidget(pobjErrorPadding);
...
mpvbloErrors->addWidget(pobjErrorPadding);
It's only doing what you ask for - pobjErrorPadding is a child of mpvbloErrors and not mpsaErrors after this.
@Christian-Ehrlicher , thank you, I will look again.
-
More edits, still not right:
mpvbloErrors = new QVBoxLayout(this); mpsaErrors = new QScrollArea; mpvbloErrors->addWidget(mpsaErrors); mpfrmloErrors = new QFormLayout; mpvbloErrors->addItem(mpfrmloErrors); int intFixedHeight(fontMetrics().height() * MainWindow::mscuintErrorRows); mpsaErrors->setFixedHeight(intFixedHeight); QPushButton* pbtnAck(new QPushButton(tr("&Clear Errors"))); QObject::connect(pbtnAck, &QPushButton::clicked, [this, pbtnAck] { mpsaErrors->setVisible(false); pbtnAck->setVisible(false); } ); mpvbloErrors->addWidget(pbtnAck, 1); QWidget* pobjErrorWrapper(this); pobjErrorWrapper->setLayout(mpvbloErrors);
Now there should be red rows shown, expecting 3 but nothing...
-
Hi,
As @JonB already wrote, QScrollArea is a container widget so 99% of the time you do not set a layout on it. You are in these 99%.
As already suggested, use a QWidget on which you apply the QFormLayout and set that widget on the QScrollArea.
You will then have the result you expect.
-
Hi,
As @JonB already wrote, QScrollArea is a container widget so 99% of the time you do not set a layout on it. You are in these 99%.
As already suggested, use a QWidget on which you apply the QFormLayout and set that widget on the QScrollArea.
You will then have the result you expect.
@SGaist , latest code:
mpobjErrors = new QWidget(this); //Wrapper/container for everything mpvbloErrors = new QVBoxLayout; //Vertical layout for error messages mpsaErrors = new QScrollArea; //Vertical layout to be scrollable mpsaErrors->setWidget(mpobjErrors); //Add scroll area to container mpobjErrors->setLayout(mpvbloErrors); //Add vertical layout to container int intFixedHeight(fontMetrics().height() * MainWindow::mscuintErrorRows); mpsaErrors->setFixedHeight(intFixedHeight); //Large enough for 3 rows of errors mpvbloErrors->addStretch(1); QPushButton* pbtnAck(new QPushButton(tr("&Clear Errors"))); QObject::connect(pbtnAck, &QPushButton::clicked, [this, pbtnAck] { mpobjErrors->setVisible(false); } ); mpfrmloErrors = new QFormLayout; //Layout for errors, time and cause mpvbloErrors->addLayout(mpfrmloErrors, 1); //Add form to vertical layout mpvbloErrors->addWidget(pbtnAck, 1, Qt::AlignHCenter); //Add button to container
The result from is:
I only want 3 lines to be displayed and the rest to be accessed using the scroll bar, but there is no scroll bar.
Its the QFormLayout that is used to display the error lines, the QVBoxLayout is used to contain the QFormLayout and the Clear Errors button at the bottom. I want the QFormLayout to be scrollable.
[edit]...:
//Create container for errors panel mpobjErrors = new QWidget(this); mpvbloErrors = new QVBoxLayout; mpobjErrors->setLayout(mpvbloErrors); //Create a widget that contains the scrollable errors form QWidget* pobjFormErrorsContr(new QWidget(mpobjErrors)); mpfrmloErrors = new QFormLayout; pobjFormErrorsContr->setLayout(mpfrmloErrors); int intFixedHeight(fontMetrics().height() * MainWindow::mscuintErrorRows); mpsaErrors = new QScrollArea; mpsaErrors->setWidget(pobjFormErrorsContr); mpsaErrors->setFixedHeight(intFixedHeight); mpvbloErrors->addWidget(pobjFormErrorsContr, 1, Qt::AlignHCenter); //Create a push button for acknowledging and clearing errors panel QPushButton* pbtnAck(new QPushButton(tr("&Clear Errors"))); mpvbloErrors->addWidget(pbtnAck, 1, Qt::AlignHCenter); QObject::connect(pbtnAck, &QPushButton::clicked, [this, pbtnAck] { mpobjErrors->setVisible(false); } ); //Default to hidden until errors are available to display mpobjErrors->setVisible(false);
I thought perhaps an additional widget container would be required for the QFormLayout, didn't help.
-
Why do you have a QVBoxLayou and a QFormLayout in mpobjErrors on the widget in your QScrollArea ?
The logic would rather be
-- QWidget ("this" in your sample code)
--- QVBoxLayout
---- QScrollArea (fixed height)
----- QWidget
------ QFormLayout
------- Dynamic number of widgets
---- QPushButton -> clear buttonSo you don't have to hunt for the clear button if you have lots of errors.
Note that depending on how many errors there might be limiting to three lines may not be the best user experience.
-
Why do you have a QVBoxLayou and a QFormLayout in mpobjErrors on the widget in your QScrollArea ?
The logic would rather be
-- QWidget ("this" in your sample code)
--- QVBoxLayout
---- QScrollArea (fixed height)
----- QWidget
------ QFormLayout
------- Dynamic number of widgets
---- QPushButton -> clear buttonSo you don't have to hunt for the clear button if you have lots of errors.
Note that depending on how many errors there might be limiting to three lines may not be the best user experience.
@SGaist , its supposed to be like this:
QWidget( mpobjErrors ) -- QVBoxLayout( mpvbloErrors ) ----- QWidget( pobjFormErrorsContr ) -------- QScrollArea( fixed height ) -------- QFormLayout( mpfrmloErrors ) ----- QPushButton( pbtnAck )
Where only the QFormLayout is scrollable, but it isn't.
-
@SGaist , its supposed to be like this:
QWidget( mpobjErrors ) -- QVBoxLayout( mpvbloErrors ) ----- QWidget( pobjFormErrorsContr ) -------- QScrollArea( fixed height ) -------- QFormLayout( mpfrmloErrors ) ----- QPushButton( pbtnAck )
Where only the QFormLayout is scrollable, but it isn't.
----- QWidget( pobjFormErrorsContr ) -------- QScrollArea( fixed height ) -------- QFormLayout( mpfrmloErrors )
But I/we already said that
QScrollArea
takes asetWidget(someWidget)
for the thing it wants to scroll, which has to be aQWidget
not aQLayout
.Also your
QFormLayout
is not anywhere descended fromQScrollArea
, it's a sibling, so it's not inside it, so it won't be subject to scrollability. -
----- QWidget( pobjFormErrorsContr ) -------- QScrollArea( fixed height ) -------- QFormLayout( mpfrmloErrors )
But I/we already said that
QScrollArea
takes asetWidget(someWidget)
for the thing it wants to scroll, which has to be aQWidget
not aQLayout
.Also your
QFormLayout
is not anywhere descended fromQScrollArea
, it's a sibling, so it's not inside it, so it won't be subject to scrollability. -
@JonB , see code above:
mpsaErrors = new QScrollArea; mpsaErrors->setWidget(pobjFormErrorsContr);
-
-
@JonB , what diagram are you referring to? the fixed height is just a setting, the parent of the QScrollArea is the widget its under.
-
@SPlatten said in QGroupBox, QScrollArea, QFormLayout:
what diagram are you referring to?
The 3 lines I quoted verbatim from your previous post. Whatever.
-
-
//Create container for errors panel mpobjErrors = new QWidget(this); mpvbloErrors = new QVBoxLayout; mpobjErrors->setLayout(mpvbloErrors); mpsaErrors = new QScrollArea; int intFixedHeight(fontMetrics().height() * MainWindow::mscuintErrorRows); mpsaErrors->setFixedHeight(intFixedHeight); //Create a widget that contains the scrollable errors form QWidget* pobjFormErrorsContr(new QWidget); mpsaErrors->setWidget(pobjFormErrorsContr); mpfrmloErrors = new QFormLayout; pobjFormErrorsContr->setLayout(mpfrmloErrors); mpvbloErrors->addWidget(pobjFormErrorsContr, 1, Qt::AlignHCenter); //Create a push button for acknowledging and clearing errors panel QPushButton* pbtnAck(new QPushButton(tr("&Clear Errors"))); mpvbloErrors->addWidget(pbtnAck, 1, Qt::AlignHCenter); QObject::connect(pbtnAck, &QPushButton::clicked, [this, pbtnAck] { mpobjErrors->setVisible(false); } ); //Default to hidden until errors are available to display mpobjErrors->setVisible(false);
From the above the structure should be:
QWidget
-- QVBoxLayout
----- QScrollArea, with fixed height to show 3 rows
------- QWidget
---------- QFormLayout
------ QPushButtonThe image of this output:
The form layout needs to be the full width of the QVBoxLayout and should be just 3 rows as the image shows it isn't. -
//Create container for errors panel mpobjErrors = new QWidget(this); mpvbloErrors = new QVBoxLayout; mpobjErrors->setLayout(mpvbloErrors); mpsaErrors = new QScrollArea; int intFixedHeight(fontMetrics().height() * MainWindow::mscuintErrorRows); mpsaErrors->setFixedHeight(intFixedHeight); //Create a widget that contains the scrollable errors form QWidget* pobjFormErrorsContr(new QWidget); mpsaErrors->setWidget(pobjFormErrorsContr); mpfrmloErrors = new QFormLayout; pobjFormErrorsContr->setLayout(mpfrmloErrors); mpvbloErrors->addWidget(pobjFormErrorsContr, 1, Qt::AlignHCenter); //Create a push button for acknowledging and clearing errors panel QPushButton* pbtnAck(new QPushButton(tr("&Clear Errors"))); mpvbloErrors->addWidget(pbtnAck, 1, Qt::AlignHCenter); QObject::connect(pbtnAck, &QPushButton::clicked, [this, pbtnAck] { mpobjErrors->setVisible(false); } ); //Default to hidden until errors are available to display mpobjErrors->setVisible(false);
From the above the structure should be:
QWidget
-- QVBoxLayout
----- QScrollArea, with fixed height to show 3 rows
------- QWidget
---------- QFormLayout
------ QPushButtonThe image of this output:
The form layout needs to be the full width of the QVBoxLayout and should be just 3 rows as the image shows it isn't.@SPlatten
Your "diagram" now looks like @SGaist's, so I am happy.I have played with scroll areas all morning for you, and I have had enough! Play with this:
#include "widget.h" #include <QApplication> #include <QScrollArea> #include <QBoxLayout> #include <QPushButton> int main(int argc, char *argv[]) { QApplication a(argc, argv); Widget w; QVBoxLayout layout0; w.setLayout(&layout0); QScrollArea scrollArea(&w); layout0.addWidget(&scrollArea); QWidget container(&scrollArea); scrollArea.setWidget(&container); QVBoxLayout layout; container.setLayout(&layout); for (int i = 0; i < 10; i++) layout.addWidget(new QPushButton); scrollArea.setVerticalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAsNeeded); scrollArea.setFixedHeight(100); scrollArea.setWidgetResizable(true); w.show(); return a.exec(); }
Note the
scrollArea.setWidgetResizable(true);
. Without that I don't actually see any buttons. Is that what you are missing?Don't ask me about Qt layouts/size policies etc., I have always found them about as intuitive as a duck-billed platypus, I play till I get what I want.
-
@SPlatten
Your "diagram" now looks like @SGaist's, so I am happy.I have played with scroll areas all morning for you, and I have had enough! Play with this:
#include "widget.h" #include <QApplication> #include <QScrollArea> #include <QBoxLayout> #include <QPushButton> int main(int argc, char *argv[]) { QApplication a(argc, argv); Widget w; QVBoxLayout layout0; w.setLayout(&layout0); QScrollArea scrollArea(&w); layout0.addWidget(&scrollArea); QWidget container(&scrollArea); scrollArea.setWidget(&container); QVBoxLayout layout; container.setLayout(&layout); for (int i = 0; i < 10; i++) layout.addWidget(new QPushButton); scrollArea.setVerticalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAsNeeded); scrollArea.setFixedHeight(100); scrollArea.setWidgetResizable(true); w.show(); return a.exec(); }
Note the
scrollArea.setWidgetResizable(true);
. Without that I don't actually see any buttons. Is that what you are missing?Don't ask me about Qt layouts/size policies etc., I have always found them about as intuitive as a duck-billed platypus, I play till I get what I want.
@JonB , thank you, however its missing the QFormLayout which is required, see my post before you post.
Edited code, still doesn't work.
//Create container for errors panel mpobjErrors = new QWidget(this); mpvbloErrors = new QVBoxLayout; mpobjErrors->setLayout(mpvbloErrors); //Create scroll area mpsaErrors = new QScrollArea(mpobjErrors); //Create a widget that contains the scrollable errors form QWidget* pobjFormErrorsContr(new QWidget(mpsaErrors)); //Set-up scroll area mpsaErrors->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); int intFixedHeight(fontMetrics().height() * MainWindow::mscuintErrorRows); mpsaErrors->setWidget(pobjFormErrorsContr); mpsaErrors->setFixedHeight(intFixedHeight); mpsaErrors->setWidgetResizable(true); mpfrmloErrors = new QFormLayout(pobjFormErrorsContr); mpvbloErrors->addWidget(pobjFormErrorsContr, 1, Qt::AlignHCenter);//addLayout(mpfrmloErrors, 1);// //Create a push button for acknowledging and clearing errors panel QPushButton* pbtnAck(new QPushButton(tr("&Clear Errors"))); mpvbloErrors->addWidget(pbtnAck, 1, Qt::AlignHCenter); QObject::connect(pbtnAck, &QPushButton::clicked, [this, pbtnAck] { mpobjErrors->setVisible(false); } );
-
@JonB , thank you, however its missing the QFormLayout which is required, see my post before you post.
Edited code, still doesn't work.
//Create container for errors panel mpobjErrors = new QWidget(this); mpvbloErrors = new QVBoxLayout; mpobjErrors->setLayout(mpvbloErrors); //Create scroll area mpsaErrors = new QScrollArea(mpobjErrors); //Create a widget that contains the scrollable errors form QWidget* pobjFormErrorsContr(new QWidget(mpsaErrors)); //Set-up scroll area mpsaErrors->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); int intFixedHeight(fontMetrics().height() * MainWindow::mscuintErrorRows); mpsaErrors->setWidget(pobjFormErrorsContr); mpsaErrors->setFixedHeight(intFixedHeight); mpsaErrors->setWidgetResizable(true); mpfrmloErrors = new QFormLayout(pobjFormErrorsContr); mpvbloErrors->addWidget(pobjFormErrorsContr, 1, Qt::AlignHCenter);//addLayout(mpfrmloErrors, 1);// //Create a push button for acknowledging and clearing errors panel QPushButton* pbtnAck(new QPushButton(tr("&Clear Errors"))); mpvbloErrors->addWidget(pbtnAck, 1, Qt::AlignHCenter); QObject::connect(pbtnAck, &QPushButton::clicked, [this, pbtnAck] { mpobjErrors->setVisible(false); } );
@SPlatten
I found I had to put inscrollArea.setWidgetResizable(true);
to make it respect the height. You are saying it still does not. I assume you have verified the value forfontMetrics().height() * MainWindow::mscuintErrorRows
. You can put aQFormLayout
into my sample code in place ofQVBoxLayout layout;
, I can't see why that would behave any differently vertically. -
@SPlatten
I found I had to put inscrollArea.setWidgetResizable(true);
to make it respect the height. You are saying it still does not. I assume you have verified the value forfontMetrics().height() * MainWindow::mscuintErrorRows
. You can put aQFormLayout
into my sample code in place ofQVBoxLayout layout;
, I can't see why that would behave any differently vertically.@JonB , just to verify:
int intFontHeight(fontMetrics().height()), intFixedHeight(intFontHeight * MainWindow::mscuintErrorRows);
intFontHeight is 13
MainWindow::mscuintErrorRows is 3
intFixedHeight is 39Clearly setFixedHeight on mpsaErrors is not having the desired effect.