<bdo id='KLEL9'></bdo><ul id='KLEL9'></ul>
      <tfoot id='KLEL9'></tfoot>

      <small id='KLEL9'></small><noframes id='KLEL9'>

    1. <legend id='KLEL9'><style id='KLEL9'><dir id='KLEL9'><q id='KLEL9'></q></dir></style></legend>
    2. <i id='KLEL9'><tr id='KLEL9'><dt id='KLEL9'><q id='KLEL9'><span id='KLEL9'><b id='KLEL9'><form id='KLEL9'><ins id='KLEL9'></ins><ul id='KLEL9'></ul><sub id='KLEL9'></sub></form><legend id='KLEL9'></legend><bdo id='KLEL9'><pre id='KLEL9'><center id='KLEL9'></center></pre></bdo></b><th id='KLEL9'></th></span></q></dt></tr></i><div id='KLEL9'><tfoot id='KLEL9'></tfoot><dl id='KLEL9'><fieldset id='KLEL9'></fieldset></dl></div>

        带有 FlowLayout 小部件的 QScrollArea 未正确调整大小

        时间:2023-08-04
        <i id='qVvr7'><tr id='qVvr7'><dt id='qVvr7'><q id='qVvr7'><span id='qVvr7'><b id='qVvr7'><form id='qVvr7'><ins id='qVvr7'></ins><ul id='qVvr7'></ul><sub id='qVvr7'></sub></form><legend id='qVvr7'></legend><bdo id='qVvr7'><pre id='qVvr7'><center id='qVvr7'></center></pre></bdo></b><th id='qVvr7'></th></span></q></dt></tr></i><div id='qVvr7'><tfoot id='qVvr7'></tfoot><dl id='qVvr7'><fieldset id='qVvr7'></fieldset></dl></div>

        1. <small id='qVvr7'></small><noframes id='qVvr7'>

          <tfoot id='qVvr7'></tfoot>

          1. <legend id='qVvr7'><style id='qVvr7'><dir id='qVvr7'><q id='qVvr7'></q></dir></style></legend>
                <tbody id='qVvr7'></tbody>

                <bdo id='qVvr7'></bdo><ul id='qVvr7'></ul>
                • 本文介绍了带有 FlowLayout 小部件的 QScrollArea 未正确调整大小的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

                  问题描述

                  我想创建一个类似于 KDE(或 Gnome 或 MacOS)系统设置的小部件(例如,像这张图片)

                  I want to create a widget similar to the KDE (or Gnome or MacOS) system settings (e.g., like this picture)

                  我已经从 Qt 文档示例.

                  如果我将一些 FlowLayout 小部件(包装在带有 QVBoxLayout 的容器小部件中)放入 QScrollArea 并调整 QSrollArea 的大小,那么一切都会按照应有的方式流动和重新布局.

                  If I put some FlowLayout widgets (wrapped in a container widget with a QVBoxLayout) into a QScrollArea and resize the QSrollArea, everything flows and re-layouts as it shoulds.

                  然而,如果我增加滚动区域的宽度以减少它需要的高度,滚动区域仍然认为它的小部件需要其 minimumWidth 的原始高度:

                  However, if I increase the scroll area’s width so that it needs less height, the scroll area’s still thinks that its widgets require the orginal height for their minimumWidth:

                  如何使用子级的实际高度更新滚动区域,以便在不再需要垂直滚动条时消失?

                  How can I can I update the scroll area with the actual height of its child so that the vertical scroll bar disappears when it’s no longer needed?

                  您将在下面找到 FlowLayout 的 (Python) 实现,并在 __main__ 块中找到实际示例.

                  Below, you’ll find the (Python) implementation of the FlowLayout and in the __main__ block the actual example.

                  干杯,斯蒂芬

                  """
                  PyQt5 port of the `layouts/flowlayout
                  <https://doc.qt.io/qt-5/qtwidgets-layouts-flowlayout-example.html>`_ example
                  from Qt5.
                  
                  Usage:
                  
                      python3 -m pip install pyqt5
                      python3 flow_layout.py
                  
                  """
                  from PyQt5.QtCore import pyqtSignal, QPoint, QRect, QSize, Qt
                  from PyQt5.QtWidgets import QLayout, QSizePolicy, QSpacerItem
                  
                  
                  class FlowLayout(QLayout):
                      """A ``QLayout`` that aranges its child widgets horizontally and
                      vertically.
                  
                      If enough horizontal space is available, it looks like an ``HBoxLayout``,
                      but if enough space is lacking, it automatically wraps its children into
                      multiple rows.
                  
                      """
                      heightChanged = pyqtSignal(int)
                  
                      def __init__(self, parent=None, margin=0, spacing=-1):
                          super().__init__(parent)
                          if parent is not None:
                              self.setContentsMargins(margin, margin, margin, margin)
                          self.setSpacing(spacing)
                  
                          self._item_list = []
                  
                      def __del__(self):
                          while self.count():
                              self.takeAt(0)
                  
                      def addItem(self, item):  # pylint: disable=invalid-name
                          self._item_list.append(item)
                  
                      def addSpacing(self, size):  # pylint: disable=invalid-name
                          self.addItem(QSpacerItem(size, 0, QSizePolicy.Fixed, QSizePolicy.Minimum))
                  
                      def count(self):
                          return len(self._item_list)
                  
                      def itemAt(self, index):  # pylint: disable=invalid-name
                          if 0 <= index < len(self._item_list):
                              return self._item_list[index]
                          return None
                  
                      def takeAt(self, index):  # pylint: disable=invalid-name
                          if 0 <= index < len(self._item_list):
                              return self._item_list.pop(index)
                          return None
                  
                      def expandingDirections(self):  # pylint: disable=invalid-name,no-self-use
                          return Qt.Orientations(Qt.Orientation(0))
                  
                      def hasHeightForWidth(self):  # pylint: disable=invalid-name,no-self-use
                          return True
                  
                      def heightForWidth(self, width):  # pylint: disable=invalid-name
                          height = self._do_layout(QRect(0, 0, width, 0), True)
                          return height
                  
                      def setGeometry(self, rect):  # pylint: disable=invalid-name
                          super().setGeometry(rect)
                          self._do_layout(rect, False)
                  
                      def sizeHint(self):  # pylint: disable=invalid-name
                          return self.minimumSize()
                  
                      def minimumSize(self):  # pylint: disable=invalid-name
                          size = QSize()
                  
                          for item in self._item_list:
                              minsize = item.minimumSize()
                              extent = item.geometry().bottomRight()
                              size = size.expandedTo(QSize(minsize.width(), extent.y()))
                  
                          margin = self.contentsMargins().left()
                          size += QSize(2 * margin, 2 * margin)
                          return size
                  
                      def _do_layout(self, rect, test_only=False):
                          m = self.contentsMargins()
                          effective_rect = rect.adjusted(+m.left(), +m.top(), -m.right(), -m.bottom())
                          x = effective_rect.x()
                          y = effective_rect.y()
                          line_height = 0
                  
                          for item in self._item_list:
                              wid = item.widget()
                  
                              space_x = self.spacing()
                              space_y = self.spacing()
                              if wid is not None:
                                  space_x += wid.style().layoutSpacing(
                                      QSizePolicy.PushButton, QSizePolicy.PushButton, Qt.Horizontal)
                                  space_y += wid.style().layoutSpacing(
                                      QSizePolicy.PushButton, QSizePolicy.PushButton, Qt.Vertical)
                  
                              next_x = x + item.sizeHint().width() + space_x
                              if next_x - space_x > effective_rect.right() and line_height > 0:
                                  x = effective_rect.x()
                                  y = y + line_height + space_y
                                  next_x = x + item.sizeHint().width() + space_x
                                  line_height = 0
                  
                              if not test_only:
                                  item.setGeometry(QRect(QPoint(x, y), item.sizeHint()))
                  
                              x = next_x
                              line_height = max(line_height, item.sizeHint().height())
                  
                          new_height = y + line_height - rect.y()
                          self.heightChanged.emit(new_height)
                          return new_height
                  
                  
                  if __name__ == '__main__':
                      import sys
                      from PyQt5.QtWidgets import QApplication, QPushButton, QScrollArea, QVBoxLayout, QWidget
                  
                  
                      class Container(QWidget):
                          def __init__(self):
                              super().__init__()
                              self.setLayout(QVBoxLayout())
                              self._widgets = []
                  
                          def sizeHint(self):
                              w = self.size().width()
                              h = 0
                              for widget in self._widgets:
                                  h += widget.layout().heightForWidth(w)
                  
                              sh = super().sizeHint()
                              print(sh)
                              print(w, h)
                              return sh
                  
                          def add_widget(self, widget):
                              self._widgets.append(widget)
                              self.layout().addWidget(widget)
                  
                          def add_stretch(self):
                              self.layout().addStretch()
                  
                  
                      app = QApplication(sys.argv)  # pylint: disable=invalid-name
                      container = Container()
                      for i in range(2):
                          w = QWidget()
                          w.setWindowTitle('Flow Layout')
                          l = FlowLayout(w, 10)
                          w.setLayout(l)
                          l.addWidget(QPushButton('Short'))
                          l.addWidget(QPushButton('Longer'))
                          l.addWidget(QPushButton('Different text'))
                          l.addWidget(QPushButton('More text'))
                          l.addWidget(QPushButton('Even longer button text'))
                          container.add_widget(w)
                      container.add_stretch()
                  
                      sa = QScrollArea()
                      sa.setWidgetResizable(True)
                      sa.setWidget(container)
                      sa.show()
                  
                      sys.exit(app.exec_())
                  

                  推荐答案

                  解决方案非常简单:使用 FlowLayout 的 heightChanged 信号更新容器的最小高度(ScrollArea 的小部件).

                  The solution was (surprisingly) simple: Use the FlowLayout’s heightChanged signal to update the minimum height of the container (the ScrollArea’s widget).

                  这是一个工作示例:

                  """
                  PyQt5 port of the `layouts/flowlayout
                  <https://doc.qt.io/qt-5/qtwidgets-layouts-flowlayout-example.html>`_ example
                  from Qt5.
                  
                  """
                  from PyQt5.QtCore import pyqtSignal, QPoint, QRect, QSize, Qt
                  from PyQt5.QtWidgets import QLayout, QSizePolicy, QSpacerItem
                  
                  
                  class FlowLayout(QLayout):
                      """A ``QLayout`` that aranges its child widgets horizontally and
                      vertically.
                  
                      If enough horizontal space is available, it looks like an ``HBoxLayout``,
                      but if enough space is lacking, it automatically wraps its children into
                      multiple rows.
                  
                      """
                      heightChanged = pyqtSignal(int)
                  
                      def __init__(self, parent=None, margin=0, spacing=-1):
                          super().__init__(parent)
                          if parent is not None:
                              self.setContentsMargins(margin, margin, margin, margin)
                          self.setSpacing(spacing)
                  
                          self._item_list = []
                  
                      def __del__(self):
                          while self.count():
                              self.takeAt(0)
                  
                      def addItem(self, item):  # pylint: disable=invalid-name
                          self._item_list.append(item)
                  
                      def addSpacing(self, size):  # pylint: disable=invalid-name
                          self.addItem(QSpacerItem(size, 0, QSizePolicy.Fixed, QSizePolicy.Minimum))
                  
                      def count(self):
                          return len(self._item_list)
                  
                      def itemAt(self, index):  # pylint: disable=invalid-name
                          if 0 <= index < len(self._item_list):
                              return self._item_list[index]
                          return None
                  
                      def takeAt(self, index):  # pylint: disable=invalid-name
                          if 0 <= index < len(self._item_list):
                              return self._item_list.pop(index)
                          return None
                  
                      def expandingDirections(self):  # pylint: disable=invalid-name,no-self-use
                          return Qt.Orientations(Qt.Orientation(0))
                  
                      def hasHeightForWidth(self):  # pylint: disable=invalid-name,no-self-use
                          return True
                  
                      def heightForWidth(self, width):  # pylint: disable=invalid-name
                          height = self._do_layout(QRect(0, 0, width, 0), True)
                          return height
                  
                      def setGeometry(self, rect):  # pylint: disable=invalid-name
                          super().setGeometry(rect)
                          self._do_layout(rect, False)
                  
                      def sizeHint(self):  # pylint: disable=invalid-name
                          return self.minimumSize()
                  
                      def minimumSize(self):  # pylint: disable=invalid-name
                          size = QSize()
                  
                          for item in self._item_list:
                              minsize = item.minimumSize()
                              extent = item.geometry().bottomRight()
                              size = size.expandedTo(QSize(minsize.width(), extent.y()))
                  
                          margin = self.contentsMargins().left()
                          size += QSize(2 * margin, 2 * margin)
                          return size
                  
                      def _do_layout(self, rect, test_only=False):
                          m = self.contentsMargins()
                          effective_rect = rect.adjusted(+m.left(), +m.top(), -m.right(), -m.bottom())
                          x = effective_rect.x()
                          y = effective_rect.y()
                          line_height = 0
                  
                          for item in self._item_list:
                              wid = item.widget()
                  
                              space_x = self.spacing()
                              space_y = self.spacing()
                              if wid is not None:
                                  space_x += wid.style().layoutSpacing(
                                      QSizePolicy.PushButton, QSizePolicy.PushButton, Qt.Horizontal)
                                  space_y += wid.style().layoutSpacing(
                                      QSizePolicy.PushButton, QSizePolicy.PushButton, Qt.Vertical)
                  
                              next_x = x + item.sizeHint().width() + space_x
                              if next_x - space_x > effective_rect.right() and line_height > 0:
                                  x = effective_rect.x()
                                  y = y + line_height + space_y
                                  next_x = x + item.sizeHint().width() + space_x
                                  line_height = 0
                  
                              if not test_only:
                                  item.setGeometry(QRect(QPoint(x, y), item.sizeHint()))
                  
                              x = next_x
                              line_height = max(line_height, item.sizeHint().height())
                  
                          new_height = y + line_height - rect.y()
                          self.heightChanged.emit(new_height)
                          return new_height
                  
                  
                  if __name__ == '__main__':
                      import sys
                      from PyQt5.QtWidgets import QApplication, QPushButton, QScrollArea, QVBoxLayout, QWidget, QGroupBox
                  
                      app = QApplication(sys.argv)
                  
                      container = QWidget()
                      container_layout = QVBoxLayout()
                      for i in range(2):
                          g = QGroupBox(f'Group {i}')
                          l = FlowLayout(margin=10)
                          l.heightChanged.connect(container.setMinimumHeight)
                          g.setLayout(l)
                          l.addWidget(QPushButton('Short'))
                          l.addWidget(QPushButton('Longer'))
                          l.addWidget(QPushButton('Different text'))
                          l.addWidget(QPushButton('More text'))
                          l.addWidget(QPushButton('Even longer button text'))
                          container_layout.addWidget(g)
                      container_layout.addStretch()
                      container.setLayout(container_layout)
                  
                      w = QScrollArea()
                      w.setWindowTitle('Flow Layout')
                      w.setWidgetResizable(True)
                      w.setWidget(container)
                      w.show()
                  
                      sys.exit(app.exec_())
                  

                  这篇关于带有 FlowLayout 小部件的 QScrollArea 未正确调整大小的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持html5模板网!

                  上一篇:线程实时记录 下一篇:如何从 qcombobox 获取 itemdata?

                  相关文章

                  最新文章

                • <small id='rAYK9'></small><noframes id='rAYK9'>

                  <legend id='rAYK9'><style id='rAYK9'><dir id='rAYK9'><q id='rAYK9'></q></dir></style></legend>
                    <bdo id='rAYK9'></bdo><ul id='rAYK9'></ul>
                  <tfoot id='rAYK9'></tfoot>

                • <i id='rAYK9'><tr id='rAYK9'><dt id='rAYK9'><q id='rAYK9'><span id='rAYK9'><b id='rAYK9'><form id='rAYK9'><ins id='rAYK9'></ins><ul id='rAYK9'></ul><sub id='rAYK9'></sub></form><legend id='rAYK9'></legend><bdo id='rAYK9'><pre id='rAYK9'><center id='rAYK9'></center></pre></bdo></b><th id='rAYK9'></th></span></q></dt></tr></i><div id='rAYK9'><tfoot id='rAYK9'></tfoot><dl id='rAYK9'><fieldset id='rAYK9'></fieldset></dl></div>