How to add a widget to a pre-existing QLayout? - c++

I'm looking for a super simple example, and can't seem to find one. I have a MainWindow. When a button gets pressed I want to create a new window that gets opened up in the layout of MainWindow, to become a part of the mainwindow.
I have the code that sets up when a button is pushed to call this slot...when it gets called my QLabel shows up, but my QWidget does not
QWidget *test = new QWidget();
test->setGeometry(QRect(100,100,100,100));
layout->addWidget(test,0,0)
//Operation Mode
QLabel *operationalModeLabel1 = new QLabel("TEST");
layout->addWidget(operationalModeLabel1,2,1);

The reason for "lack of examples" is that you think of it wrong. What you describe is done all the time, by every single Qt example that uses layouts! I mean it. It doesn't matter when you add a widget to a layout. There's nothing magical about adding widgets "now" vs. adding them "later".
Just think of the title of the question: it makes no sense. All widgets must be added to layouts that already exist! By definition, no less. If there's no layout, how could you add a widget to it?
Your code is wrong, that's all. It's always pointless to set a geometry on a widget that is to be managed by a layout. As soon as you add it to the layout, the layout will change the geometry.
Since you're adding an empty widget into the layout, you most likely won't be able to see it. That's why the label shows up - it's not an empty widget.
If you want a widget that has a fixed size, to make it easier to notice, just set the fixed size on it. Even better, make it red so that it stands out.
QWidget * test = new QWidget();
test->setStyleSheet("QWidget { background-color: red }");
test->setFixedSize(100, 100);
layout->addWidget(test, 0, 0);

Related

In QT "ui->scrollArea->horizontalScrollBar()->setValue(0)" has no effect

So in my UI designer I have a ScrollArea Widget, I then in my MainWindow.cpp, I create a QGraphicScene and a QGraphics View. I create a new widget and give that widget a QVBoxLayout so that it will auto-size(which is correct to my understanding).
I then use ui->scrollArea->setWidget(widget); to make this new widget the child of my scrollView.
All of this seems correct because I have scroll bars that I can navigate my scene with. However; using the line ui->scrollArea->horizontalScrollBar()->setValue(0); still has no effect on the scroll bar values.
scene = new QGraphicsScene();
scene->setSceneRect(0,0,2500,2500);
view = new QGraphicsView(scene);
QWidget *widget = new QWidget;
view->setBackgroundBrush(Qt::white);
QVBoxLayout* bLayout = new QVBoxLayout(widget);
ui->scrollArea->setWidget(widget);
bLayout->addWidget(view);
widget->show();
ui->scrollArea->horizontalScrollBar()->setValue(0);
ui->scrollArea->verticalScrollBar()->setValue(0);
I just had the this problem. Then, after debugging with ui->scrollArea->verticalScrollBar()->value() I realized that the scrolling area has no size before the component is show on the screen, i.e., it does not change the scrolling because it is not visible yet.
This is a sample Python code, but the is the same for C++, except the Language Syntax.
from PyQt5.QtWidgets import QDialog
...
dialog = QDialog()
...
verticalScrollBar = dialog.QPlainTextEdit.verticalScrollBar()
horizontalScrollBar = dialog.QPlainTextEdit.horizontalScrollBar()
# Has no effect, if you print the values, you will see always 0
verticalScrollBar.setValue( horizontalScrollBar.maximum() )
horizontalScrollBar.setValue( horizontalScrollBar.minimum() )
dialog.show()
# Now it has effect
verticalScrollBar.setValue( horizontalScrollBar.maximum() )
horizontalScrollBar.setValue( horizontalScrollBar.minimum() )
Autoscroll PyQT QTextWidget
If you are sure to address the correct scrollbar (as pointed in the comments by thuga), maybe check if your scroll area is modified after that init. I mean I'm not sure of the bahaviour, but if you modified some text in your widget for example, I think the scrollbar will be impacted.
You may need to catch some of your widget's event to reapply those:
ui->scrollArea->horizontalScrollBar()->setValue(0);
ui->scrollArea->verticalScrollBar()->setValue(0);
If it doesn't help, you should try to debug by tracking scrollbar value with
ui->scrollArea->verticalScrollBar()->value()
and see if your set is well applied, and maybe when it is overriden
Just in case, you may also try some of the methods indicated here, but it's probably not relevant to your issue: setValue of ScrollBar Don't work at first time

Nothing showing up in QScrollArea

