pyqt瀑布流布局

最近研究瀑布流布局,发现都是收费的,所以只能自己写算法写布局。
所以啥都不说直接上代码

ImageLabel

参考 pyqt5 QLabel显示网络图片或qfluentwidgets官网

代码

import math
import sys
from pathlib import Pathfrom PyQt5.Qt import *
from qfluentwidgets import ImageLabelclass FlowLayout(QLayout):""" 流布局 """def __init__(self, parent=None, needAni=False, isTight=False):"""Parameters----------parent:parent window or layoutneedAni: boolwhether to add moving animationisTight: boolwhether to use the tight layout when widgets are hidden"""super().__init__(parent)self._items = []  # type: List[QLayoutItem]self._anis = []  # type: List[QPropertyAnimation]self._aniGroup = QParallelAnimationGroup(self)self._verticalSpacing = 10self._horizontalSpacing = 10self.duration = 300self.ease = QEasingCurve.Linearself.needAni = needAniself.isTight = isTightself._deBounceTimer = QTimer(self)self._deBounceTimer.setSingleShot(True)self._deBounceTimer.timeout.connect(lambda: self._doLayout(self.geometry(), True))self._wParent = Noneself._isInstalledEventFilter = Falsedef addItem(self, item):self._items.append(item)def insertItem(self, index, item):self._items.insert(index, item)def addWidget(self, w):super().addWidget(w)self._onWidgetAdded(w)def insertWidget(self, index, w):self.insertItem(index, QWidgetItem(w))self.addChildWidget(w)self._onWidgetAdded(w, index)def _onWidgetAdded(self, w, index=-1):if not self._isInstalledEventFilter:if w.parent():self._wParent = w.parent()w.parent().installEventFilter(self)else:w.installEventFilter(self)if not self.needAni:returnani = QPropertyAnimation(w, b'geometry')ani.setEndValue(QRect(QPoint(0, 0), w.size()))ani.setDuration(self.duration)ani.setEasingCurve(self.ease)w.setProperty('flowAni', ani)self._aniGroup.addAnimation(ani)if index == -1:self._anis.append(ani)else:self._anis.insert(index, ani)def setAnimation(self, duration, ease=QEasingCurve.Linear):""" set the moving animationParameters----------duration: intthe duration of animation in millisecondsease: QEasingCurvethe easing curve of animation"""if not self.needAni:returnself.duration = durationself.ease = easefor ani in self._anis:ani.setDuration(duration)ani.setEasingCurve(ease)def count(self):return len(self._items)def itemAt(self, index: int):if 0 <= index < len(self._items):return self._items[index]return Nonedef takeAt(self, index: int):if 0 <= index < len(self._items):item = self._items[index]  # type: QLayoutItemani = item.widget().property('flowAni')if ani:self._anis.remove(ani)self._aniGroup.removeAnimation(ani)ani.deleteLater()return self._items.pop(index).widget()return Nonedef removeWidget(self, widget):for i, item in enumerate(self._items):if item.widget() is widget:return self.takeAt(i)def removeAllWidgets(self):""" remove all widgets from layout """while self._items:self.takeAt(0)def takeAllWidgets(self):""" remove all widgets from layout and delete them """while self._items:w = self.takeAt(0)if w:w.deleteLater()def expandingDirections(self):return Qt.Orientation(0)def hasHeightForWidth(self):return Truedef heightForWidth(self, width: int):""" get the minimal height according to width """return self._doLayout(QRect(0, 0, width, 0), False)def setGeometry(self, rect: QRect):super().setGeometry(rect)if self.needAni:self._deBounceTimer.start(80)else:self._doLayout(rect, True)def sizeHint(self):return self.minimumSize()def minimumSize(self):size = QSize()for item in self._items:size = size.expandedTo(item.minimumSize())m = self.contentsMargins()size += QSize(m.left() + m.right(), m.top() + m.bottom())return sizedef setVerticalSpacing(self, spacing: int):""" set vertical spacing between widgets """self._verticalSpacing = spacingdef verticalSpacing(self):""" get vertical spacing between widgets """return self._verticalSpacingdef setHorizontalSpacing(self, spacing: int):""" set horizontal spacing between widgets """self._horizontalSpacing = spacingdef horizontalSpacing(self):""" get horizontal spacing between widgets """return self._horizontalSpacingdef eventFilter(self, obj: QObject, event: QEvent) -> bool:if obj in [w.widget() for w in self._items] and event.type() == QEvent.Type.ParentChange:self._wParent = obj.parent()obj.parent().installEventFilter(self)self._isInstalledEventFilter = Trueif obj == self._wParent and event.type() == QEvent.Type.Show:self._doLayout(self.geometry(), True)self._isInstalledEventFilter = Truereturn super().eventFilter(obj, event)def _doLayout(self, rect: QRect, move: bool):""" adjust widgets position according to the window size """aniRestart = Falsemargin = self.contentsMargins()x = rect.x() + margin.left()y = rect.y() + margin.top()rowHeight = 0spaceX = self.horizontalSpacing()spaceY = self.verticalSpacing()for i, item in enumerate(self._items):if item.widget() and not item.widget().isVisible() and self.isTight:continuenextX = x + item.sizeHint().width() + spaceXif nextX - spaceX > rect.right() - margin.right() and rowHeight > 0:x = rect.x() + margin.left()y = y + rowHeight + spaceYnextX = x + item.sizeHint().width() + spaceXrowHeight = 0if move:target = QRect(QPoint(x, y), item.sizeHint())if not self.needAni:item.setGeometry(target)elif target != self._anis[i].endValue():self._anis[i].stop()self._anis[i].setEndValue(target)aniRestart = Truex = nextXrowHeight = max(rowHeight, item.sizeHint().height())if self.needAni and aniRestart:self._aniGroup.stop()self._aniGroup.start()return y + rowHeight + margin.bottom() - rect.y()class WaterFallFlowLayout(FlowLayout):""" 瀑布流布局 """def _doLayout(self, rect: QRect, move: bool):""" 重写布局函数 """aniRestart = False# 获取item的宽度margin = self.contentsMargins()item_width = self._items[0].sizeHint().width()# 计算列数columnCount = math.floor(rect.width() / item_width)# 获取spacingspaceX = self.horizontalSpacing()spaceY = self.verticalSpacing()# 布局,根据布局调整左边宽度,默认是居中的,若靠左left=0,靠右2 * leftleft = (rect.width() - item_width * columnCount - spaceX * (columnCount - 1)) // 2hrr = []for index, item in enumerate(self._items):item_size = item.sizeHint()if index < columnCount:target = QRect(QPoint(left + index * (item_width + spaceX), spaceY), item_size)hrr.append(item_size.height() + spaceY)else:minHeight = min(hrr)i = hrr.index(minHeight)target = QRect(QPoint(left + i * (item_width + spaceX), minHeight + spaceY), item_size)hrr[i] += item_size.height() + spaceYif not self.needAni:item.setGeometry(target)elif target != self._anis[index].endValue():self._anis[index].stop()self._anis[index].setEndValue(target)aniRestart = Trueif self.needAni and aniRestart:self._aniGroup.stop()self._aniGroup.start()return max(hrr)class Window(QScrollArea):def __init__(self, parent=None):super().__init__(parent)self.widget = QWidget()self.waterfallLayout = WaterFallFlowLayout(self.widget)pngs = Path(r"G:\手机\壁纸\手机壁纸").glob("**/*.png")for i, file in enumerate(pngs):pixmap = QPixmap(str(file))if not pixmap.isNull():imageLabel = ImageLabel()imageLabel.setBorderRadius(8, 8, 8, 8)imageLabel.setPixmap(pixmap)imageLabel.scaledToWidth(300)self.waterfallLayout.addWidget(imageLabel)if i == 30:breakself.__initWidgets()def __initWidgets(self):self.widget.setAutoFillBackground(False)self.setWidget(self.widget)self.setWidgetResizable(True)if __name__ == '__main__':QApplication.setHighDpiScaleFactorRoundingPolicy(Qt.HighDpiScaleFactorRoundingPolicy.PassThrough)QApplication.setAttribute(Qt.AA_EnableHighDpiScaling)QApplication.setAttribute(Qt.AA_UseHighDpiPixmaps)app = QApplication(sys.argv)app.setQuitOnLastWindowClosed(True)demo = Window()demo.resize(800, 600)demo.show()sys.exit(app.exec_())

