How to avoid hidden QWidget height included in QStackedLayout? - qt

I have this scenario with which I have been struggling for few hours:
I have a main widget, whose layout is set to main_layout, before which 3 layouts are added to the main_layout:
A QVBoxLayout (header_app_layout)
A second QVBoxLayout (header_loader_layout)
A QStackBoxLayout (content_layout)
The QStackBoxLayout (content_layout) has 2 child widgets added to it, of which only 1 is shown:
m_content1_widget (shown widget)
m_content2_widget
My problem is that, content_layout is taking into consideration the heights of the hidden child widgets in the widget: m_content1_widget, because of which the main_widget height is overflowing.
If I change content_layout from QStackedLayout to QVBoxLayout type, it all starts working fine.
So it seems to me that, QStackedLayout is respecting the height of the hidden widgets, which I don't want it to. Any ideas to overcome this ?
Here is the code:
main.cpp
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
main_widget w;
w.setFixedSize(400, 400);
w.show();
return app.exec();
}
main_widget.h
#include <QWidget>
#include <QLabel>
#include <QStackedLayout>
#include <QVBoxLayout>
#include <QPushButton>
class main_widget : public QWidget
{
Q_OBJECT
public:
main_widget();
};
main_widget.cpp
#include "main_widget.h"
main_widget::main_widget()
: QWidget(nullptr)
{
QVBoxLayout *header_app_layout = new QVBoxLayout();
QLabel *header_app_label = new QLabel();
header_app_label->setText(tr("Header"));
header_app_layout->addWidget(header_app_label);
QVBoxLayout* header_loader_layout = new QVBoxLayout();
QLabel* header_loader_label = new QLabel();
header_loader_label->setText(tr("Header Loader"));
header_loader_layout->addWidget(header_loader_label);
QWidget *m_content1_widget = new QWidget();
QVBoxLayout* content1_layout = new QVBoxLayout(m_content1_widget);
QPushButton* content1_button1 = new QPushButton(tr("content1_button1"));
content1_layout->addWidget(content1_button1);
QPushButton* content1_button2 = new QPushButton(tr("content1_button2"));
content1_layout->addWidget(content1_button2);
QPushButton* content1_button3 = new QPushButton(tr("content1_button3"));
content1_layout->addWidget(content1_button3);
content1_button2->hide(); //Hidden for now. But it's height is being included
content1_button3->hide();
QWidget* m_content2_widget = new QWidget();
QVBoxLayout* content2_layout = new QVBoxLayout(m_content2_widget);
QPushButton* content2_button1 = new QPushButton(tr("content2_button1"));
content2_layout->addWidget(content2_button1);
QPushButton* content2_button2 = new QPushButton(tr("content2_button2"));
content2_layout->addWidget(content2_button2);
QPushButton* content2_button3 = new QPushButton(tr("content2_button3"));
content2_layout->addWidget(content2_button3);
content2_button2->hide();
content2_button3->hide();
QStackedLayout* content_layout = new QStackedLayout(); //Doesn't work
//QVBoxLayout *content_layout = new QVBoxLayout(); //Works, but I need it to be of type `QStackedLayout` to show the 2 child widgets conditionally
content_layout->addWidget(m_content1_widget);
content_layout->addWidget(m_content2_widget);
content_layout->setStackingMode(QStackedLayout::StackingMode::StackOne);
content_layout->setCurrentIndex(0);
QVBoxLayout* main_layout = new QVBoxLayout;
main_layout->addLayout(header_app_layout); //Adding a QVBoxLayout
main_layout->addLayout(header_loader_layout); //Adding another QVBoxLayout
main_layout->addSpacing(32);
main_layout->addLayout(content_layout); //Adding the QStackedLayout
this->setLayout(main_layout);
}

I was able to resolve the issue by calling adjustSize on m_content2_widget, which removed the space occupied by the hidden controls inside m_content2_widget.
m_content2_widget->adjustSize();

Related

QScrollArea Child Widget size set according to to Parents size change

