How to manage layout on QDockWidget? - c++

I'm getting started with Qt and I have a project for my school. I want to make an interface that read a database of space-stuff and displays them.
Until now I can display the table in a list, and my actual goal is to show the details of the object when it is double clicked.
To do so I tried to open a second dock whenever the object is double clicked, and tried to make a layout inside the second dock to display properly the details.
The program successfuly open a new dock, but the widget are way too small and all packed in the upper left corner of the dock:
picture of the bug:
I tried to do not use layout but only setWidget with QDockWidget, but it does only display the last widget.
Here is my code for the layout:
dock1 = new QDockWidget(tr("Caractéristiques de l'objet : "), this);
dock1->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
QVBoxLayout* layout = new QVBoxLayout();
Nom_Objets = new QLineEdit(dock1);
layout->addWidget(Nom_Objets);
//dock1->setWidget(Nom_Objets);
Categorie_Objets = new QLineEdit(dock1);
layout->addWidget(Categorie_Objets);
//dock1->setWidget(Categorie_Objets);
Description_Objets = new QTextEdit(dock1);
layout->addWidget(Description_Objets);
//dock1->setWidget(Description_Objets);
setLayout(layout);
addDockWidget(Qt::RightDockWidgetArea, dock1);

If you want to add several widgets to a QDockWidget then you must use a QWidget as a container:
dock1 = new QDockWidget(tr("Caractéristiques de l'objet : "), this);
dock1->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
addDockWidget(Qt::RightDockWidgetArea, dock1);
QWidget* container = new QWidget;
dock1->setWidget(container);
QVBoxLayout* layout = new QVBoxLayout(container);
Nom_Objets = new QLineEdit;
Categorie_Objets = new QLineEdit;
Description_Objets = new QTextEdit;
layout->addWidget(Nom_Objets);
layout->addWidget(Categorie_Objets);
layout->addWidget(Description_Objets);

Related

Change Background Color specific QSplitter Child

I am using Qt Creator 4.13.1 with Qt 5.15.1 on Windows 10 Pro.
I am new to using Stylesheets in Qt and a bit confused of the possible selectors considering QSplitter and its child. I want to have 2 childs separated by a splitter-handle and draw their backgrounds in different colors.
This is an example szenario
QSplitter* splitter = new QSplitter();
QWidget* widgetA = new QWidget();
// add a layout with some further child widgets
QWidget* widgetB = new QWidget();
// add a layout with some further child widgets
splitter->addWidget(widgetA);
splitter->addWidget(widgetB);
layout()->addWidget(splitter);
where I tried:
widgetA->setStyleSheet("background-color: #ff0000;"); which applies to all child widgets of widgetA (e.g. QLabels, QPushButtons, ...) , but not to their surrounding widgetA itself
splitter->setStyleSheet("background-color: #ff0000;"); applies to the widgetA, widgetB and the handle and all widgets below widgetA and widgetB
naming widgetA->setObjectName("Tim"); and splitter->setStyleSheet("QWidget#Tim {background-color: #ff0000;}"); which has no effect at all.
[EDIT] splitter->setStyleSheet("QSplitter QWidget #Andy {background-color: #ff0000;}"); applies the background only to a certain widget inside either child widget. But using splitter->setStyleSheet("QSplitter #Tim {background-color: #ff0000;}"); has (again) no effect at all.
How would I set the background-color of widgetA separately, so without affecting the childs of widgetA or the other splitter child widgetB?
I don't see any problems with using widget->setStyleSheet() in your case. Here, I have tested your implementation of setObjectName():
Application::Application(QWidget *parent) :
QWidget(parent)
{
//set a base layout for the parent of splitter
QHBoxLayout *boxLayout = new QHBoxLayout(this);
this->setLayout(boxLayout);
//allocate splitter with parent
QSplitter* splitter = new QSplitter(this);
QWidget* widgetA = new QWidget();
widgetA->setObjectName("widgetA");
widgetA->setLayout(new QVBoxLayout());
//example buttons as child for widgetA
QPushButton *p = new QPushButton("0",widgetA);
widgetA->layout()->addWidget(p);
p = new QPushButton("1",widgetA);
widgetA->layout()->addWidget(p);
p = new QPushButton("2",widgetA);
widgetA->layout()->addWidget(p);
p = new QPushButton("3",widgetA);
widgetA->layout()->addWidget(p);
//widgetB, all similar to widgetA
QWidget* widgetB = new QWidget();
widgetB->setObjectName("widgetB");
widgetB->setLayout(new QVBoxLayout());
widgetA->setStyleSheet("QWidget#widgetA{background-color: #ff0000;}");
widgetB->setStyleSheet("QWidget#widgetB{background-color: #00ff00;}");
p = new QPushButton("1",widgetB);
widgetB->layout()->addWidget(p);
p = new QPushButton("2",widgetB);
widgetB->layout()->addWidget(p);
p = new QPushButton("3",widgetB);
widgetB->layout()->addWidget(p);
//add both widgets to splitter
splitter->addWidget(widgetA);
splitter->addWidget(widgetB);
//add splitter to base layout
this->layout()->addWidget(splitter);
}
Output

