certflow.widgets.flow_layout 源代码

"""自动换行的 ``FlowLayout``。

根治「标签 + 控件」稀疏单控件被 ``addStretch()`` 撑满整行的问题(重构计划第 4/5 节)。
控件按内容宽度排布,一行放不下自动折到下一行。
"""

from __future__ import annotations

from PySide6.QtCore import QRect, QSize, Qt
from PySide6.QtWidgets import QLayout, QWidget


[文档] class FlowLayout(QLayout): """流布局:水平排布子项,超出宽度自动换行。""" def __init__(self, parent: QWidget | None = None, margin: int = 0, spacing: int = -1) -> None: super().__init__(parent) if parent is not None: self.setContentsMargins(margin, margin, margin, margin) self.setSpacing(spacing if spacing >= 0 else 6) self._items: list[QLayout.Item] = []
[文档] def addItem(self, item: QLayout.Item) -> None: # noqa: N802 self._items.append(item)
[文档] def count(self) -> int: # noqa: N802 return len(self._items)
[文档] def itemAt(self, index: int) -> QLayout.Item | None: # noqa: N802 return self._items[index] if 0 <= index < len(self._items) else None
[文档] def takeAt(self, index: int) -> QLayout.Item | None: # noqa: N802 return self._items.pop(index) if 0 <= index < len(self._items) else None
[文档] def expandingDirections(self) -> Qt.Orientations: # noqa: N802 return Qt.Orientation(0)
[文档] def hasHeightForWidth(self) -> bool: # noqa: N802 return True
[文档] def heightForWidth(self, width: int) -> int: # noqa: N802 return self._do_layout(QRect(0, 0, width, 0), True)
[文档] def setGeometry(self, rect: QRect) -> None: # noqa: N802 super().setGeometry(rect) self._do_layout(rect, False)
[文档] def sizeHint(self) -> QSize: # noqa: N802 return self.minimumSize()
[文档] def minimumSize(self) -> QSize: # noqa: N802 size = QSize() for item in self._items: size = size.expandedTo(item.minimumSize()) margins = self.contentsMargins() return size + QSize( 2 * margins.left() + 2 * margins.right(), 2 * margins.top() + 2 * margins.bottom(), )
def _do_layout(self, rect: QRect, test_only: bool) -> int: margins = self.contentsMargins() effective = rect.adjusted( +margins.left(), +margins.top(), -margins.right(), -margins.bottom() ) x = effective.x() y = effective.y() line_height = 0 space_x = self.spacing() space_y = self.spacing() for item in self._items: w = item.sizeHint().width() h = item.sizeHint().height() next_x = x + w + space_x if next_x - space_x > effective.right() and line_height > 0: x = effective.x() y += line_height + space_y next_x = x + w + space_x line_height = 0 if not test_only: item.setGeometry(QRect(x, y, w, h)) x = next_x line_height = max(line_height, h) return y + line_height - rect.y() + margins.bottom()