Skip to content

FlowLayout

Qt Base Class: QLayout

Signature: QLayout(self, parent: Optional[PySide6.QtWidgets.QWidget] = None) -> None

Base classes

Name Children Inherits
Layout
prettyqt.widgets.layout

⋔ Inheritance diagram

graph TD
  1473367016960["custom_widgets.FlowLayout"]
  1473296341776["widgets.Layout"]
  1473296333968["widgets.LayoutMixin"]
  1473299815024["core.ObjectMixin"]
  140713234304496["builtins.object"]
  1473296346656["widgets.LayoutItemMixin"]
  1473365768928["QtWidgets.QLayout"]
  1473288842240["QtCore.QObject"]
  1473291690208["Shiboken.Object"]
  1473290791120["QtWidgets.QLayoutItem"]
  1473296341776 --> 1473367016960
  1473296333968 --> 1473296341776
  1473299815024 --> 1473296333968
  140713234304496 --> 1473299815024
  1473296346656 --> 1473296333968
  140713234304496 --> 1473296346656
  1473365768928 --> 1473296341776
  1473288842240 --> 1473365768928
  1473291690208 --> 1473288842240
  140713234304496 --> 1473291690208
  1473290791120 --> 1473365768928
  1473291690208 --> 1473290791120

🛈 DocStrings

Bases: Layout

Layout which adjusts its children based on space available.

Source code in prettyqt\custom_widgets\layouts\flowlayout.py
class FlowLayout(widgets.Layout):
    """Layout which adjusts its children based on space available."""

    ID = "flow"

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._items = []

    def __add__(self, other: widgets.QWidget | widgets.QLayout) -> FlowLayout:
        if not isinstance(other, widgets.QWidget | widgets.QLayout):
            raise TypeError
        self.add(other)
        return self

    def __del__(self):
        item = self.takeAt(0)
        while item:
            item = self.takeAt(0)

    def addLayout(self, layout: widgets.QLayout):
        widget = widgets.Widget()
        widget.setLayout(layout)
        self.addWidget(widget)

    def addItem(self, item):
        self._items.append(item)

    def itemAt(self, idx):
        try:
            return self._items[idx]
        except IndexError:
            pass

    def takeAt(self, idx):
        try:
            return self._items.pop(idx)
        except IndexError:
            pass

    def count(self):
        return len(self._items)

    def hasHeightForWidth(self):
        return True

    def heightForWidth(self, width):
        return self._do_layout(core.Rect(0, 0, width, 0), apply_geometry=False)

    def setGeometry(self, rect):
        super().setGeometry(rect)
        self._do_layout(rect, apply_geometry=True)

    def expandingDirections(self):
        return constants.Orientation(0)

    def minimumSize(self):
        size = core.QSize()
        for item in self._items:
            size = size.expandedTo(item.minimumSize())
        left, top, right, bottom = self.getContentsMargins()
        return size + core.QSize(left + right, top + bottom)

    sizeHint = minimumSize

    def smart_spacing(self, horizontal: bool = True) -> int:
        p = self.parent()
        if p is None:
            return -1
        if p.isWidgetType():
            which = (
                widgets.Style.PixelMetric.PM_LayoutHorizontalSpacing
                if horizontal
                else widgets.Style.PixelMetric.PM_LayoutVerticalSpacing
            )
            return p.style().pixelMetric(which, None, p)
        return p.spacing()

    def _do_layout(self, rect: core.QRect, apply_geometry: bool = False) -> int:
        erect = rect.marginsRemoved(self.contentsMargins())
        x, y = erect.x(), erect.y()

        line_height = 0

        def layout_spacing(wid, horizontal: bool = True):
            if (ans := self.smart_spacing(horizontal)) != -1:
                return ans
            if wid is None:
                return 0
            return wid.style().layoutSpacing(
                widgets.SizePolicy.ControlType.PushButton,
                widgets.SizePolicy.ControlType.PushButton,
                constants.HORIZONTAL if horizontal else constants.VERTICAL,
            )

        lines, current_line = [], []
        gmap = {}
        for item in self._items:
            isz, wid = item.sizeHint(), item.widget()
            hs, vs = layout_spacing(wid), layout_spacing(wid, False)

            next_x = x + isz.width() + hs
            if next_x - hs > erect.right() and line_height > 0:
                x = erect.x()
                y = y + line_height + vs
                next_x = x + isz.width() + hs
                lines.append((line_height, current_line))
                current_line = []
                line_height = 0
            if apply_geometry:
                gmap[item] = x, y, isz
            x = next_x
            line_height = max(line_height, isz.height())
            current_line.append((item, isz.height()))

        lines.append((line_height, current_line))

        if apply_geometry:
            for line_height, items in lines:
                for item, item_height in items:
                    x, wy, isz = gmap[item]
                    if item_height < line_height:
                        wy += (line_height - item_height) // 2
                    item.setGeometry(core.Rect(core.Point(x, wy), isz))

        return y + line_height - rect.y() + self.contentsMargins().bottom()

⌗ Property table

Qt Property Type Doc
objectName QString
spacing int
contentsMargins QMargins
sizeConstraint QLayout::SizeConstraint