When are widgets deleted in Qt (QVBoxLayout class)?

I have some simple code to create a new widget using Qt:
Dock::Dock() : QDockWidget() {
label = new QLabel(QLatin1String("TEST"));
QVBoxLayout* layout = new QVBoxLayout();
layout->addWidget(label, 0, Qt::AlignTop);
layout->addStretch(-1);
QWidget* multiWidget = new QWidget();
multiWidget->setLayout(layout);
setWidget(multiWidget);
}
Where label is a private member QLabel* label. My question is: am I responsible for deleting label in Dock's destructor?
I tried changing the code so that label is a std::shared_ptr<QLabel>:
Dock::Dock() : QDockWidget() {
label = std::make_shared<QLabel>(QLatin1String("TEST"));
QVBoxLayout* layout = new QVBoxLayout();
layout->addWidget(label.get(), 0, Qt::AlignTop);
layout->addStretch(-1);
QWidget* multiWidget = new QWidget();
multiWidget->setLayout(layout);
setWidget(multiWidget);
}
So that it is deleted automatically when `Dock' is destroyed but I get an error when I close the program.
In order to properly set up the objects tree you need to do the following:
Create the container widget first,
Create child widget and set it's parent,
Create layout of the container widget,
Add widget to the layout.
Here is the code that demonstrates the mentioned approach:
Dock::Dock()
:
QDockWidget()
{
QWidget* multiWidget = new QWidget;
label = new QLabel(QLatin1String("TEST"), multiWidget); // Set parent
QVBoxLayout* layout = new QVBoxLayout(multiWidget); // Sets layout
layout->addWidget(label, 0, Qt::AlignTop);
layout->addStretch(-1);
setWidget(multiWidget);
}

Qt layouts, difference between passing and not passing QWidget as parent

I have created a simple QHBoxLayout (horizontal) that is pushed to the bottom of the QVBoxLayout (Vertical) and it contains two buttons. See code:
QWidget* create_ver_and_horizontal_box() {
QWidget* temp = new QWidget();
// Add buttons to the horizontal box
QHBoxLayout* hbox = new QHBoxLayout();
QPushButton *ok = new QPushButton("OK");
QPushButton *cancel = new QPushButton("Cancel");
hbox->addWidget(ok);
hbox->addWidget(cancel);
// Create a vertical box and add the horizontal box to
// the end of it
QVBoxLayout* vbox = new QVBoxLayout();
vbox->addStretch(1);
vbox->addLayout(hbox);
// set the layout and return
temp->setLayout(vbox);
return temp;
}
and the resulting UI is the following.
But when I add the QWidget temp to be the parent of the QHBoxLayout, like so:
// Add buttons to the horizontal box
QHBoxLayout* hbox = new QHBoxLayout(temp);
This is what I get:
I want to understand what is going on here. And in which cases I want the QWidget to be the parent of a layout or any other QWidget(s) and in which cases I don't the containing QWidget to be the parent of the containing QWidgets. For example, I could've added temp to be the parent of the two Push buttons but I didn't. What is the implication of not adding vs adding.
Thanks,
QHBoxLayout* hbox = new QHBoxLayout(temp);
is equivalent to
QHBoxLayout* hbox = new QHBoxLayout();
temp->setLayout(hbox);
I.e. you are making the horizontal layout responsible for temp.
The call to setLayout(vbox) should have generated a runtime warning message, that temp already has a layout, hinting at that.
Since you want the vertical layout to be responsible for that widget, either keep the temp->setLayout(vbox) or pass temp to the constructor of QVBoxLayout.

Items in QHBoxLayout layout overlap

I can't figure out what is wrong with Qt. I am trying to create a simple layout, like this:
+-------+-----------+
| | Label1 |
| Thumb |-----------+
| | Label2 |
| |(multiline)|
+-------+-----------+
And this is the code that does this:
labelInfoName = new QLabel("Sample name", this);
labelInfoDetails = new QLabel("Sample details...", this);
labelInfoDetails->setAlignment(static_cast<Qt::Alignment>(Qt::AlignTop | Qt::AlignLeft));
QVBoxLayout* textInfoLayout = new QVBoxLayout(this);
textInfoLayout->addWidget(labelInfoName);
textInfoLayout->addWidget(labelInfoDetails, 1);
// Create info pane
imgInfoThumbnail = new QLabel(this);
imgInfoThumbnail->setFixedSize(64, 64);
imgInfoThumbnail->setStyleSheet("background: black;");
QHBoxLayout* infoLayout = new QHBoxLayout(this);
infoLayout->addWidget(imgInfoThumbnail);
infoLayout->addLayout(textInfoLayout, 1)
this->setLayout(infoLayout);
And this is a QWidget. This is the code that sets up the layout in a class derived from QWidget. Then I want to display it as a dockable widget, which I do like this from my QMainWindow class:
widget = new Widget(this); // Widget that was set up above
QDockWidget* dockWidget = new QDockWidget("Project", this);
dockWidget->setWidget(widget);
addDockWidget(Qt::LeftDockWidgetArea, dockWidget);
But this is what I get instead:
I need the widget to be a custom control that I can place anywhere. Previously, it was defined as a QDockWidget, and instead of calling this->setLayout() I was creating a QWidget object, and this worked as expected:
QWidget* widget = new QWidget(this);
widget->setLayout(infoLayout);
this->setWidget(widget);
But the way I've done it now, it puts them on top of each other. What am I doing wrong?
You are creating layout incorrectly.
When you pass parent (widget) to a layout this layout is set automatically as layout to this widget.
Problem is that once layout is set for a widget it can't be changed, I'm pretty sure you are receiving some warning about this.
So just remove this when constructing a layout (at least in first case):
labelInfoName = new QLabel("Sample name", this);
labelInfoDetails = new QLabel("Sample details...", this);
labelInfoDetails->setAlignment(static_cast<Qt::Alignment>(Qt::AlignTop | Qt::AlignLeft));
QVBoxLayout* textInfoLayout = new QVBoxLayout();
textInfoLayout->addWidget(labelInfoName);
textInfoLayout->addWidget(labelInfoDetails, 1);
// Create info pane
imgInfoThumbnail = new QLabel(this);
imgInfoThumbnail->setFixedSize(64, 64);
imgInfoThumbnail->setStyleSheet("background: black;");
QHBoxLayout* infoLayout = new QHBoxLayout(this);
infoLayout->addWidget(imgInfoThumbnail);
infoLayout->addLayout(textInfoLayout, 1)
this->setLayout(infoLayout);

Layouts doesn't work in Qt

i'm having a problem with layouts in Qt. I'm trying to compile this code, with 2 horizontal layouts and a vertical main layout. Each horizontal layout have 3 buttons and both horizontal layout are incorporated in the vertical layout. But after i compile this code, i can only see a small window with just the "Exit" button.
firstline = new QHBoxLayout(this);
secondline = new QHBoxLayout(this);
layout = new QVBoxLayout(this);
eat = new QPushButton("Eat", this);
drink = new QPushButton("Drink", this);
smoke = new QPushButton("Smoke", this);
save = new QPushButton("Save", this);
load = new QPushButton("Load", this);
exit = new QPushButton("Exit", this);
firstline->addWidget(eat);
firstline->addWidget(drink);
firstline->addWidget(smoke);
secondline->addWidget(save);
secondline->addWidget(load);
secondline->addWidget(exit);
layout->addLayout(firstline);
layout->addLayout(secondline);
setLayout(layout);
You are already setting the layout for your dialog through these statements...
firstline = new QHBoxLayout(this);
secondline = new QHBoxLayout(this);
So call their constructors without specifying their parent widget.
firstline = new QHBoxLayout();
secondline = new QHBoxLayout();
This would display your layout as you are expecting.