QPushButton changes size of widgets in layout - c++

This problem is driving me insane and I can't seem to find a logical answer. I'm pretty new to this so please bear with.
I've been creating an application where I create a vertical 'navigation bar' and need to add QPushButtons dynamically. I've noticed that the
horizontal position of a label in a QVBox changes when a QPushButton is added to it.
I've created a minimal version:
Before Adding QPushButton:
Label reaches the edge of the application
After adding QPushButton:
Label width is reduced slightly
Here is the code I'm using to dynamically add the QPushButton:
void MainWindow::on_pushButton_clicked()
{
QPushButton *newButton = new QPushButton("Test");
newButton->setContentsMargins(0,0,0,0);
newButton->setStyleSheet("margin: 0; padding: 0;");
ui->verticalLayout->setMargin(0);
ui->verticalLayout->setContentsMargins(0,0,0,0);
// add new push button inside VBox
ui->verticalLayout->addWidget(newButton);
}
.ui file:
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>203</width>
<height>224</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralWidget">
<widget class="QWidget" name="verticalLayoutWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>201</width>
<height>151</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label">
<property name="styleSheet">
<string notr="true">border: 1px solid white;</string>
</property>
<property name="text">
<string>TextLabel</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QPushButton" name="pushButton">
<property name="geometry">
<rect>
<x>10</x>
<y>180</y>
<width>181</width>
<height>32</height>
</rect>
</property>
<property name="text">
<string>Add Push Button To VBox</string>
</property>
</widget>
</widget>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>
<connections/>
</ui>
As you can see setting the margins on both the QPushButton and the layout don't seem to have any effect. Is there anyone who could shed some light on this issue?

Let's analyze your .ui with the help of Qt Designer, if we stretch the window you get the following:
As you can see the layout only affects the QLabel, so the initial button will not be handled by the layout, but the added button will be. Therefore, you do not observe a similar behavior.
The solution is to restructure the design using the following structure:
QMainWindow
└── QVBoxLayout
├── QLabel
└── QWidget
└── QVBoxLayout
└── QPushButton
You must change the size policy of the QWidget to take the minimum height by setting Maximum in Vertical Policy:
And in that second layout add the button. The .ui is the following:
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>335</width>
<height>303</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralWidget">
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QLabel" name="label">
<property name="styleSheet">
<string notr="true">border: 1px solid white;</string>
</property>
<property name="text">
<string>TextLabel</string>
</property>
</widget>
</item>
<item>
<widget class="QWidget" name="widget" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QPushButton" name="pushButton">
<property name="text">
<string>Add Push Button To VBox</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>
<connections/>
</ui>
Then it is no longer necessary to modify the button:
void MainWindow::on_pushButton_clicked()
{
QPushButton *newButton = new QPushButton("Test");
ui->verticalLayout->addWidget(newButton);
}
Obtaining the following:

Related

how to center a middle widget and expand its cell

In Qt designer, how do i center a middle widget in a vertical/horizontal/grid layout and expand its cell at the same time, what i want to get is something like this:
what i get:
One possible solution is to place the middle QPushButton in a QWidget through a layout, and then place that QWidget in the second column of the QHBoxLayout:
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Form</class>
<widget class="QWidget" name="Form">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QPushButton" name="pushButton">
<property name="text">
<string>PushButton</string>
</property>
</widget>
</item>
<item>
<widget class="QWidget" name="widget" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QPushButton" name="pushButton_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>PushButton</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_3">
<property name="text">
<string>PushButton</string>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
Output:
You're gonna need to add a horizontal spacer. And then for the spacer you can add properties. Whether it should be fixed or expanding.
So first select and add a horizontal spacer, and then when you select the horizontal spacer, in the properties widget you'll be able to set properties to it:
The way the spacer will be placed in-between two widgets, is by first dragging the spacer and placing it in between the widgets, selecting all of them and then right-click and group horizontally. This will put your widgets and the spacer in a horizontal layout:
If you want to do it in the code manually, look into QSpacerItem.

How does the Auto-Exclusion work with QRadioButtons with nested widgets?

