Pyqt margin padding setting invalid in parent-children widget [duplicate] - python

I have set up an image button with some text, but the image does not align with the text due to some extra margins. How can I get rid of these margins? I have tried setting setContentsMargins(0,0,0,0) and setSpacing(0) on various components but it doesn't seem to affect the correct margins.
Here is a demo:
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
class ImageButton(QWidget):
def __init__(self, img_location):
QWidget.__init__(self)
self.img_location = img_location
self.button = QToolButton(self)
self.button.clicked.connect(self.handleButton)
self.button.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
self.button.setIcon(QIcon(img_location))
self.button.setIconSize(QSize(300,400))
layout = QVBoxLayout(self)
layout.addWidget(self.button)
def handleButton(self):
print(self.img_location)
app = QApplication([])
window = QMainWindow()
window.resize(800,600)
label_title = QLabel("bob asdfjak f ajksf asljf ajdslf aldskj ksf kslfhadjks lfhiu sofhjaklfsiuod fahklfhadisufaksufhdsuifhosa fasdf afsda")
label_title.setStyleSheet('background-color: yellow')
label_title.setAlignment(Qt.AlignCenter)
label_title.adjustSize()
label_title.setWordWrap(True)
imgbtn = ImageButton("a.png")
imgbtn.setStyleSheet('background-color: green')
layout_box = QVBoxLayout()
layout_box.setContentsMargins(0,0,0,0)
layout_box.setSpacing(0)
layout_box.addWidget(imgbtn, 0, Qt.AlignTop)
layout_box.addWidget(label_title, 0, Qt.AlignTop)
layout_box.setAlignment(Qt.AlignCenter)
layout_box.setSpacing(0)
content = QWidget()
content.setStyleSheet('background-color: blue')
content.setFixedWidth(300)
content.setFixedHeight(400)
content.setLayout(layout_box)
window.setCentralWidget(content)
window.show()
app.exec_()
The Yellow region marks the text label, the Green region marks the imagebutton, and the Blue region marks the space I'm trying to get rid of. See how the yellow region expands to the size of the blue, with the end result that the text doesn't align to the imagebutton.
How can I get rid of this blue region?

That margin is that of the QVBoxLayout that you use to place the QToolButton inside ImageButton, so the solution is to set it to 0 that margin:
# ...
class ImageButton(QWidget):
def __init__(self, img_location):
super().__init__(self)
# ...
layout = QVBoxLayout(self)
layout.addWidget(self.button)
layout.setContentsMargins(0, 0, 0, 0)
# ...

Related

PyQt5 Example of Using `QSizePolicy` to Shrink a Widget

I am trying to stop a widget from expanding by setting its size policy but things are not working.
The following code runs:
from PyQt5.QtWidgets import*
import pyqtgraph as pg
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.layout = QHBoxLayout()
self.left_widget = pg.GraphicsLayoutWidget()
self.layout.addWidget(self.left_widget)
self.right_widget = RightWidget()
#self.right_widget.groupbox.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
self.layout.addWidget(self.right_widget)
self.widget = QWidget()
self.widget.setLayout(self.layout)
self.setCentralWidget(self.widget)
class RightWidget(QWidget):
def __init__(self):
super().__init__()
self.layout = QVBoxLayout()
self.groupbox = QGroupBox()
self.groupbox.setTitle("some title")
#self.groupbox.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
self.groupboxlayout = QVBoxLayout()
self.button1 = QPushButton ("1")
self.groupboxlayout.addWidget(self.button1)
self.button2 = QPushButton ("2")
self.groupboxlayout.addWidget(self.button2)
self.button3 = QPushButton ("3")
self.groupboxlayout.addWidget(self.button3)
self.groupbox.setLayout(self.groupboxlayout)
self.layout.addWidget(self.groupbox)
self.button4 = QPushButton ("4")
self.layout.addWidget(self.button4)
self.button5 = QPushButton ("5")
self.layout.addWidget(self.button5)
self.setLayout(self.layout)
if __name__ == '__main__':
import sys
system_app = QApplication(sys.argv)
main = MainWindow()
main.show()
system_app.exec()
It gives:
The specific choice of widgets should not matter. The point is that, there is a large widget on the left and there are smaller widgets on the right that is not large enough to fill the column. I want to modify the above code to shrink the widgets on the right hand side. That is:
In words, I want the widgets to shrink to top and bottom of the page in a way taking minimum space (and hence leaving the middle empty).
I attempted to use QSizePolicy to achieve the desired result. The commented lines seem to have no impact on the page at all. I don't know what went wrong.

