分享一个壁纸软件的设计思路
在QScrollArea
中添加一个总体的垂直布局,创建若干个水平布局,使用垂直布局组合,具体如图。在添加QAbstractButton
时设置button.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
属性,它会根据窗口大小自动调整。
WebImageLabel
参考https://blog.csdn.net/weixin_54217201/article/details/137932686
将class ImageLabel(QLabel)
换成class ImageLabel(QAbstractButton)
删除Clicked事件即可
代码如下
import math
import sys
from typing import List
from enum import Enum
from PyQt5.QtCore import pyqtSignal, QSize, Qt
from PyQt5.QtGui import QPixmap
from PyQt5.QtWidgets import (QAbstractButton, QWidget, QButtonGroup, QApplication, QGridLayout, QLayoutItem,
QSizePolicy, QHBoxLayout, QVBoxLayout, QScrollArea, QPushButton, QLabel)
from qfluentwidgets import SmoothScrollDelegate
from components import WebImageLabel, ReloadWidget
class LayoutPosition(Enum):
Left = 0
Center = 1
Right = 2
class PictureGridWidget(QScrollArea):
rowWidgetCount = 5
buttonClicked = pyqtSignal(QAbstractButton)
buttonPressed = pyqtSignal(QAbstractButton)
buttonReleased = pyqtSignal(QAbstractButton)
buttonToggled = pyqtSignal(QAbstractButton)
reloadClicked = pyqtSignal()
def __init__(self, parent=None):
super().__init__(parent)
self.delegate = SmoothScrollDelegate(self, False)
self._bigButtons = []
self._noDataWidget = None
self.view = QWidget()
self.buttonGroup = QButtonGroup(self.view)
self.verticalLayout = QVBoxLayout(self.view)
self.__initUi()
self.__initNoDataWidget()
def __initUi(self):
self.setWidget(self.view)
self.setWidgetResizable(True)
self.setContentsMargins(0, 0, 0, 0)
self.setObjectName("PictureGridWidget")
self.verticalLayout.setSpacing(5)
self.verticalLayout.setContentsMargins(0, 0, 10, 0)
self.verticalLayout.setAlignment(Qt.AlignTop)
self.buttonGroup.buttonClicked.connect(self.buttonClicked)
self.buttonGroup.buttonPressed.connect(self.buttonPressed)
self.buttonGroup.buttonReleased.connect(self.buttonReleased)
self.buttonGroup.buttonToggled.connect(self.buttonToggled)
def __resetRowLayout(self, buttons: list, position: LayoutPosition = LayoutPosition.Left):
"""
重置行布局
"""
horizontalLayout = QHBoxLayout()
verticalLayout_1 = QVBoxLayout()
verticalLayout_2 = QVBoxLayout()
horizontalLayout.setSpacing(5)
verticalLayout_1.setSpacing(5)
verticalLayout_2.setSpacing(5)
horizontalLayout.setContentsMargins(0, 0, 0, 0)
verticalLayout_1.setContentsMargins(0, 0, 0, 0)
verticalLayout_2.setContentsMargins(0, 0, 0, 0)
button1 = buttons[0] # type: QAbstractButton
button1.setMinimumHeight(300)
self._bigButtons.append(button1)
for button in buttons[1:3]:
verticalLayout_1.addWidget(button)
for button in buttons[3:5]:
verticalLayout_2.addWidget(button)
if position == LayoutPosition.Left:
horizontalLayout.addWidget(button1)
horizontalLayout.addLayout(verticalLayout_1)
horizontalLayout.addLayout(verticalLayout_2)
horizontalLayout.setStretch(0, 2)
horizontalLayout.setStretch(1, 1)
horizontalLayout.setStretch(2, 1)
elif position == LayoutPosition.Center:
horizontalLayout.addLayout(verticalLayout_1)
horizontalLayout.addWidget(button1)
horizontalLayout.addLayout(verticalLayout_2)
horizontalLayout.setStretch(0, 1)
horizontalLayout.setStretch(1, 2)
horizontalLayout.setStretch(2, 1)
elif position == LayoutPosition.Right:
horizontalLayout.addLayout(verticalLayout_1)
horizontalLayout.addLayout(verticalLayout_2)
horizontalLayout.addWidget(button1)
horizontalLayout.setStretch(0, 1)
horizontalLayout.setStretch(1, 1)
horizontalLayout.setStretch(2, 2)
return horizontalLayout
def __resetLayout(self, buttons: list):
sum_buttons = len(buttons)
poses = [i for i in LayoutPosition] * math.ceil(sum_buttons / self.rowWidgetCount)
for index, value in enumerate(range(0, sum_buttons, self.rowWidgetCount)):
self.verticalLayout.addLayout(
self.__resetRowLayout(buttons[value:value + self.rowWidgetCount], poses[index]))
def __resetBigButtons(self, width: int):
"""
重置大按钮
"""
for button in self._bigButtons: # type: WebImageLabel
button.scaledToWidth(width // 2)
def __initNoDataWidget(self):
if self.count() == 0:
_noDataWidget = ReloadWidget()
_noDataWidget.reloadClicked.connect(self.reloadClicked)
self.verticalLayout.addWidget(_noDataWidget, 0, Qt.AlignVCenter | Qt.AlignHCenter)
self._noDataWidget = _noDataWidget
else:
if self._noDataWidget:
self._noDataWidget.deleteLater()
self.verticalLayout.removeWidget(self._noDataWidget)
def setNoDataWidget(self, widget: QWidget):
self._noDataWidget = widget
self.update()
def noDataWidget(self):
return self._noDataWidget
def addButtons(self, buttons: List[QAbstractButton]):
for button in buttons:
button.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
self.buttonGroup.addButton(button)
self.__resetLayout(buttons)
self.__resetBigButtons(self.width())
self.__initNoDataWidget()
def buttons(self):
return self.buttonGroup.buttons()
def takeAt(self, index: int) -> QLayoutItem:
item = self.verticalLayout.takeAt(index)
if isinstance(item, QHBoxLayout):
item.deleteLater()
return item
def count(self):
return self.verticalLayout.count()
def removeAllWidgets(self):
while self.count():
self.takeAt(0)
for button in self.buttons():
self.buttonGroup.removeButton(button)
button.deleteLater()
self.__initNoDataWidget()
def resizeEvent(self, a0):
self.__resetBigButtons(a0.size().width())
super().resizeEvent(a0)
def checkedButton(self):
return self.buttonGroup.checkedButton()
def checkedId(self):
return self.buttonGroup.checkedId()
if __name__ == '__main__':
QApplication.setHighDpiScaleFactorRoundingPolicy(
Qt.HighDpiScaleFactorRoundingPolicy.PassThrough)
QApplication.setAttribute(Qt.AA_EnableHighDpiScaling)
QApplication.setAttribute(Qt.AA_UseHighDpiPixmaps)
app = QApplication(sys.argv)
demo = PictureGridWidget()
demo.setMinimumSize(900, 600)
imgList = [
r"G:\手机\壁纸\电脑壁纸\79f6134e92bb51d4f1602bb0503898fc.png",
r"G:\手机\壁纸\电脑壁纸\2b1ccbd66541d46c880560476210e35f.png",
r"G:\手机\壁纸\电脑壁纸\aa7d1b13c29fee7477f3c3f78d6478be.png",
r"G:\手机\壁纸\电脑壁纸\64bbc8d0138d99f4512719146b72d14f.jpeg",
r"G:\手机\壁纸\电脑壁纸\9eb771c6486a4a5d2442b0f997084d55.png"
]
labelList = []
for img in imgList:
i = WebImageLabel()
i.setPixmap(QPixmap(img))
labelList.append(i)
demo.addButtons(labelList)
bu = QPushButton(demo)
demo.buttonClicked.connect(print)
bu.clicked.connect(lambda: demo.removeAllWidgets())
demo.show()
sys.exit(app.exec_())