预览图

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/149363.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

erlang学习:Linux命令学习4

顺序控制语句学习 if&#xff0c;else对文件操作 判断一个文件夹是否存在&#xff0c;如果存在则进行删除&#xff0c;如果不存在则创建该文件夹&#xff0c;并复制一份该脚本后&#xff0c;删除该脚本 if [ -d "/erlangtest/testdir"]; then echo "删除文件夹…

JavaWeb--小白笔记07-2:超链接以及servlet对表单数据的完整处理

一.超链接 Html使用标签<a></a>来设置超链接&#xff0c;<a>有一个属性href"" 必须加进去&#xff0c;里面就是链接地址 注意&#xff1a;链接里必须包含https://前缀 <a></a>里面可以是一个字&#xff0c;一个词或者一副图...点击…

27 C 语言标准库 <stdio.h> 中的两个重要字符串函数:sprintf、sscanf

目录 1 sprintf 1.1 函数原型 1.2 功能说明 1.3 案例演示 1.4 注意事项 2 sscanf 2.1 函数原型 2.2 功能说明 2.3 案例演示 2.4 注意事项 1 sprintf 1.1 函数原型 sprintf 函数是 C 语言标准库中的一个函数&#xff0c;用于将格式化的数据写入字符串。其函数原型定义…