QPaintEvent event rect for scrollable widget

I have a QPaintEvent override for a custom widget that has a fixed size set. This fixed size can change per instance but in this simple example, ive set it. however the PaintEvent doesn't take it into account so when the users scrolls to the right the rectangle shouldn't paint rounded corners since the widget extends past the visible viewport. How do i fix this?
Full widget painted correctly...
When i resize dialog and scroll right, you'll see rounded corners appear on the left side... when it should NOT.
They should look like this...
Code
import os
import sys
from PySide2 import QtGui, QtWidgets, QtCore, QtSvg
class Card(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Card, self).__init__(parent=parent)
self.label = QtWidgets.QLabel('Help This Paint Event Is Broken')
self.label.setFixedHeight(40)
self.label.setFixedWidth(300)
self.mainLayout = QtWidgets.QVBoxLayout(self)
self.mainLayout.addWidget(self.label)
# overrides
def paintEvent(self, event):
painter = QtGui.QPainter()
painter.begin(self)
painter.setOpacity(1.0)
painter.setRenderHints(QtGui.QPainter.Antialiasing)
painter.setPen(QtGui.QColor(0, 0, 0, 128))
painter.setPen(QtCore.Qt.NoPen)
painter.setBrush(QtGui.QColor('#F44336'))
painter.drawRoundedRect(event.rect(), 12, 12)
painter.setRenderHint(QtGui.QPainter.Antialiasing)
painter.end()
class ListViewExample(QtWidgets.QWidget):
def __init__(self, parent=None):
super(ListViewExample, self).__init__(parent)
self.resize(200,200)
self.listView = QtWidgets.QListWidget()
self.listView.setSpacing(10)
self.listView.setVerticalScrollMode(QtWidgets.QAbstractItemView.ScrollPerPixel)
self.listView.verticalScrollBar().setSingleStep(10)
# layout
self.mainLayout = QtWidgets.QVBoxLayout()
self.mainLayout.setContentsMargins(0,0,0,0)
self.mainLayout.addWidget(self.listView)
self.setLayout(self.mainLayout)
for x in range(50):
wgt = Card()
self.appendItem(wgt)
def appendItem(self, widget):
lwi = QtWidgets.QListWidgetItem()
lwi.setSizeHint(widget.sizeHint())
self.listView.addItem(lwi)
self.listView.setItemWidget(lwi, widget)
################################################################################
# Widgets
################################################################################
def unitTest_CardDelegate():
app = QtWidgets.QApplication(sys.argv)
window = ListViewExample()
window.show()
app.exec_()
if __name__ == '__main__':
pass
unitTest_CardDelegate()
QPaintEvent::rect() returns the visible rectangle, not the rectangle of the widget itself, so you observe this behavior. The solution is:
painter.drawRoundedRect(self.rect(), 12, 12)

Can't remove margins from QVBoxLayout

I have set up an image button with some text, but the image does not align with the text due to some extra margins. How can I get rid of these margins? I have tried setting setContentsMargins(0,0,0,0) and setSpacing(0) on various components but it doesn't seem to affect the correct margins.
Here is a demo:
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
class ImageButton(QWidget):
def __init__(self, img_location):
QWidget.__init__(self)
self.img_location = img_location
self.button = QToolButton(self)
self.button.clicked.connect(self.handleButton)
self.button.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
self.button.setIcon(QIcon(img_location))
self.button.setIconSize(QSize(300,400))
layout = QVBoxLayout(self)
layout.addWidget(self.button)
def handleButton(self):
print(self.img_location)
app = QApplication([])
window = QMainWindow()
window.resize(800,600)
label_title = QLabel("bob asdfjak f ajksf asljf ajdslf aldskj ksf kslfhadjks lfhiu sofhjaklfsiuod fahklfhadisufaksufhdsuifhosa fasdf afsda")
label_title.setStyleSheet('background-color: yellow')
label_title.setAlignment(Qt.AlignCenter)
label_title.adjustSize()
label_title.setWordWrap(True)
imgbtn = ImageButton("a.png")
imgbtn.setStyleSheet('background-color: green')
layout_box = QVBoxLayout()
layout_box.setContentsMargins(0,0,0,0)
layout_box.setSpacing(0)
layout_box.addWidget(imgbtn, 0, Qt.AlignTop)
layout_box.addWidget(label_title, 0, Qt.AlignTop)
layout_box.setAlignment(Qt.AlignCenter)
layout_box.setSpacing(0)
content = QWidget()
content.setStyleSheet('background-color: blue')
content.setFixedWidth(300)
content.setFixedHeight(400)
content.setLayout(layout_box)
window.setCentralWidget(content)
window.show()
app.exec_()
The Yellow region marks the text label, the Green region marks the imagebutton, and the Blue region marks the space I'm trying to get rid of. See how the yellow region expands to the size of the blue, with the end result that the text doesn't align to the imagebutton.
How can I get rid of this blue region?
That margin is that of the QVBoxLayout that you use to place the QToolButton inside ImageButton, so the solution is to set it to 0 that margin:
# ...
class ImageButton(QWidget):
def __init__(self, img_location):
super().__init__(self)
# ...
layout = QVBoxLayout(self)
layout.addWidget(self.button)
layout.setContentsMargins(0, 0, 0, 0)
# ...