I want to fit (child) widget into the parent widget size. So if the parent window is too small to display all the elements of the child widget the QScrollArea should appear otherwise it should be invisible.
I have attached the pictures for a better understanding.
The black box is where I want my scroll to appear. Since when we reduce the size of the window, sometimes you can't see the scroll bar (as displayed in the below picture) it doesn't look elegant enough for big projects.
Please help me with the same, thanks in advance.
Here's the sample code that I used for example:
int main(int argc, char *argv[]){
QApplication a(argc, argv);
QScrollPractice w;
QDialog * dlg = new QDialog();
//dlg->setGeometry(100, 100, 260, 260);
dlg->setMinimumSize(150, 200);
QScrollArea *scrollArea = new QScrollArea(dlg);
scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
scrollArea->setWidgetResizable(true);
//scrollArea->setGeometry(10, 10, 200, 200);
//scrollArea->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Ignored);
//QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
scrollArea->setSizePolicy(sizePolicy);
QWidget *widget = new QWidget(scrollArea);
scrollArea->setWidget(widget);
QVBoxLayout *layout = new QVBoxLayout(widget);
widget->setLayout(layout);
for (int i = 0; i < 10; i++)
{
QPushButton *button = new QPushButton(QString("%1").arg(i));
layout->addWidget(button);
}
dlg->show();
return a.exec();
}
Your Dialog is missing a layout as well. Thats the reason the scrollArea Widget isnt spread out across the dialog.
#include <QApplication>
#include <QDialog>
#include <QScrollArea>
#include <QVBoxLayout>
#include <QPushButton>
int main(int argc, char* argv[]){
QApplication a(argc, argv);
QDialog* dlg = new QDialog();
dlg->setMinimumSize(150, 200);
QScrollArea* scrollArea = new QScrollArea(dlg);
scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
scrollArea->setWidgetResizable(true);
QWidget* widget = new QWidget(scrollArea);
scrollArea->setWidget(widget);
QVBoxLayout* dlgLayout = new QVBoxLayout();
dlg->setLayout( dlgLayout );
dlgLayout->addWidget( scrollArea );
QVBoxLayout* layout = new QVBoxLayout(widget);
widget->setLayout(layout);
for (int i = 0; i < 10; i++)
{
QPushButton* button = new QPushButton(QString("%1").arg(i));
layout->addWidget(button);
}
dlg->show();
return a.exec();
}
I modified your code to make it run and compileable, also I added antoher QVBoxLayout and added it to the dialog. Then the scrollArea gets added to that Layout. Hope this helps.

Design custom QT Widget on top of QT Window

I have a QT main window and on top of this I want to add a widget ( containing buttons), as similar to image below.
If I add a dock widget , it is added in separate row, but not added as overlay on existing main window.
Any inputs ?
The easiest is to set your overlay widget's parent to be the main window. But because it will not be in any layout you have to take care of its geometry yourself. In case you want to have multiple overlays, the last added will be the top most.
#include <QApplication>
#include <QtGui>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QMainWindow *window = new QMainWindow();
QWidget *centralWiddget = new QWidget();
window->setCentralWidget(centralWiddget);
QVBoxLayout *layout = new QVBoxLayout(centralWiddget);
QPushButton *button = new QPushButton("Button in a layout");
layout->addWidget(button);
QPushButton *overlayButton = new QPushButton("Button overlay");
overlayButton->setParent(window);
overlayButton->setGeometry(40, 40, 120, 30)
window->show();
return app.exec();
}
You should look into using QStackedLayout to so this.

Qt GUI design programmatically

I'm try to create a GUI application.
The main window, a QMainWindow, contains 9 labels with fixed size and also the size of the main window.
I tried to make it programmatically without Qt GUI Designer. The project is built without error but I cannot see any label nor layout shown on the main window. it's just blank.
Here is my source code:
WCwindow::WCwindow()
{
// initialize widgets with text
CAM111 = new QLabel("CAM 01");
CAM121 = new QLabel("CAM 02");
CAM131 = new QLabel("CAM 03");
CAM211 = new QLabel("CAM 04");
CAM221 = new QLabel("CAM 05");
CAM231 = new QLabel("CAM 06");
CAM311 = new QLabel("CAM 07");
CAM321 = new QLabel("CAM 08");
CAM331 = new QLabel("CAM 09");
CAM111->setFixedSize(wcW,wcH);
CAM121->setFixedSize(wcW,wcH);
CAM131->setFixedSize(wcW,wcH);
CAM211->setFixedSize(wcW,wcH);
CAM221->setFixedSize(wcW,wcH);
CAM231->setFixedSize(wcW,wcH);
CAM311->setFixedSize(wcW,wcH);
CAM321->setFixedSize(wcW,wcH);
CAM331->setFixedSize(wcW,wcH);
QGridLayout *layout = new QGridLayout;
layout->addWidget(CAM111,0,0);
layout->addWidget(CAM121,0,1);
layout->addWidget(CAM131,0,2);
layout->addWidget(CAM211,1,0);
layout->addWidget(CAM221,1,1);
layout->addWidget(CAM231,1,2);
layout->addWidget(CAM311,2,0);
layout->addWidget(CAM321,2,1);
layout->addWidget(CAM331,2,2);
setLayout(layout);
setWindowTitle("Camera Window");
setFixedSize(1000, 800);
}
of course, the class is initialized and evoked in main.cpp:
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
WCwindow *WCwin = new WCwindow;
WCwin->show();
return app.exec();
}
what kind of bug am I having??
The code below works fine. The problem was in the code you weren't showing. When you use a QMainWindow, as you've eventually admitted to doing, you need to set its centralWidget with a new widget that you construct.
// main.cpp
#include <QVector>
#include <QMainWindow>
#include <QLabel>
#include <QGridLayout>
#include <QApplication>
class WCwindow : public QMainWindow
{
public:
WCwindow();
private:
QVector<QLabel*> cams;
QLabel* cam(int r, int c) const {
return cams[r*3 + c];
}
};
WCwindow::WCwindow()
{
QGridLayout *layout = new QGridLayout;
for (int i = 1; i < 10; ++ i) {
QLabel * const label = new QLabel(QString("CAM %1").arg(i, 2, 10, QLatin1Char('0')));
label->setFixedSize(200, 50);
layout->addWidget(label, (i-1) / 3, (i-1) % 3);
cams << label;
}
QWidget * central = new QWidget();
setCentralWidget(central);
centralWidget()->setLayout(layout);
setWindowTitle("Camera Window");
setFixedSize(1000, 800);
}
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
WCwindow win;
win.show();
return app.exec();
}
Is WCwindow a subclass of QMainWindow? In that case i would advise to remove the layout from your window in the GUI editor by clicking the "break layout" button in the top bar, then use the following:
//setup all your labels and layout ...
//creating a QWidget, and setting the WCwindow as parent
QWidget * widget = new QWidget(this);
//set the gridlayout for the widget
widget->setLayout(layout);
//setting the WCwindow's central widget
setCentralWidget(widget);

