Pyqt5 关于流式布局和滚动条的综合使用

作者: dreamfly 分类: python 发布时间: 2020-03-23 21:56

流式布局

所谓流式布局指的是容器中的元素像流水一样,是可以浮动的,当元素一行或者一列占满的时候,它会自动流入到下一行或者下一列。

pyqt5流式布局

pyqt中采用流式布局的方法原理是,通过contentsMargins获取到子元素距离布局的上下左右宽度,然后我们将所有子元素进行遍历,如果它加上边距可以在一行放入的话,那么就放在一行内,如果不能,就放入到下一行,具体代码如下:

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())

滚动条的设置

pyqt中有专门的滚动条组件QScrollBar,这个组件需要配合其他组件使用,我们这里使用QScrollArea这个组件进行滚动条的设置。

滚动条的使用方法

  • 首先,我们需要声明QScrollArea
  • 然后,我们需要设置QScrollArea的位置大小
  • 最后,我们将需要产生滚动条的元素放入它的内部。
q  = QWidget()
qscrollarea = QtWidgets.QScrollArea(q)     qscrollarea.setGeometry(QRect(50,100,600,500))
qscrollarea.setWidgetResizable(True)
listWidget = QtWidgets.QListWidget()
qscrollarea.setWidget(listWidget)

流式布局和滚动条的结合案例:

在文件当前目录创建一个images文件夹,然后放入想要展示的多张图片,然后执行当前程序,就会看到带有滚动条的流式布局界面。
运行程序,需要安装pyqt5

效果图

from PyQt5.QtCore import QPoint, QRect, QSize, Qt,pyqtSignal
import os
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import (
    QApplication, QLayout, QPushButton, QSizePolicy, QWidget, QGridLayout)
import sys
class Window(QWidget):
    def __init__(self):
        self.imageheight = 100
        super(Window, self).__init__()
        self.resize(800, 600)

        #self.listwidget = QtWidgets.QListWidget(self)
        #self.listwidget.resize(400,300)
        #self.listwidget.setGeometry(QtCore.QRect(0, 0, 300, 200))
        #self.listwidget.addItem("test")

        highlight_dir = r"./images"
        self.files_it = iter([os.path.join(highlight_dir, file)
                              for file in os.listdir(highlight_dir)])

        # self.centralwidget = QtWidgets.QWidget(MainWindow)
        # self.gongzuomoshi = QtWidgets.QGroupBox(self.centralwidget)
        self.listWidget = QtWidgets.QListWidget(self)
        #self.listWidget.setFixedWidth(600)
        container_layout = QtWidgets.QVBoxLayout()
        g = QtWidgets.QGroupBox('')
        l = FlowLayout()
        g.setLayout(l)
        for file in iter(self.files_it):
            pixmap = QtGui.QPixmap(file)
            if not pixmap.isNull():
                autoWidth = pixmap.width()*self.imageheight/pixmap.height()
                label = QtWidgets.QLabel(pixmap=pixmap)
                label.setScaledContents(True)
                label.setFixedHeight(self.imageheight)
                label.setFixedWidth(autoWidth)
                l.addWidget(label)

        container_layout.addWidget(g)
        container_layout.addStretch()
        self.listWidget.setLayout(container_layout)

        self.qscrollarea = QtWidgets.QScrollArea(self)
        self.qscrollarea.setGeometry(QRect(50,100,600,500))
        self.qscrollarea.setWidgetResizable(True)
        self.qscrollarea.setWidget(self.listWidget)
        self.setWindowTitle("Flow Layout Scroll")

class FlowLayout(QLayout):
    """流式布局,使用说明
    1.声明流式布局 layout = FlowLayout
    2.将元素放入流式布局中
    3.将QGroupBox应用流式布局
    4.如果期望水平流式,将QGroupBox放入到QHBoxLayout,如果期望垂直布局,将QGroupBox放入到QVBoxLayout
    """
    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__':
    app = QApplication(sys.argv)
    mainWin = Window()

    mainWin.show()
    sys.exit(app.exec_())

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!

7条评论
  • Haintailk

    2022年9月2日 04:55

    generic cialis tadalafil When diagnosing ED, an assessment of the patient s cardiovascular status is essential, both in the context of the etiological investigation and in the context of a medication prescription

  • optonse

    2022年9月4日 10:15

    While some medications, such as nitrates like nitroglycerin and isosorbide, and recreational drugs called poppers that contain amyl or butyl nitrate, can have dangerous interactions with Cialis and should not be taken together at all, other medications and supplements interact with Cialis and make it less effective priligy online pharmacy

  • Issueks

    2022年9月6日 08:45

    cialis generic reviews ED has many causes such as adverse results of using prostate cancer treatment, after exposure to radiotherapy, atherosclerosis problems, as well as those with cardiovascular diseases or diabetes mellitus Pisansky et al

  • absotatot

    2022年9月8日 16:52

    The reason why Luo Jia engages in Karman vortex street power generation is because he has learned through the study of extraterrestrial Do Male Enhancement Pills cialis tadalafil 20mg price civilization and realized that this road can be done, and before cialis tadalafil 20mg price nuclear fusion, Karman vortex street power generation will be the most efficient and most environmentally friendly energy collection best price for generic cialis

  • autolla

    2022年9月11日 08:31

    If you re into bodybuilding, then you ve probably heard about Nolvadex. is clomiphene the same as clomid

  • idionmelm

    2022年9月18日 02:27

    doxycycline 100mg acne Featured presenters.

发表评论

您的电子邮箱地址不会被公开。