How can I show overlapping QWidgets with Pyqt5?

I have a toplevel widget with a layout set and 2 other widgets added to that layout, when I color them all I only see the toplevel widget color but Id like to see the children widgets on top. This is what I have attempted but it just displays a blue QWidget, I am expecting red and green widgets one on top of the other
def set_color(widget, color):
p = widget.palette()
p.setColor(widget.backgroundRole(), color)
widget.setPalette(p)
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication, QWidget,QVBoxLayout
app = QApplication([])
win = QWidget()
win.show()
win.resize(1920,1080)
vlayout = QVBoxLayout()
win.setLayout(vlayout)
set_color(win, Qt.blue)
mod_group = QWidget()
mod_layout = QHBoxLayout()
mod_group.setLayout(mod_layout)
vlayout.addWidget(mod_group)
set_color(mod_group, Qt.red)
mod_group.show()
audio_group = QWidget()
audio_layout = QHBoxLayout()
vlayout.addWidget(audio_group)
audio_group.setLayout(audio_layout)
set_color(audio_group, Qt.green)
audio_group.show()
The widgets are visible but the background color you use is the same as the parent widget, so that they are applied correctly you must enable the autoFillBackground property:
mod_group.setAutoFillBackground(True)
audio_group.setAutoFillBackground(True)

How to control spacing inside of QSplitter

The code below creates a dialog window with a QSplitter.
The left and right side of splitter is assigned a dark-colored QWidget.
Each QWidget layout's spacing was set to 0 (zero) (so there should be no margin).
To each of these 0-spacing layouts there was a light colored QLabel added.
I want QLabel to fill an entire QWidget with no spacing or margin. So QLabel would expand and to extend from edge to edge. Ideally we would not see the dark color of the QWidget. How could we modify the code so the QLabel extends from edge to edge inside of QWidget?
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
app = QApplication([])
window = QDialog()
window.setLayout(QVBoxLayout())
window.resize(400, 250)
splitter = QSplitter(Qt.Horizontal)
window.layout().addWidget(splitter)
for side in ['left', 'right']:
widget = QWidget()
widget.setStyleSheet("background-color:gray;")
widget_layout = QVBoxLayout()
widget_layout.setSpacing(0)
widget.setLayout(widget_layout)
label = QLabel('%s side QLabel' % side.capitalize())
label.setAlignment(Qt.AlignCenter)
label.setStyleSheet("background-color:lightgray;")
widget.layout().addWidget(label)
splitter.addWidget(widget)
window.show()
sys.exit(app.exec_())
You must set the layout margins to 0:
widget_layout.setContentsMargins(0, 0, 0, 0)
Code:
app = QApplication(sys.argv)
window = QDialog()
window.setLayout(QVBoxLayout())
window.resize(400, 250)
splitter = QSplitter(Qt.Horizontal)
window.layout().addWidget(splitter)
for side in ['left', 'right']:
widget = QWidget()
widget.setStyleSheet("background-color:gray;")
widget_layout = QVBoxLayout()
widget_layout.setContentsMargins(0, 0, 0, 0) # this line
widget_layout.setSpacing(0)
widget.setLayout(widget_layout)
label = QLabel('%s side QLabel' % side.capitalize())
label.setAlignment(Qt.AlignCenter)
label.setStyleSheet("background-color:lightgray;")
label.setContentsMargins(0, 0, 0, 0)
widget.layout().addWidget(label)
splitter.addWidget(widget)
window.show()
sys.exit(app.exec_())
Screenshot:
Note: setSpacing() is unnecessary in this case since this indicates the space between widgets inside a layout, but in this case only the QLabel is only in the layout.
You can also use:
splitter->setHandleWidth(1);

Categories

Resources