QScrollArea - scrollbar for a widget with many childs - c++

So, I got some problems with QScrollArea.
I want to put a widget with many children in a QScrollArea, but I just dont get any scrollbars.
Heres the code:
QDialog *dialog = new QDialog();
QVBoxLayout *dialoglayout = new QVBoxLayout( dialog );
QScrollArea *area = new QScrollArea();
dialoglayout->setMargin( 0 );
dialoglayout->addWidget( area );
area->setAlignment( Qt::AlignCenter );
area->setAlignment( Qt::AlignTop );
area->setWidgetResizable( true );
// mainwidget has a lot of children
QWidget *mainwidget = randomclass.getWidget();
QVBoxLayout *mainwidgetlayout = new QVBoxLayout( mainwidget );
dialog->setWindowFlags( Qt::Window );
area->setWidget( mainwidget );
dialog->showMaximized();
if the mainwidget is bigger than the scrollarea, the content just overflows.
Can anyone help me?
Thanks in advance.

Some widgets don't report the area to scroll and that causes the confusion with scroll area. For QScrollarea object to adjust to the content:
myWidget->setMinimumSize(myWidget->sizeHint()); // assume the min size
scrollArea->setWidget( myWidget ); // use that widget in scroll area
Specific scrollers also might need to be enabled depending on the content:
scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);

Related

Why is the QScrollArea restricted in size?

To my custom widget, inherited from QWidget, I have added a QScrollArea like this:
MainWindow::MainWindow(QWidget *parent) :
QWidget(parent)//MainWindow is a QWidget
{
auto *scrollArea = new QScrollArea(this);
auto *widget = new QWidget(this);
widget->setStyleSheet("background-color:green");
scrollArea->setWidget(widget);
scrollArea->setWidgetResizable(true);
scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
QVBoxLayout *parentLayout = new QVBoxLayout(widget);
this->setStyleSheet("background-color:blue");
for(int i=0;i<12;i++){
QHBoxLayout* labelLineEdit = f1();
parentLayout->addStretch(1);
parentLayout->addLayout(labelLineEdit);
}
parentLayout->setContentsMargins(0,0,40,0);
}
QHBoxLayout* MainWindow::f1()
{
QHBoxLayout *layout = new QHBoxLayout;
QLabel *label = new QLabel("Movie");
label->setStyleSheet("background-color:blue;color:white");
label->setMinimumWidth(300);
label->setMaximumWidth(300);
layout->addWidget(label);
QLineEdit *echoLineEdit = new QLineEdit;
echoLineEdit->setMaximumWidth(120);
echoLineEdit->setMaximumHeight(50);
echoLineEdit->setMinimumHeight(50);
echoLineEdit->setStyleSheet("background-color:white");
layout->addWidget(echoLineEdit);
layout->setSpacing(0);
return layout;
}
This produces a window which looks like this:
The problem is, that I want the scrollArea to occupy the entire window, but it does not. It also doesn't get resized when I resize the window.
How could I fix this?
The problem is, that I want the scrollArea to occupy the entire
window, but it does not. It also doesn't get resized when I resize the window.
The reason is that you have not set any kind of layout to manage the positioning of your QScrollArea widget itself, so it is just being left to its own devices (and therefore it just chooses a default size-and-location for itself and stays at that size-and-location).
A simple fix would be to add these lines to the bottom of your MainWindow constructor:
QBoxLayout * mainLayout = new QVBoxLayout(this);
mainLayout->setMargin(0);
mainLayout->addWidget(scrollArea);

Center children widget in parent widget(parent widget was added in layout)