I have a nice widget that basically looks like a dialog box with a bunch of QSliders on it. The number of sliders varies depending on the situation when the dialog (not an actual QDialog; just a QWidget) is invoked.
Since the varying number of sliders causes the box to be different sizes at different times, I now want to clean things up a bit by confining the sliders to a QScrollArea. If I understand things correctly, such a scroll area would display however many sliders fit within its height, and one could scroll down to see the rest if there were more.
Anyway, I tried a (somewhat complicated) procedure like this:
In constructor of custom QWidget class (m_variableName = member variable):
CustomScrollBox::CustomScrollBox(QWidget* _parent){
setWindowTitle(...);
...
m_scrollArea = new QScrollArea(this);
m_scrollAreaBox = new QGroupBox(m_scrollArea);
m_layout = new QGridLayout();
m_scrollAreaBox->setLayout(m_layout);
m_scrollArea->setWidget(m_scrollAreaBox);
m_scrollArea->setFixedHeight(250);
m_bottomButton = new QPushButton(this); //probably irrelevant
...
[connect calls, etc.]
}
After the constructor, the real, situation-dependent set-up of sliders occurs:
void
CustomScrollBox::SetUpWidgets(){
for([however many sliders the situation calls for]){
CustomSlider* s = new CustomSlider(this, label); //just a QWidget consisting of a
//QSlider and a QLabel to
//the left of it
..
m_layout->addWidget(s, [grid dimensions as needed]);
}
...
[set text on bottom button, etc., and add it as well]
}
This process causes nothing to show up on the overall dialog, except for an immobile scroll bar on the left. What, if possible, is the proper order of initialization steps to make this work? My guess is that I might have given something the wrong parent or set a layout at the wrong time, but the rearrganements I've tried so far haven't worked...
First of all you do not need to create explicit members for child widgets and layout to your CustomScrollBox unless you need to access them later (even then you might track them down through their child relationship to your CustomScrollBox). In particular, having set the layout of a widget you can use QWidget::layout to get QLayout* and downcast it to QGridLayout* or QVBoxLayout*. Secondly you are supplying parents to most of the child widgets ctors. Normally you should not do that as e.g. the layout to which the widget is added will take the ownership i.e. the layout will become parent to the added widget. Below is in principle what I would do. It will point you in a better direction at least.
CustomScrollBox::CustomScrollBox(QWidget* parent)
: QWidget(parent)
{
setWindowTitle(...);
...
QVBoxLayout* vBoxLayout(new QVBoxLayout);
QScrollArea* scrollArea(new QScrollArea);
vBoxLayout->addWidget(scrollArea);
QGroupBox* groupBox(new QGroupBox);
QGridLayout* gridLayout(new QGridLayout);
gridLayout->addWidget(.../*whatever buttons etc*/)
groupBox->setLayout(gridLayout);
scrollArea->setWidget(groupBox);
setLayout(vBoxLayout);
...
[connect calls, etc.]
}

QSpacerItem In QFormLayout - Vertical Expand

