Qt remove empty space between widgets on QVBoxLayout - c++

I have annoying problem. I created QVBoxLayout on which I added my widgets.
This is sample from my constructor:
layout = new QVBoxLayout;
layout->setMargin(0);
layout->setContentsMargins(QMargins(0,0,0,0));
layout->setSpacing(0);
And then I have function to add widgets.
layout->addWidget(_wave);
_wave is my own widget. But you can add whatever you want, for example QButton.
What do I want achieve?
Similar like this but without any spaces beetween widgets added to layout. Just only QButtons or other widget, sticked each other.
I added everywhere setMargins, setSpacing etc.
Please help me with that, I don't really have an idea what should I do.
Sorry for colors, but I wanted to mentioned what I want to achieve. I have mainWindow on which I added QWidget. This widget have blue background. Then to the layout, Im addding some widgets, which are orange on this image. I just want to be sure, that this blue background between widget isnt visible. I want to have widget under widget, without any space.

I know the question was posted a year ago, but if it can help some people save some time, I would be glad. I had the same problem and was able to solve it by setting:
QFrame.setFrameShape() to NoFrame
QFrame.setLineWidth() to 0.
The image below is the result of 2 QtextEdit put side by side in a Layout, using the described method.
http://doc.qt.io/qt-5/qframe.html#lineWidth-prop

Try this to achieve a "tight" look. Note that if you resize the parent widget, they will not move. Not sure if this is what you want or not, but...
// After all widgets are added to the layout
layout->insertStretch( -1, 1 );
The 2nd argument needs to be higher than any other stretch factor. Stretch factor is default zero, so if you don't set it, the above one-liner should work.

Spacing Never Zero?
As the Qt document says, some default GUI widget has extra frame around it.
Take QPushButton as an example:
In some GUI styles a default button is drawn with an extra frame
around it, up to 3 pixels or more. Qt automatically keeps this space
free around auto-default buttons, i.e. auto-default buttons may have a
slightly larger size hint.
So the culprit is not the layout but the widget itself instead. "Invisible" margin of a default widget remains even if the spacing of the layout has been set to 0.
Soultion
If you really need a "compact" layout, my suggestion is to resort to the stylesheet of the widget.
Examples
Here are examples to illustrate the idea:
Here, we have a vertical layout with both margin and spacing equal to 0, and the buttons with custom stylesheet:
QPushButton {
border: 2px solid #8f8f91;
border-radius: 6px;
background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
stop: 0 #f6f7fa, stop: 1 #dadbde);
min-width: 80px;
}
// (further stylesheet for button click is needed)
Resetting stylesheet allows us to make the layout more compact:
Insert a default QPushButton to see the difference:
You can see there is space around the default QPushButton. That's the same for other kinds of widgets.