I am building a QWidget with QRadioButtons at different levels. In other words, my widget contains some radio buttons and a subwidget (labeled groupBox in the screenshot) that also contains radio buttons.
Here is my problem: the radio buttons inside groupBox seem to interfere with the top level radio buttons (radioButton_1 and radioButton_2). I would expect that exactly one of radioButton_1 and radioButton_2 is checked at any given time, but it is now possible to uncheck these by clicking on the currently checked radio button.
The fix I came up with is to add setChecked(true) to the signal handler for radioButton_1.clicked() and radioButton_2.clicked(), but this seems a bit hacky.
connect(ui->radioButton_1, &RadioButton::clicked, [this]() {
ui->radioButton_1.setChecked(true);
});
connect(ui->radioButton_2, &RadioButton::clicked, [this]() {
ui->radioButton_2.setChecked(true);
});
Is there a better way to get the functionality back? Perhaps a function like setRadioButtonGroup({ui->radioButton_1, ui->radioButton_2}).
EDIT:
Per request for a MCVE, below is the form mainwindow.ui. Other files (mainwindow.cpp, main.cpp, mainwindow.h) are just the boilerplate provided when a QWidget Application is created in Qt Creator.
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralWidget">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QRadioButton" name="radioButton_1">
<property name="text">
<string>radioButton_1</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="radioButton_2">
<property name="text">
<string>radioButton_2</string>
</property>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>groupBox</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QRadioButton" name="radioButton_3">
<property name="text">
<string>radioButton_3</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="radioButton_4">
<property name="text">
<string>radioButton_4</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<widget class="QStatusBar" name="statusBar"/>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>
<connections/>
</ui>
To address this, I suggest you create a QButtonGroup and add all four radio button to it.
See https://doc.qt.io/qt-5/qbuttongroup.html

Dynamically created QWidget in QFormLayout does not have frame, even if explicitly asked to do so

I have a little problem with this bit of code:
DatasetWidget::DatasetWidget(QWidget *parent) : QWidget(parent),
ui(new Ui::DatasetWidget)
{
ui->setupUi(this);
// cut non-ui related stuff here ...
// Add widgets
for(int loop=0;loop<theAmountOfItemsWeAdd;++loop)
{
QLabel * ql=new QLabel("Caption");
QLineEdit * qle=new QLineEdit(this);
qle->setSizePolicy(QSizePolicy::Policy::Expanding,QSizePolicy::Policy::Fixed);
ui->formDisp->addRow(ql,qle); // ui->formDisp is of type QFormLayout*
}
// more non-UI related code
I'm creating a QLineEdit widget and adding it to a QFormLayout, "formDisp". For some weird reason that I can't figure out, the created QLineEdit does not have any frame and setFrame doesn't enable it.
I furthermore append the relevant parts of the .ui file here:
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>DatasetWidget</class>
<widget class="QWidget" name="DatasetWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>723</width>
<height>591</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>Datensatz</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="lblCaptionDatensatz">
<property name="text">
<string>Datensatz:</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lblDatensatz">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
<underline>true</underline>
</font>
</property>
<property name="text">
<string>C-XXXX-XXX</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="leDescriptor">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string extracomment="ServiceTag"/>
</property>
<property name="maxLength">
<number>7</number>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="cmdDelete">
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="hawams.qrc">
<normaloff>:/icons/res/trash-3x.png</normaloff>:/icons/res/trash- 3x.png</iconset>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QFormLayout" name="formDisp"/>
</item>
<item>
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
</layout>
</widget>
<connections/>
</ui>
As widgets added in QtCreator look exactly how they are supposed to look, I suppose something about my code must be wrong.
Update: Problem solved: Surrounding QWidget was being used inside a QListView, where it replaced an older, fixed-size version of the widget. In the code that fills the QListView with items, there was a hard-coded size hint which forced Qt to resize the new (bigger) version of the QWidget and "squeeze" it vertically.
Conclusion: When you embed a QWidget derivate in buggy old code that resizes it so there isn't enough space anymore to display all items inside the QWidget's layout, things get messy.
The setFrame(true) is a no-op since the frame is set by default.
Alas, I can't reproduce - the following has both line edits looking identical, save for their size, and their minimum sizes are set to different values, with the second one being larger than first one. A QFormLayout does not enforce a fixed row height!
// https://github.com/KubaO/stackoverflown/tree/master/questions/lineedit-frame-37831979
#include <QtWidgets>
#include <QtUiTools>
const char ui[] = R"EOF(
<ui version="4.0">
<class>DatasetWidget</class>
<widget class="QWidget" name="DatasetWidget">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="lblCaptionDatensatz">
<property name="text">
<string>Datensatz:</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lblDatensatz">
<property name="text">
<string>C-XXXX-XXX</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="leDescriptor">
<property name="maxLength">
<number>7</number>
</property>
</widget>
</item>
<item>
<layout class="QFormLayout" name="formDisp"></layout>
</item>
</layout>
</widget>
<connections/>
</ui>)EOF";
int main(int argc, char ** argv) {
QApplication app{argc, argv};
QBuffer buf;
buf.setData(ui, sizeof(ui));
auto w = QUiLoader().load(&buf);
auto & layout = *w->findChild<QFormLayout*>("formDisp");
QLineEdit edit1, edit2;
layout.addRow("Edit1", &edit1);
layout.addRow("Edit2", &edit2);
edit1.setMinimumHeight(50);
edit2.setMinimumHeight(100);
w->show();
return app.exec();
}
Problem solved. First Widget added to QFormLayout is a QLabel. The row height is then set to the height of the label. All following widgets get stuffed into the "too narrow" rows and if Qt attempted to draw a frame around them, the text line wouldn't fit into them anymore - so there is no frame. Solution: e.g. setMinimumHeight(32) on the first element that is being added to the QFormLayout.
There was also a second mistake. The whole QWidget is the graphical representation of a dataset, and in the main application many instances of this widget are used in a QListView to display the result of a database query. Before the use of the dynamically created QWidget, I had used a static widget with a fixed size. This size was used as sizeHint inside the code that filled the QListView, and I totally forgot about that. After removing the wrong sizeHint in the code of the application's main window, also the setMinimumHeight(someInt) wasn't needed anymore.

