Search code examples
pythonpysidepyside6

Space is added to the layout even if nothing was added


I have been designing a PySide6 Application but the problem is that even if I have not added any space to the layout the layout still contains a lot of visible space.

Updated Screenshot

Debug Screenshot with widget borders as red: Updated Screenshot

Is there anyway to remove the space? Here is the code:

from PySide6 import QtCore
from PySide6.QtWidgets import (
    QMainWindow,
    QVBoxLayout,
    QFormLayout,
    QWidget,
    QApplication,
    QLabel,
    QCheckBox,
    QHBoxLayout,
    QLineEdit,
    QFileDialog,
    QPushButton
)
import os
import sys


class Styler_Py(QMainWindow):
    def __init__(self, parent=None) -> None:
        super().__init__(parent)

        # Window Setup
        self.setWindowTitle("PyStyler")

        # Layout setup        
        self.container_widget = QWidget()
        self.main_layout = QVBoxLayout()
        self.container_widget.setLayout(self.main_layout)
        self.setCentralWidget(self.container_widget)

        # Irrelevant code here

        # --- New Section ---
        self.main_layout.addSpacing(10)
        self.main_layout.addStretch()
        # --- New Section ---

        # Files
        self.files_label = QLabel("<h3>Files</h3>")  # Note for the future, the closure tag did not have forward slash and have been fixed using an answer below
        self.main_layout.addWidget(self.files_label)
        self.files_layout = QVBoxLayout()
        self.main_layout.addLayout(self.files_layout)

        # Files -> Input File
        self.input_file = FileInput()
        self.input_file_layout = QHBoxLayout()
        self.files_layout.addLayout(self.input_file_layout)
        self.input_file_label = QLabel("Input File")
        self.input_file_layout.addWidget(self.input_file_label)
        self.input_file_layout.addWidget(self.input_file)
        


class FileInput(QWidget):
    def __init__(self, start_path=os.path.expanduser("~")) -> None:
        super().__init__()
        self._main_layout = QHBoxLayout()
        self.setLayout(self._main_layout)

        # Add Text edit for File Input
        self._file_input = QLineEdit(start_path)
        self._main_layout.addWidget(self._file_input)
        self._file_input_browse = QPushButton("Browse")
        self._file_input_browse.clicked.connect(self._browse_file_dialog)
        self._main_layout.addWidget(self._file_input_browse)
        self._start_path = start_path
    
    def _browse_file_dialog(self):
        if os.path.isfile(self._file_input.text()):
            path = os.path.abspath(f"{self._file_input.text()}/..")
        if os.path.isdir(self._file_input.text()):
            path = os.path.abspath(self._file_input.text())
        else:
            path = self._start_path
        file_name = QFileDialog.getOpenFileName(
            self, "Open File", path
        )
        if len(file_name[0]) > 0:
            self._file_input.setText(file_name[0])
    
    def get_path(self):
        return self._file_input.text()


def main():
    app = QApplication(sys.argv)
    app.setStyleSheet("*{ border: 1px solid red; }")
    window = Styler_Py()
    window.show()
    app.exec()

main()

I think the problem is somewhere with my custom widget but I could not find it. I have tried adding and removing a lot of the widgets but nothing happens.

Edit A Screenshot of window when resized to be a little bigger: Screenshot but bigger window


Solution

  • The first problem comes from the wrong tag closure, as it should be like this:

        self.files_label = QLabel("<h3>Files</h3>")
    

    Then, that spacing is the result of two aspects: layout spacings/margins and rich text margins.

    1. layout spacings are inherited by child layouts from their parent layout (so, the input_file_layout has a default spacing inherited by the files_layout, which in turns inherits that property from the main_layout;
    2. when layout managers are installed on widgets, they use the widget's style layout margins and spacings (QStyle.PM_Layout*Margin and QStyle.PM_Layout*Spacing) unless overriden by layout.setContentsMargins() or layout.setSpacing(); this not only happens top level widgets, but for child widgets too: layouts set on children widgets do not inherit the parent layout margins or spacings, and they use the default system (or style) values; this can be overridden
    3. rich text elements normally result in bigger space required by the label's sizeHint(); unfortunately there's no easy work around for that, as also explained in the Layout Issues documentation;

    In order to better understand the boundaries of each widget, you could add a simple stylesheet for testing purposes:

        app.setStyleSheet('*{ border: 1px solid black; }')
    

    Please consider that the above will override any widget border (including buttons, for example), so use it only for debugging in order to understand how the layout works; do NOT use it for general purposes, especially if applied on the application.