【软件测试】详解测试中常用的几种测试方法

目录 一、集成测试二、 系统测试三、验收测试四、回归测试 总结 一、集成测试 术语 集成测试是继组件测试之后的又一个层次。集成测试假定交给这个层次的测试对象已经经过了组件测试&#xff0c;并且任何组件内部的缺陷都已经尽可能地被纠正。 集成 开发人员、测试人员和专…

【裸机装机系列】14.kali(ubuntu)-linux装机在分区时采用manual手动形式该怎么做

推荐阅读&#xff1a; 1.kali(ubuntu)-为什么弃用ubuntu&#xff0c;而选择基于debian的kali操作系统 如果在装机的时候选则了manual手动模式&#xff0c;可以根据以下步骤一步步做: 1> 在“partition disks”这个地方选择了manual,也就是手动自己分区的方式 点击"c…

大模型框架 LangChain 介绍

文章目录 langchain介绍安装依赖大模型类别千帆大模型案例常见问题 langchain介绍 是一个开源大语言模型框架&#xff0c;本身不提供大模型算法&#xff0c;只提供对接大模型算法平台的接口&#xff08;模型包裹器&#xff09;&#xff1b;langchain官网v0.2&#xff0c;内部涉…

828华为云征文 | 云服务器Flexus X实例,Docker集成搭建斗地主

828华为云征文 | 云服务器Flexus X实例&#xff0c;Docker集成搭建斗地主 华为云端口放行 服务器放行对应端口8078 Docker安装并配置镜像加速 1、购买华为云 Flexus X 实例 Flexus云服务器X实例-华为云 (huaweicloud.com) 2、docker安装 yum install -y docker-ce3、验证 Dock…

问请问请问2312123213123

&#x1f4e2;博客主页&#xff1a;https://blog.csdn.net/2301_779549673 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01; &#x1f4e2;本文由 JohnKi 原创&#xff0c;首发于 CSDN&#x1f649; &#x1f4e2;未来很长&#…

后台管理系统开箱即用的组件库!!【送源码】

今天给大家推荐几款的后台管理系统开箱即用的组件库&#xff0c;基于ElementUI二次封装&#xff0c;开发必备 Headless UI Headless UI 是一款出色的前端组件库&#xff0c;专为与 Tailwind CSS 集成而设计。一组完全无样式、完全可访问的 UI 组件&#xff0c;可以自由的引入…

使用Docker和cpolar在Linux服务器上搭建DashDot监控面板

使用Docker和cpolar在Linux服务器上搭建DashDot监控面板 前言环境准备安装Docker下载Dashdot镜像 部署DashDot应用本地访问DashDot服务安装cpolar内网穿透固定DashDot公网地址结语 前言 在这个数字化飞速发展的时代&#xff0c;服务器作为支撑各种应用和服务的基础设施&#xf…