I created a layout contain a parent widget. In that parent widget i created another widget.
My code is similarly to this:
QGridLayout *layout = new QGridLayout();
QWidget *parentWidget = new QWidget();
layout->addWidget(parentWidget );
QWidget *childWidget = new QWidget(parentWidget);
How can i center the child widget in parent widget ?
The problem is we cannot get the true size of parent widget because it's in a layout.
Move the child inside the parent's showeEvent. You can use a bool flag to do it only when the parent is shown for the first time.
void Parent::showEvent(QShowEvent *)
{
if(_first_show)
{
_first_show = false;
_child->move(this->rect().center() - _child->rect().center());
}
}
Proof that it works (red is the parent, and blue is the child):
You can do this by setting fixed size of child widget and placing it inside grid layout of parent widget.
QGridLayout *layout = new QGridLayout();
QWidget *parentWidget = new QWidget();
layout->addWidget(parentWidget );
QWidget *childWidget = new QWidget(parentWidget);
QGridLayout *parentLayout = new QGridLayout();
parentWidget->setLayout(parentLayout);
parentLayout->addWidget(childWidget);
childWidget->setFixedSize(/*some fixed size for child widget*/);

Having a QScrollArea dynamically fit its parent but does not expand for its children

I seem to be having an issue with getting the behavior I want from a QScrollArea. As it stands, whenever I add something to the layout of the widget set as the target of the scroll area it will rather opt to expand the entire window rather than fit to scroll.
Here's my current setup:
QSplitter * mainArea = new QSplitter( Qt::Vertical );
QWidget * containment = new QWidget;
containment->setLayout( new QVBoxLayout );
currentStructures = new QWidget;
currentStructures->setLayout( new QVBoxLayout );
currentStructures->layout()->setAlignment( Qt::AlignTop );
QScrollArea * scroll = new QScrollArea();
scroll->setWidget( currentStructures );
containment->layout()->addWidget( currentStructures );
mainArea->addWidget( containment );
mainArea->addWidget( new QWidget ); //TODO: create preview bar
this->layout()->addWidget( mainArea );
This makes it so that the scroll area only ever expands and never shows the scroll bars.
By inserting this line:
containment->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Ignored );
I can get the area to ignore the size of its children but it also doesn't take up the space needed nor does it show scroll bars -- it just crunches the widget inside of it.
I'm a bit of a greenhorn to using Qt, but I was wondering how I would achieve the behavior that I need: I would like the scroll area to greedily take up the area it has available from its parent layout but not expand the the containing layouts vertically when adding but instead actually shows scroll bars. I'm planning on allowing a lot of resizing, so it needs to actually scale to the parent instead of just being a fixed size. I am at a loss as to how I should proceed in solving this aspect of my GUI. Thank you for your time.
If you would like to tackle this problem visually, here's a harness that you can use. I greatly appreciate your help.
#include <QtWidgets\qapplication.h>
#include <QtWidgets\qsplitter.h>
#include <QtWidgets\qlayout.h>
#include <QtWidgets\qscrollarea.h>
#include <QtWidgets\qpushbutton.h>
#include <QtWidgets\qlabel.h>
#include <QtWidgets\qsizepolicy.h>
int main( int argc, char * argv[] )
{
QApplication app( argc, argv );
QWidget * testWidget = new QWidget;
testWidget->setLayout( new QVBoxLayout );
//////////////////CODE IN QUESTIION//////////////////////
QSplitter * mainArea = new QSplitter( Qt::Vertical );
QWidget * containment = new QWidget;
containment->setLayout( new QVBoxLayout );
//containment->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Ignored );
QWidget * currentStructures = new QWidget;
currentStructures->setLayout( new QVBoxLayout );
currentStructures->layout()->setAlignment( Qt::AlignTop );
QScrollArea * scroll = new QScrollArea();
scroll->setWidget( currentStructures );
containment->layout()->addWidget( currentStructures );
mainArea->addWidget( containment );
///////////////////////////////////////////////////////////
QPushButton * pushIntoLayout = new QPushButton( "Add Element to Widget" );
QWidget::connect( pushIntoLayout, &QPushButton::clicked, [currentStructures](){ currentStructures->layout()->addWidget( new QLabel( "A generated label" ) ); } );
mainArea->addWidget( pushIntoLayout );
currentStructures->setStyleSheet(
"QWidget {"
"background-color: #FAA;"
"}"
);
testWidget->layout()->addWidget( mainArea );
testWidget->show();
return app.exec();
}
Even after copying and pasting my code to make a test harness I had not noticed my grievous error. I had mistakenly pushed the currentStructures widget to the container's layout rather than scroll, the scrolling area after giving it its child.
An excerpt from the Qt docs on void QScrollArea::setWidget( QWidget * widget ) for those unfamiliar:
The widget becomes a child of the scroll area, and will be destroyed when the scroll area is deleted or when a new widget is set.
Thanks to everyone who looked it over.
For those wondering, the fixed code would look like the following:
QSplitter * mainArea = new QSplitter( Qt::Vertical );
QWidget * containment = new QWidget;
containment->setLayout( new QVBoxLayout );
QWidget * currentStructures = new QWidget;
currentStructures->setLayout( new QVBoxLayout );
currentStructures->layout()->setAlignment( Qt::AlignTop );
QScrollArea * scroll = new QScrollArea();
scroll->setWidget( currentStructures );
scroll->setWidgetResizable( true );
containment->layout()->addWidget( scroll );
mainArea->addWidget( containment );
mainArea->addWidget( new QWidget ); //TODO: create preview bar
this->layout()->addWidget( mainArea );
Cheers!