I would like to force an expanding space in my QFormLayout, but no matter what QFormLayout only uses the QSpaceItem::sizeHint(). Does anyone know a way around this, or the proper way to handle this?
MyWidget::MyWidget(QWidget *parent) : QWidget(parent)
{
SetupLayout();
}
void MyWidget::SetupLayout()
{
QFormLayout * layout = new QFormLayout();
layout->addRow("Something1", new QComboBox());
layout->addRow("Something2", new QSpinBox());
//Spacer
layout->addItem(new QSpacerItem(0,10, QSizePolicy::Expanding, QSizePolicy::Expanding));
layout->addRow(QPushButton("Something3"));
setLayout(layout);
}
So there were a few different issues:
QFormLayout do not expand like other layouts. My widgets (a few of them) were being placed into a QFormLayout. This prevented them from expanding. I switched my main parent layout from QFormLayout to QVBoxLayout. This made me have to use QLayout::setAlignment(Qt::AlignTop)
This fixed a few problems with a few of my other widgets not expanding. However these widgets used QVBoxLayout. The widget above uses a QFormLayout. To get this expand, I had to use the following line in my QSpacerItem:
QSpacerItem * my_spacer = new QSpacerItem(0,1000, QSizePolicy::Expanding, QSizePolicy::Expanding);
I am supplying some example code. The goal is to show the hierarchy, and where QFormLayout would cause trouble.
Example code:
//A main Widget class
void SetupLayout()
{
QHBoxLayout * main_layout = new QHBoxLayout();
main_layout->addWidget(Some_Widget);
//Create a control widget
control_widget = new QWidget(); // IMPORTANT control_widget is a member
QVBoxLayout * layout = new QVBoxLayout(); //IMPORTANT!!!! - Here it was QFormLayout
layout->setAlignment(Qt::AlignTop); //IMPORTANT - Needed this after switching to QVBoxLayout
layout->addWidget(new QComboBox("stuff")); //Some combo box
control_widget->setLayout(layout);
main_layout->addWidget(control_widget);
}
//Later on, we have a "Put a new widget in the control area" task
void NewControlArea()
{
if(current_control)
control_widget->removeWidget(current_control); //current_control is a member variable
current_control = new MyWidget(); //FROM ABOVE
control_widget->addWidget(current_control);
}
If MyWidget uses a QFormLayout, things are not expanded unless I add spacers with size hints. However, if MyWidget uses a QVBoxLayout, any QWidgets inside it are expanded correctly.
After lot of time with manual as well as lots of tries i guess it's impossible to do what you want using QFormLayout.
This layout is desinged for windows with lot of fields to fill, but only for that.
If you want to add bigger spacing between sections of your form you can use QVBoxLayout with a couple of QFormLayout's inside it separated by spacings.
Notice that in this case each section will have own width of first and second column so maybe that is not the best solution.
The other solution (if we are talking about grouping some options) is to use a couple of QGroupBoxes with QFormLayouts in it. The groups will not be separated by growing spacing, but it will be very readable and you can name your groups. If grouping options is what you want to do - this is probably the most common and user friendly way to do this.
If you only want visual effect you pointed - columns with same width in every section and growing spacing between sections, you can use QGridLayout with 2 columns and add spacers in rows between sections. In this case you have to create QLabel to put into first column by yourself.
Just for posterity, I was having a similar problem. I found that having an organization like the following would cause anything in the inner layout (QHBoxLayout) to not expand vertically as they would if I had dropped them into the QFormLayout by themselves:
QFormLayout
-QHBoxLayout
--QListWidget
However, if I added a layer of indirection by putting the HBoxLayout into a QWidget, then sizing worked correctly:
QFormLayout
-QWidget
--QHBoxLayout
---QListWidget
So you might try adding a QWidget in there and putting your spacer inside of it.
What I did is probably a bit of hacking and is not very elegant, yet it did the trick in just one row:
addRow(" ", (QWidget*)nullptr);
This doubles the space between rows added before and after this call.
I suspect that MyWidget has the wrong size. The layout will use the widget's size to work out how best to layout its own items. Just because one of those items is set to an expanding policy does not mean that the layout will force the size of MyWidget to expand. If the size of MyWidget is fixed there is nothing the internal layout can do.
If you make MyWidget bigger you should see the layout working as you hope. Perhaps you need to put MyWidget in a vertical layout with its policy set to expanding? Without knowing how MyWidget gets its size it's hard to be sure.

Qt Gridlayout doesn't realign GUI elements

I have the following code in the ctor of my main window widget, in my Qt App. No matter how I align the buttons added to the QGridLayout, they always stay in the upper left corner, on top of each other.
Can anybody tell me what I've done wrong, I can't find it.
btn_File= new QPushButton("&File", this);
btn_Close = new QPushButton("&Close", this);
btn_File->setAutoFillBackground(true);
btn_Close->setAutoFillBackground(true);
QGridLayout * layout = new QGridLayout(this);
layout->setContentsMargins(20,20,10,10);
layout->setSpacing(5);
layout->addWidget(btn_File,2,2, Qt::AlignRight);
layout->addWidget(btn_Close,1,1);
this->setLayout(layout);
EDIT: It seems that only the btn_Close is being drawn. I just tried to add a QComboBox to the grid, and it doesn't show up.
The problem was that my main window was derived from QMainWindow, in which you need to add a CentralWidget before adding GUI elements. I changed my main window to derive from QWidget instead, and now it works.
tried calling this->adjustSize() at the end?
qt layouts really suck!
alignment on qgridlayout depends on the size of the objects, how many cols an object needs, and the size of the biggest object inserted.. so it is very difficult to put objects as you want...
i suggest to use setGeometry or move instead!

qt - widget - positioning

I want to place some widgets in a parent widget in some random places, like one button at Point (10,10) and another at (15,40), etc. How to achieve this?. QGridLayout is pushing everything into row column style. But I want to put the widgets whereever I want,Can anybody help me?
If you really want to set absolute positions, I would ignore using a layout altogether. You can manually set the positions of elements by using the move() function or the setGeometry() function.
QWidget *parent = new QWidget();
parent->resize(400, 400);
QPushButton *buttonA = new QPushButton(parent);
buttonA->setText("First Button");
buttonA->move(10, 10);
QPushButton *buttonB = new QPushButton(parent);
buttonB->setText("Second Button");
buttonB->move(15, 40);
Side note: I would avoid setting absolute positions of elements in Qt. Why? Well, Qt tries to be a platform-independent GUI library. On different platforms, a lot of display things can change (i.e. font size of text in push buttons) so the size of your actual push buttons can vary to accommodate large or smaller font sizes. This can throw off your meticulously spaced push buttons is you use absolute positions as in the example above.
If you use layouts, overlapping buttons or buttons falling off the edge of your window can be avoided.
You can see my answer for overlay button in QT: Qt Widget Overlays. This may help you to achieve what you want.