Unity进阶之C#知识补充

概述 Unity跨平台的基本原理 了解.Net相关知识 Unity跨平台的基本原理&#xff08;Mono&#xff09; Unity跨平台的基本原理&#xff08;IL2CPP&#xff09; IL2CPP 模式可能存在的问题处理 报错的话就去下载 用到的测试类 C#版本和Unity的关系 C#各版本新功能和语法 C# 1~4 功…

【模型】感知器

感知器是最早的人工神经网络之一&#xff0c;也是现代深度学习的基础之一。 1. 感知器&#xff08;Perceptron&#xff09; 1.1 定义与功能 感知器是一种线性二分类模型&#xff0c;旨在模拟生物神经元的基本功能。它通过对输入特征进行加权求和&#xff0c;并应用激活函数来…

chapter17-多线程基础——(自定义泛型)——day20

580-程序进程线程 581-并发并行 并发和并行也可以同时进行 582-继承Thread创建线程 583-多线程机制 主线程和子线程交替执行 单核&#xff1a;两个线程并发 多核&#xff1a;两个线程并行 主线程结束&#xff0c;不是说进程就结束&#xff0c;进程要等所有线程结束 584-为什…

如何破解西门子博途V19里的密码设置

现在使用TIA Portal V19的工程师是越来越多了&#xff0c;V19有个显著的变化就是访问密码的设置&#xff0c;很多小伙伴忽然发现已经用了很多年的功能&#xff0c;在改动以后都不会设置了&#xff0c;那我们今天就带着您看一下如何才能在 V19 中正确的设置 S7-1500 访问密码。 …

AI论文写作可靠吗?分享5款论文写作助手ai免费网站

AI论文写作的可靠性是一个备受关注的话题。在当前的技术背景下&#xff0c;AI写作工具能够显著提高论文写作的效率和质量&#xff0c;但其可靠性和安全性仍需谨慎评估。 AI论文写作的可靠性 技术能力与限制 AI论文写作的质量很大程度上取决于用户提供的输入指令或素材的质量…

小程序面板开发教程|开发照明 Matter 面板步骤(一)

一. 前置知识 前言 出于对 Matter 标准协议及第三方设备接入的可拓展性等方面考虑&#xff0c;照明 Matter 模型面板的功能点定义会与照明的 DP 模型有所不同&#xff0c;因此本文会着重介绍照明 Matter 面板的功能点定义及与 DP 模型的区别&#xff0c;以方便面板小程序开发…

thinkphp 做分布式服务+读写分离+分库分表+负载均衡(分区)(后续接着写)

thinkphp 做分布式服务读写分离分库分表负载均衡&#xff08;分区&#xff09; 引言 thinkphp* 大道至简负载均衡分布式服务一、读写分离1、读写分离的实现方式2、主从同步的三种模式2-1、异步模式&#xff08;mysql async-mode&#xff09;2-2、半同步模式&#xff08;mysql s…

STM32 map 文件浅析

目录 一、概述二、Section Cross References三、Removing Unused input sections from the image四、Memory Map of the image1、Local Symbols2、全局符号&#xff08;Global Symbols&#xff09; 五、Image Symbol Table六、Image component sizes 一、概述 .map 文件是编译…

力扣 中等 92.反转链表 II

文章目录 题目介绍题解 题目介绍 题解 class Solution {public ListNode reverseBetween(ListNode head, int left, int right) {// 创建一个哑节点&#xff0c;它的 next 指向头节点&#xff0c;方便处理ListNode dummy new ListNode(0, head);// p0 用于指向反转部分的前一个…

(无人车)/舵机电机/基本行进

一、CubeMx配置 &#xff08;1&#xff09;定时器配置 &#xff08;2&#xff09;电机GPIO端口配置 二、连线 &#xff08;1&#xff09;谁给谁供电 &#xff08;2&#xff09;单片机离开电脑供电&#xff0c;直接运行 三、特别注意 &#xff08;1&#xff09;电脑给单片机…