3
votes

I am using QHBoxLayout for layout. The breakdown is: pic.1 is what happens, pic.2 is what I want - widgets don't overlap and there is a gap between them. For pic.2, I created a Gap widget to stick between the existing widgets. But this is a cumbersome solution which implies extra maintenance (especially when I have more than two widgets to care for). Moreover, since B overlaps A, I think the newly added gap widget overlaps A as well, maybe according the fraction of its size. I am not so sure about this.

pic 1

pic 2

I tried using self.layout.addSpacing(10), but that doesn't work. The red widget shifts by 10 pixels from where it was before, not from the border of the widget on the left.

Note, too, that the contained widgets will all have some minimum width specification.

So, how can I add the space between two widgets like in pic.2?

import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *

class Gap(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent=parent)
        self.setMinimumWidth(10)
        self.setMinimumHeight(1)

class Line(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent=parent)

        # Set layout

        self.layout = QHBoxLayout()
        self.setLayout(self.layout)

        # Set palette

        self.palette1 = QPalette()
        self.palette1.setColor(QPalette.Window, Qt.red)

        self.palette2 = QPalette()
        self.palette2.setColor(QPalette.Window, Qt.blue)

        self.palettebg = QPalette()
        self.palettebg.setColor(QPalette.Window, Qt.green)
        self.setAutoFillBackground(True)
        self.setPalette(self.palettebg)

        # Set labels

        self.label1 = QLabel(self)
        self.label1.setText("A")
        self.label1.setStyleSheet('font-size: 36pt;')
        self.label1.adjustSize()
        self.label1.setAutoFillBackground(True)
        self.label1.setPalette(self.palette1)
        self.label1.setMinimumSize(36, 36)

        self.label2 = QLabel(self)
        self.label2.setText("B")
        self.label2.move(30, 0)
        self.label2.setStyleSheet('font-size: 36pt;')
        self.label2.adjustSize()
        self.label2.setAutoFillBackground(True)
        self.label2.setPalette(self.palette2)
        self.label2.setMinimumSize(36, 36)

        self.gap = Gap()

        self.layout.addWidget(self.label1)
        # self.layout.addWidget(self.gap)
        # self.layout.addSpacing(10)
        self.layout.addWidget(self.label2)

class App(QMainWindow):

    def __init__(self):
        super().__init__()
        self.title = 'PyQt5'
        self.left = 10
        self.top = 10
        self.width = 200
        self.height = 54
        self.initUI()

    def initUI(self):
        self.setWindowTitle(self.title)
        self.setGeometry(self.left, self.top, self.width, self.height)

        self.line = Line(self)
        self.line.resize(74, 54)
        self.line.move(50, 50)

        self.show()

if __name__ == '__main__':
    app = QApplication(sys.argv)

    # CUSTOM
    app.setFont(QFontDatabase().font("Monospace", "Regular", 14))

    ex = App()
    sys.exit(app.exec_())

EDIT clarification, as requested: (1) suppose the size of the parent widget is too small (and cannot be resized), (2) the parent widget has QHBoxLayout with widgets A and B added to it, (3) the parent widget being too small, QHBoxLayout aranges the child widgets A and B such that they overlap each other like in the first picture. (4) Such overlap is undesirable, instead the widgets just need to be placed one after another, with no overlap, and with gap between them, like in picture 2. I don't know how to do this with QHBoxLayout.

EDIT 2 Here is a visual explanation.

The green here is the parent widget - not resizable by assumption. Widget A is added:

enter image description here

Add widget B:

enter image description here

Now, widget B is on top of A. I don't want it. I want this instead:

enter image description here

1
Try to change self.line.resize(74, 54) to self.line.resize(94, 60)S. Nick
@S.Nick that would indeed work, but that defeats the point, which is to have the parent's size not sufficiently large. Sorry I didn't clarify this.user3496846
Please edit your question to include that point and clarify exactly what you are trying to achieve.G.M.
@G.M. ok, I added a summary of my problemuser3496846

1 Answers

2
votes

The minimumSize of the child widgets does not influence the minimumSize of the parent widget, and the use of the layout does not influence the minimumSize of the widget either. The layouts set the minimumSizeHint and sizeHint using as information the minimumSize of the widgets that handle plus other features such as the size and sizing policy. So in the first instance you must set the minimumSize of the parent widget to be the minimumSizeHint of it.

On the other hand the layout has a spacing by default so it is advisable to set it to 0.

class Line(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent=parent, autoFillBackground=True)
        # Set palette
        palette1 = QPalette()
        palette1.setColor(QPalette.Window, Qt.red)

        palette2 = QPalette()
        palette2.setColor(QPalette.Window, Qt.blue)

        palettebg = QPalette()
        palettebg.setColor(QPalette.Window, Qt.green)
        self.setPalette(palettebg)

        # Set labels
        self.label1 = QLabel(text="A", autoFillBackground=True)
        self.label1.setStyleSheet('font-size: 36pt;')
        self.label1.setPalette(palette1)
        self.label1.setMinimumSize(36, 36)
        self.label1.adjustSize()

        self.label2 = QLabel(text="B", autoFillBackground=True)
        self.label2.setStyleSheet('font-size: 36pt;')
        self.label2.setPalette(palette2)
        self.label2.setMinimumSize(36, 36)
        self.label2.adjustSize()

        # Set layout
        layout = QHBoxLayout(self, spacing=0)
        layout.addWidget(self.label1)
        layout.addSpacing(10)
        layout.addWidget(self.label2)
        self.setMinimumSize(self.minimumSizeHint())
        # or
        # layout = QHBoxLayout(self, spacing=10)
        # layout.addWidget(self.label1)
        # layout.addWidget(self.label2)
        # self.setMinimumSize(self.minimumSizeHint())

enter image description here


Update:

The maximum size of the layout that can be handled is the size of the parent widget, so in its case it will compress not respecting the spaces, a solution is to set a widget that is the content, and in that to establish the layout, so the layout will stretch to the content widget with freedom.

class Line(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent=parent, autoFillBackground=True)
        # Set palette
        palette1 = QPalette()
        palette1.setColor(QPalette.Window, Qt.red)

        palette2 = QPalette()
        palette2.setColor(QPalette.Window, Qt.blue)

        palettebg = QPalette()
        palettebg.setColor(QPalette.Window, Qt.green)
        self.setPalette(palettebg)

        # Set labels
        self.label1 = QLabel(text="A", autoFillBackground=True)
        self.label1.setStyleSheet('font-size: 36pt;')
        self.label1.setPalette(palette1)
        self.label1.setMinimumSize(36, 36)
        self.label1.adjustSize()

        self.label2 = QLabel(text="B", autoFillBackground=True)
        self.label2.setStyleSheet('font-size: 36pt;')
        self.label2.setPalette(palette2)
        self.label2.setMinimumSize(36, 36)
        self.label2.adjustSize()

        content_widget = QWidget(self)
        layout = QHBoxLayout(content_widget, spacing=10)
        layout.addWidget(self.label1)
        layout.addWidget(self.label2)
        content_widget.setFixedSize(content_widget.minimumSizeHint())

enter image description here