QBoxLayout screws up QFormLayout?

Following simplified code snippet:
#include <QtGui>
int main(int argc, char **argv)
{
QApplication app(argc, argv);
QWidget *window = new QWidget();
QFormLayout *form = new QFormLayout();
// first row
form->addRow("First row:", new QLineEdit());
// second row
QWidget *hbox_widget = new QWidget();
QBoxLayout *hbox = new QHBoxLayout();
hbox->addWidget(new QLineEdit());
hbox_widget->setLayout(hbox);
form->addRow("Second row:", hbox_widget);
window->setLayout(form);
window->show();
return app.exec();
}
Here, I create a QFormLayout with two rows: the first is a classic example of label+input widget, the second one is almost the same, with the exception that the input widget is "boxed" in a QHBoxLayout(+containing widget).
For some reason, this seems to screw up the "vertical centering" of the input widget (in the 2nd row). How can I add a widget which contains others in a hboxlayout to a formlayout, and still have them all centered vertically?
Set the contents margins of the QHBoxLayout to 0:
QBoxLayout *hbox = new QHBoxLayout();
hbox->setContentsMargins(0, 0, 0, 0);

Qt - Making a Splitter Horizontal and Vertical at same time

I have a QGridLayout with a QSplitter on it. In that QSplitter I have two elements with a splitter that lets me move the splitter from left to right. Fine, there it's fine. But then I want to add another splitter but that moves up to down. (I'll explain with an image.)
So it's mostly having 2 splitters, one that moves left-to-right and other that moves up-to-down.
I hope you understand.
QGridLayout *layout = new QGridLayout(this);
QSplitter *splitter = new QSplitter();
text1 = new QPlainTextEdit();
text2 = new QPlainTextEdit();
splitter->addWidget(text1);
splitter->addWidget(text2);
text1->resize(800, this->height());
layout->addWidget(splitter, 1, 0);
browser = new QTextBrowser();
browser->resize(1, 1);
layout->addWidget(browser, 2, 0);
setLayout(layout);
Here i add only 1 splitter, since i don't know how to do the 2nd one.
You should be able to adapt this for your needs easily. The idea is to create a container for the first two elements, then connect the container with the 3rd element all via splitters.
#include <QtGui>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QWidget wnd;
QTextEdit *editor1 = new QTextEdit;
QTextEdit *editor2 = new QTextEdit;
QTextEdit *editor3 = new QTextEdit;
QSplitter *split1 = new QSplitter;
QSplitter *split2 = new QSplitter;
QVBoxLayout *layout = new QVBoxLayout;
QWidget *container = new QWidget;
QVBoxLayout *container_layout = new QVBoxLayout;
split1->addWidget(editor1);
split1->addWidget(editor2);
container_layout->addWidget(split1);
container->setLayout(container_layout);
split2->setOrientation(Qt::Vertical);
split2->addWidget(container);
split2->addWidget(editor3);
layout->addWidget(split2);
wnd.setLayout(layout);
wnd.show();
return app.exec();
}

Resources