Resizing Qt UI elements

I have a simple qt ui that contains
|- central widget
|- label
|- button
I would like to manually place and resize the label and button freely (using the mouse), and I just can't seem to be able to do that.
I can only resize the entire window, and the label/button stretch with it. I tried all combinations of size policies
Thanks!
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>326</width>
<height>254</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralWidget">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Bla</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="startButton">
<property name="text">
<string>Start</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>
<connections/>
</ui>
try to remove
<layout class="QVBoxLayout" name="verticalLayout">
and
</layout>
but if you are working under qt creator or qt designer,
you can easily do this thing. You need to choose centralWidget and click to button Break Layout that placed under menu bar.
Check this documentation. This should be helpful to utilize Qt Designer components. It is quite possible that you don't have to do lot of work. I never used this so my help ends here.

How to disable word wrapping on QWebView?

I'm using what I believe is a pretty standard example of a WYSIWYG editor from graphics-dojo built using a QWebView. The source can be found here
I'm trying to disable the word wrapping in the QWebView so if an element extends beyond the width of the window, a horizontal scrollbar will appear and no wrapping will occur. By default it appears that the text in the QWebView wraps at all window widths except when the width is resized to under about 100 pixels which is when the horizontal scrollbar appears. Given this behavior I know the horizontal scrollbar is enabled. I've looked at QWebView, QWebFrame, and QWebPage and can't seem to find any references to word wrapping. I wonder if it is a property of the underlying WebKit.
In summary: How can I disable word wrapping on a QWebView so that a horizontal scrollbar appearing is the default behavior?
The QWebView is contained in the htmleditor.ui file like this.
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>659</width>
<height>398</height>
</rect>
</property>
<property name="windowTitle">
<string>HTML Editor</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout">
<property name="margin">
<number>0</number>
</property>
<item>
<widget class="QTabWidget" name="tabWidget">
<property name="tabPosition">
<enum>QTabWidget::South</enum>
</property>
<property name="tabShape">
<enum>QTabWidget::Rounded</enum>
</property>
<property name="currentIndex">
<number>0</number>
</property>
<property name="documentMode">
<bool>true</bool>
</property>
<widget class="QWidget" name="tab">
<attribute name="title">
<string>Tab 1</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="margin">
<number>0</number>
</property>
<item>
<widget class="QWebView" name="webView">
<property name="url">
<url>
<string>about:blank</string>
</url>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_2">
<attribute name="title">
<string>Tab 2</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_3">
<property name="margin">
<number>0</number>
</property>
<item>
<widget class="QPlainTextEdit" name="plainTextEdit">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
...