I could be wrong but there does not seem to be an obvious and non-hack of a way to do what you desire. However, according to the documentation you may find that just doing a manual layout will solve your problem. (http://doc.qt.io/qt-5/layout.html : Manual Layout)
It seems as if one could implement a Layout class that actually provides a very compact horizontal or vertical layout and I believe I had written one a few years ago using Python and Qt. With that in mind, you should be able to implement your own MyCompactLayout(horizontal=True) and use it.

Related

QDockWidget::background-color not applied when docked

I have a QDockWidget:
I would like to alert the user to certain events by setting the background color of the title bar.
I have achieved this by setting the style sheet for my DockWidget:
void DockWidget::setCriticalAlert()
{
setStyleSheet("QDockWidget { background-color:red; }");
}
The result is this:
The problem is that the background-color doesn't get applied when the QDockWidget is docked:
How can I get the background color to be applied when the QDockWidget is docked?
This is a bug in Qt.
Issue 10537
Quoting from the linked issue:
The problem is that in QDockWidget::paintEvent, there is a
isFloating() condition before drawing PE_FrameDockWidget. We cannot
jsut remove this condition as it would break the other style (that
does not whish to draw frame when the dockwidget is docked) We cannot
either use PE_Widget to draw the frame as then it goes over the
dockwidget's title The solution is maybe to introduce a new
PE_FrameDockWidgetDocked primitive element. Or some
SH_DockWidget_DrawDockedFrame stylehint to draw the frame in every
cases.
a valid workaround seems to be to set the stylesheet of the parent, and use the class-and-id selector. Forgive the python formatted code but the concept is the same - in this case, 'dock' is a QDockWidget which has been given an object name using setObjectName(), and its parent, the QMainWindow, is 'self':
self.setStyleSheet("QDockWidget#"+str(dock.objectName())+"::title {background-color:red}")
In PyQt5.5, this works at runtime, i.e., can be changed on the fly.
I find a solution like this:
Firstly put a frame behind all the widgets of dockwidget's center widget, as the background.
Then set stylesheet for the frame.
By this way, we could change the background color of dockwidget.
Or you can extend the dockwidget and overwrite the function
void QDockWidget::setWidget(QWidget *widget)
using private/qdockwidget_h. and add a frame as this widget's father.

101 Qt stylesheet margins padding hack guide in C++. Setting padding doesn't work

After months of research and asking here, I found out the solution to make margins be reset to 0 and paddings to 0, stylize a widget and start from scratch a design using stylesheets in qt.
The widgets must be containers of something else.
101 Guide to style widgets margins/padding using stylesheets in qt4
Create any kind of BoxModel stylable widget (not QWidget, use QFrame instead!). Check documentation
Assign a normal layout to it.
If you don't want the default margins, which are big as apox. 8px more or less, you have to set the layout (not the widget, you can, but doesn't work) contents margin to 0: setContentsMargins(0,0,0,0).
Optionally (I don't know which cases), to bring everything to the extreme reset (no borders, nothing at all), set spacing to 0 too. setSpacing(0)
set the widget object name to a custom name: setObjectName("name").
set your style changing QFrame by your widget: QFrame#name { things... }
If you want to stylize the custom widget and you have a custom class name for it, and you intend to use the NAME of the class instead of using setObjectName, add this small hack reimplementing your paint method, which is included in Qt Stylesheet documentation example.
If you subclass from QWidget, you need to provide a paintEvent for
your custom QWidget as below:
void CustomWidget::paintEvent(QPaintEvent *)
{
QStyleOption opt;
opt.init(this);
QPainter p(this);
style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
}
The above code is a no-operation if there is no stylesheet set.
Warning: Make sure you define the Q_OBJECT macro for your custom
widget.
Then you can create the style by using the class name. ClassName {}
Now, I have a serious problem which I shared with other people and I had no solution. Padding doesn't work at all. Only margins work.
So
ClassName
{ padding: 200px; margin: 5px; }
does the same as
ClassName
{ margin: 5px; }
That brings the bothering situation when you have to create subcontainers with margins to add a padding. That brings us to an infinite hierarchy... Which is not desirable at all.
Does anybody know how to completely finish my 101 guide?
Padding works
My problem comes from the class I used for checking that padding didn't work. It was a subclass of QWidget, which, as documentation clearly says:
Supports only the background, background-clip and background-origin
properties.
So my background property was working and I didn't understand why padding didn't.
So I answered my own question without knowing it.

Specific QPushButton style

How can I customize the look of a QPushButton or QToolButton to look something like elementaryos's webpage "buttons"?
All I really want is the characteristic image position and the text on it's side, maybe if i'm lucky i can also get a border like that, but i don't really need the little description below the title :)
Can i do it only with StyleSheets, or do i have to subclass QPushButton/QAbstractButton/Something like that? I already searched everywhere but didn't found that level of customization without things like painting something in a fixed place, which is exactly what i don't want.
EDIT:
I really would like a solution that would get me a customizable button, not a fixed image one, something in the tracks of
MainWindowButton(QString(title), /*opt*/QString(description), QImage(icon));
There are a number of approaches that may work.
You might first consider trying to compose a solution with a normal QPushButton with a QVBoxLayout on it. You could add three QLabels; one for the title text, one for the caption text and one for the image. Some CSS could probably be used to render the background image of the button for up and down and more CSS to style the text in the two labels and position the image on the third but you would then find that the labels don't shift down when the button is clicked.
I think the best solution involves direct painting. You could do this by sub classing a QWidget and overriding the paintEvent(). Render everything for the up state and shift everything over and down a bit for the down state.
You could achieve this without sub classing by rendering the up and down states to a QImage and styling a QPushbutton with them using CSS.
There are a number of combinations of these approaches too.
You can set the background as white with the icon in the right corner with some creative use of the border-image stylesheet property where the bottom border is as tall as the icon and the top, left and right borders are 0 pixels wide. You'll need to make a custom image that basically looks like the icon with a couple pixels width on the left and top that are white
http://doc.qt.digia.com/qq/qq20-qss.html#theboxmodel
The text you may have to do overriding paintEvent.

Qt window resize problem

I am having a problem redrawing a QWidget window after its size has been adjusted. I have tried update(), repaint(), adjustSize(), but all seem to suffer from the same thing: only part of the window is redrawn, resulting in the window frame on the bottom and right sides to not show. The window is also not resized entirely.
Just in case it makes a difference, the window is in a QMdiArea.
Thanks.
// ... some subwidget resizing and moving.
calibrationWindowUIs[activeWindow].layoutWidget2->move(QPoint(oldXLeft, 30 + height + 21));
calibrationWindowUIs[activeWindow].layoutWidget1->move(QPoint(oldXRight, 30 + height + 21));
// Set window size.
calibrationWindows[activeWindow]->setMinimumSize(calibrationWindowUIs[activeWindow].tabWidget->geometry().width() + 40, calibrationWindowUIs[activeWindow].tabWidget->geometry().height() + 40);
calibrationWindows[activeWindow]->update();
Note: I'm new to Qt; perhaps I'm doing something wrong with layouts?
Edit: I may have not given enough information. Alright, to be quite honest, I still have to delve deeper into layouts and related material. What I had tried to do here was to use Qt Designer in order to design the window. I've done what perhaps amounts to a stupid mistake: I didn't use an overall parent layout for the entire window, but hacked it with a couple of smaller layouts that I therefore have to move about and resize individually. See the Qt Designer screen (the red rectangles are the sole layouts): .
What is happening is that in the frame to the right, I am playing a video clip that can be of various resolutions. I want the frame to resize depending on this resolution, which also means that the buttons and window have to move/resize accordingly. That is where the window resize comes in. I'm sure there is a more elegant solution than what I am doing here, but I am trying to handle several other scenarios here and hence the lack of quality of code.
The result is that when I load a clip, the window attempts to resize, but does so badly; the following is the result:
If the window is dragged, it 'pops' into its correct size; in the meantime, however, it just looks ugly.
A couple further questions: do you use the Qt Designer to design your UIs? I found that programmatically you can achieve much better control of your interfaces. One thing which I could not do in the designer was to have a layout parented by the main widget, i.e. the equivalent of having the following bit of code:
QVBoxLayout* layout = new QVBoxLayout;
this->setLayout(layout);
A layout placed in the designer always seems to create this 'layoutWidget' subwidget, which the layout you placed is then parented to. Any way around that?
We use a mix of designer and code to create layouts, the Qt layout system can be very unintuitive at times. But I would probably not layout a full series of tabs in one designer ui file, i would make each tab each own widget and then assemble them either through code or in the designer by promoting to custom classes. This gives you better separation of responsibilities, by putting all the functionality of all the tabs into one file you almost guarantee a large unwieldy class.
When a widget has child widgets in designer you can assign a layout to it by adding it from the context menu. Make sure nothing is selected and click on the background of the widget in which you want to create a layout, select the layout and all of the widgets children will be assigned the layout.
What does help is creating hierarchies of layouts. Looking at your first screenshot, i would probably use a vertical layout with spacers on top and bottom for the items on the right, an horizontal layout with spacers left and right for the button bar and a grid layout for all the items together. Without the spacers your items will extend when the window grows. The spacers will let you control the behavior under resizing better.
you are calling setMinimumSize(). That's fine, but you should also call resize()

QWidget background color does not fully cover the QWidget

Using Qt Creator, I have set a QWidget's background property to black. However, some parts of the QWidget, more specifically, between QFrames/QGroupBoxes are still in its system's default color.
Now, I thought that the QFrames and QGroupBoxes need to have its background property set to black too, but it did not work. I have also tried setting the border-color to black, but it does not work, since by default borders, margins are set to 0.
QWidget { background: black; }
Any advice on this issue?
EDIT
The QWidgets are placed in QMdiArea. However, if I make it a QWindow, it works. However, I want the QWidgets to be in the QMdiArea. Also, if I just show the QWidgets as it is, the spaces that I have mentioned above are transparent.
It sounds like you have some widgets within another widget, and are setting the contained widgets to be black, but then the space between them is not black. If that is the case, it is likely because you have a layout in the containing widget, which allocates space between each contained widget. The empty space between widgets will be drawn with the containing widget's background color.
Found out the solution. It seems that you need to set the background color at the QMdiSubWindow, not at QWidget. Don't know why, but it seems logical.