Qt C++ Display new window centered on old window

I have QWidget with button. When button is pressed, show new smaller window (Qwidget too). I want then new window is centered horizontal and veritcal on main window. Code which display new window is:
QWidget *wdg = new QWidget;
QPushButton *closeBtn = new QPushButton("Close");
QHBoxLayout *layout = new QHBoxLayout;
layout->addWidget(closeBtn);
wdg->setLayout(layout);
wdg->show();
wdg->resize(400,200);
Use the move slot. For example:
QPoint centerPoint = oldWidget->geometry()->center();
newWidget->adjustSize();
newWidget->move(centerPoint.x() - newWidget->width()/2, centerPoint.y() - newWidget->height()/2);
You may consider using frameGeometry() instead of geometry().
http://qt-project.org/doc/qt-5/application-windows.html#window-geometry
Hope that helps.

Qt QHBoxLayout percentage size

How can I maintain an aspect ratio between two QHBoxLayouts?
For instance I want a QHBoxLayout to be one third of the entire window width and the other to be two thirds of the entire window width:
How can I achieve this? I tried messing with the size hints of the controls in them but that didn't work out
void QSizePolicy::setHorizontalStretch(uchar stretchFactor)
Example:
QHBoxLayout* layout = new QHBoxLayout(form);
QWidget* left = new QWidget(form);
QSizePolicy spLeft(QSizePolicy::Preferred, QSizePolicy::Preferred);
spLeft.setHorizontalStretch(1);
left->setSizePolicy(spLeft);
layout->addWidget(left);
QWidget* right = new QWidget(form);
QSizePolicy spRight(QSizePolicy::Preferred, QSizePolicy::Preferred);
spRight.setHorizontalStretch(2);
right->setSizePolicy(spRight);
layout->addWidget(right);
The answer of york.beta is working, but I prefer much less code.
At least the sizePolicy is by default Prefered/Prefered.
The default policy is Preferred/Preferred, which means that the widget can be freely resized, but prefers to be the size sizeHint() returns.
You can simply use the second parameter of addWidget to stretch the widgets.
QHBoxLayout *layout = new QHBoxLayout( this );
layout->setContentsMargins( 0, 0, 0, 0 );
layout->setSpacing( 0 );
QPushButton *left = new QPushButton( "133px", this );
left->setStyleSheet( "QPushButton{border: 1px solid red;}" );
QPushButton *right = new QPushButton( "267px", this );
right->setStyleSheet( "QPushButton{border: 1px solid blue;}" );
layout->addWidget( left, 33 );
layout->addWidget( right, 66 );
this->setLayout( layout );
this->setFixedWidth( 400 );
See http://doc.qt.io/qt-5/qboxlayout.html#addWidget
and http://doc.qt.io/qt-5/qwidget.html#sizePolicy-prop
You can also use the layoutStretch property:
https://doc.qt.io/qt-5/layout.html#stretch-factors
In your case it'd be
<layout class="QHBoxLayout" name="horizontalLayout" stretch="1,2">
You can edit the sizePolicy for the widgets and set a higher horizontalStretch for the widget in the right.