Issue
When I used a custom Widget as the CentralWidget for QMainWindow in PyQt6, there was a gap between the CentralWidget and the QMainWindow? I wonder why that is.Here's my code:
from PyQt6.QtWidgets import QApplication, QWidget, QMainWindow, QLabel, QHBoxLayout
import sys
class MyWidget(QWidget):
def __init__(self):
super().__init__()
self._layout = QHBoxLayout(self)
self.label = QLabel("hello")
self.label.setStyleSheet("QLabel {color: white;}")
self._layout.addWidget(self.label)
self.setStyleSheet("background-color: black; color: white;")
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
# When using custom widgets, there is a gap
self.central_widget = MyWidget()
# When using Qwidget, there is no gap
# self.central_widget = QWidget()
# self.central_layout = QHBoxLayout()
# self.central_layout.addWidget(QLabel("hello"))
# self.central_widget.setLayout(self.central_layout)
self.setCentralWidget(self.central_widget)
# self.central_widget.setStyleSheet("background-color: black; color: white; border: none;")
if __name__ == '__main__':
app = QApplication(sys.argv)
win = MainWindow()
win.show()
sys.exit(app.exec())
I want to know why there is a difference between using a custom widget and using a QWidget, and how to fix it.
Solution
You are misinterpreting the result.
In your custom subclass you are setting the following stylesheet:
background-color: black; color: white;
This results in the following:
- subclassed QWidgets do not paint the background set in style sheets (see the QSS documentation about QWidget), with the only exception of top level widgets (windows);
- using generic properties (without proper selector types) will automatically propagate those properties to any child widget;
What you see is not the background of the widget, it's the background of the label. The gap that you see near the edges is the layout margin.
The situation is more clear if you specify the alignment on the label; when adding a child to a layout, the layout will try to make the widget occupy as much space available within the "layout cell", but if the alignment is specified it will only use the widget's size hint.
Try to do the following:
self._layout.addWidget(self.label, alignment=Qt.AlignCenter)
And you will see this:
Theoretically, you could try to nullify the layout margin:
self._layout.setContentsMargins(0, 0, 0, 0)
In reality, that is not the correct solution, because:
- you may still want a layout margin;
- spacing in the layout will not have the background, since it's only shown on the children, not the parent;
- if you need to specify the layout alignment as above, you will still have unpainted gaps;
- you will still have problems with other widgets (due to the usage of generic QSS properties, which should always be avoided for parents);
So, in order to make the widget have its own background you must use proper syntax in the QSS (with selector types) and ensure that the parent widget actually paints its background, which can be achieved either by setting the Qt.WA_StyledBackground
attribute, or by implementing the paintEvent()
.
class MyWidget(QWidget):
def __init__(self):
...
self.setStyleSheet("MyWidget { background-color: black;} ")
self.setAttribute(Qt.WA_StyledBackground)
Alternatively:
class MyWidget(QWidget):
def __init__(self):
...
self.setStyleSheet("MyWidget { background-color: black;} ")
def paintEvent(self, event):
qp = QStylePainter(self)
opt = QStyleOption()
opt.initFrom(self)
qp.drawPrimitive(QStyle.PE_Widget, opt)
Answered By - musicamante
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.