提交 5b22cfac 编写于 作者: 之一Yo's avatar 之一Yo

添加 `FlipView`

上级 5bd80c9d
# coding:utf-8
import sys
from pathlib import Path
from PyQt5.QtCore import QModelIndex, Qt, QRect, QSize
from PyQt5.QtGui import QIcon, QPainter, QFont, QColor
from PyQt5.QtWidgets import QApplication, QStyleOptionViewItem, QWidget, QHBoxLayout, QVBoxLayout
from qfluentwidgets import (FlipImageDelegate, setTheme, Theme, HorizontalPipsPager, HorizontalFlipView,
VerticalFlipView, getFont)
class CustomFlipItemDelegate(FlipImageDelegate):
""" Custom flip item delegate """
def paint(self, painter: QPainter, option: QStyleOptionViewItem, index: QModelIndex):
super().paint(painter, option, index)
painter.save()
# draw mask
painter.setBrush(QColor(255, 255, 255, 200))
painter.setPen(Qt.NoPen)
rect = option.rect
rect = QRect(rect.x(), rect.y(), 200, rect.height())
painter.drawRect(rect)
# draw text
painter.setPen(Qt.black)
painter.setFont(getFont(16, QFont.Bold))
painter.drawText(rect, Qt.AlignCenter, '🥰\n硝子酱一级棒卡哇伊')
painter.restore()
class Demo(QWidget):
def __init__(self):
super().__init__()
# setTheme(Theme.DARK)
# self.setStyleSheet('Demo{background:rgb(32,32,32)}')
self.flipView = HorizontalFlipView(self)
self.pager = HorizontalPipsPager(self)
# adjust view size
# self.flipView.setItemSize(QSize(320, 180))
# self.flipView.setFixedSize(QSize(320, 180))
# NOTE: use custom delegate
# self.flipView.setItemDelegate(CustomFlipItemDelegate(self.flipView))
# add images
self.flipView.addImages([str(i) for i in Path('./resource').glob('*')])
self.pager.setPageNumber(self.flipView.count())
self.pager.currentIndexChanged.connect(self.flipView.setCurrentIndex)
self.flipView.currentIndexChanged.connect(self.pager.setCurrentIndex)
# self.flipView.setCurrentIndex(2)
self.setLayout(QVBoxLayout(self))
self.layout().addWidget(self.flipView, 0, Qt.AlignCenter)
self.layout().addWidget(self.pager, 0, Qt.AlignCenter)
self.layout().setAlignment(Qt.AlignCenter)
self.layout().setSpacing(20)
self.resize(600, 600)
if __name__ == '__main__':
# enable dpi scale
QApplication.setHighDpiScaleFactorRoundingPolicy(Qt.HighDpiScaleFactorRoundingPolicy.PassThrough)
QApplication.setAttribute(Qt.AA_EnableHighDpiScaling)
QApplication.setAttribute(Qt.AA_UseHighDpiPixmaps)
app = QApplication(sys.argv)
w = Demo()
w.show()
app.exec_()
\ No newline at end of file
......@@ -512,182 +512,182 @@ In that case, I would accept it no matter which side the ball falls on.</source>
<context>
<name>ListFrame</name>
<message>
<location filename="../../view/view_interface.py" line="76"/>
<location filename="../../view/view_interface.py" line="90"/>
<source>Star Platinum</source>
<translation>白金之星</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="76"/>
<location filename="../../view/view_interface.py" line="90"/>
<source>Hierophant Green</source>
<translation>法皇之绿</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="77"/>
<location filename="../../view/view_interface.py" line="91"/>
<source>Made in Haven</source>
<translation>天堂制造</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="77"/>
<location filename="../../view/view_interface.py" line="91"/>
<source>King Crimson</source>
<translation>绯红之王</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="78"/>
<location filename="../../view/view_interface.py" line="92"/>
<source>Silver Chariot</source>
<translation>银色战车</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="78"/>
<location filename="../../view/view_interface.py" line="92"/>
<source>Crazy diamond</source>
<translation>疯狂钻石</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="79"/>
<location filename="../../view/view_interface.py" line="93"/>
<source>Metallica</source>
<translation>金属制品</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="79"/>
<location filename="../../view/view_interface.py" line="93"/>
<source>Another One Bites The Dust</source>
<translation>败者食尘</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="80"/>
<location filename="../../view/view_interface.py" line="94"/>
<source>Heaven&apos;s Door</source>
<translation>黑蚊子多</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="81"/>
<location filename="../../view/view_interface.py" line="95"/>
<source>The Grateful Dead</source>
<translation>壮烈成仁</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="81"/>
<location filename="../../view/view_interface.py" line="95"/>
<source>Stone Free</source>
<translation>石之自由</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="82"/>
<location filename="../../view/view_interface.py" line="96"/>
<source>The World</source>
<translation>砸瓦鲁多</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="82"/>
<location filename="../../view/view_interface.py" line="96"/>
<source>Sticky Fingers</source>
<translation>钢链手指</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="83"/>
<location filename="../../view/view_interface.py" line="97"/>
<source>Ozone Baby</source>
<translation>臭氧宝宝</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="83"/>
<location filename="../../view/view_interface.py" line="97"/>
<source>Love Love Deluxe</source>
<translation>华丽挚爱</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="84"/>
<location filename="../../view/view_interface.py" line="98"/>
<source>Hermit Purple</source>
<translation>隐者之紫</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="84"/>
<location filename="../../view/view_interface.py" line="98"/>
<source>Gold Experience</source>
<translation>黄金体验</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="85"/>
<location filename="../../view/view_interface.py" line="99"/>
<source>King Nothing</source>
<translation>虚无之王</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="85"/>
<location filename="../../view/view_interface.py" line="99"/>
<source>Paper Moon King</source>
<translation>纸月之王</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="86"/>
<location filename="../../view/view_interface.py" line="100"/>
<source>Scary Monster</source>
<translation>骇人恶兽</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="86"/>
<location filename="../../view/view_interface.py" line="100"/>
<source>Mandom</source>
<translation>男子领域</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="87"/>
<location filename="../../view/view_interface.py" line="101"/>
<source>20th Century Boy</source>
<translation>20世纪男孩</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="87"/>
<location filename="../../view/view_interface.py" line="101"/>
<source>Tusk Act 4</source>
<translation> Act 4</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="88"/>
<location filename="../../view/view_interface.py" line="102"/>
<source>Ball Breaker</source>
<translation>铁球破坏者</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="88"/>
<location filename="../../view/view_interface.py" line="102"/>
<source>Sex Pistols</source>
<translation>性感手枪</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="89"/>
<location filename="../../view/view_interface.py" line="103"/>
<source>D4C Love Train</source>
<translation>D4C 爱之列车</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="89"/>
<location filename="../../view/view_interface.py" line="103"/>
<source>Born This Way</source>
<translation>天生完美</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="90"/>
<location filename="../../view/view_interface.py" line="104"/>
<source>SOFT &amp; WET</source>
<translation>软又湿</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="90"/>
<location filename="../../view/view_interface.py" line="104"/>
<source>Paisley Park</source>
<translation>佩斯利公园</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="91"/>
<location filename="../../view/view_interface.py" line="105"/>
<source>Wonder of U</source>
<translation>奇迹于你</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="91"/>
<location filename="../../view/view_interface.py" line="105"/>
<source>Walking Heart</source>
<translation>行走的心</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="92"/>
<location filename="../../view/view_interface.py" line="106"/>
<source>Cream Starter</source>
<translation>护霜旅行者</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="92"/>
<location filename="../../view/view_interface.py" line="106"/>
<source>November Rain</source>
<translation>十一月雨</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="93"/>
<location filename="../../view/view_interface.py" line="107"/>
<source>Smooth Operators</source>
<translation>调情圣手</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="93"/>
<location filename="../../view/view_interface.py" line="107"/>
<source>The Matte Kudasai</source>
<translation>片刻静候</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="80"/>
<location filename="../../view/view_interface.py" line="94"/>
<source>Killer Queen</source>
<translation>杀手皇后💀</translation>
</message>
......@@ -1475,27 +1475,27 @@ In that case, I would accept it no matter which side the ball falls on.</source>
<context>
<name>TableFrame</name>
<message>
<location filename="../../view/view_interface.py" line="149"/>
<location filename="../../view/view_interface.py" line="163"/>
<source>Title</source>
<translation>标题</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="149"/>
<location filename="../../view/view_interface.py" line="163"/>
<source>Artist</source>
<translation>歌手</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="149"/>
<location filename="../../view/view_interface.py" line="163"/>
<source>Album</source>
<translation>专辑</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="149"/>
<location filename="../../view/view_interface.py" line="163"/>
<source>Year</source>
<translation>年份</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="149"/>
<location filename="../../view/view_interface.py" line="163"/>
<source>Duration</source>
<translation>时长</translation>
</message>
......@@ -1647,32 +1647,32 @@ In that case, I would accept it no matter which side the ball falls on.</source>
<context>
<name>TreeFrame</name>
<message>
<location filename="../../view/view_interface.py" line="108"/>
<location filename="../../view/view_interface.py" line="122"/>
<source>JoJo 1 - Phantom Blood</source>
<translation>JoJo 1 - 幻影之血</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="109"/>
<location filename="../../view/view_interface.py" line="123"/>
<source>Jonathan Joestar</source>
<translation>乔纳森·乔斯达</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="109"/>
<location filename="../../view/view_interface.py" line="123"/>
<source>Dio Brando</source>
<translation>迪奥·布兰度</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="109"/>
<location filename="../../view/view_interface.py" line="123"/>
<source>Will A. Zeppeli</source>
<translation>威廉·A·齐贝林</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="116"/>
<location filename="../../view/view_interface.py" line="130"/>
<source>JoJo 3 - Stardust Crusaders</source>
<translation>JoJo3 - 星尘斗士</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="117"/>
<location filename="../../view/view_interface.py" line="131"/>
<source>Jotaro Kujo</source>
<translation></translation>
</message>
......@@ -1699,5 +1699,10 @@ In that case, I would accept it no matter which side the ball falls on.</source>
<source>A simple ListView</source>
<translation>简单的列表组件</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="61"/>
<source>Flip view</source>
<translation>翻转视图</translation>
</message>
</context>
</TS>
......@@ -512,182 +512,182 @@ In that case, I would accept it no matter which side the ball falls on.</source>
<context>
<name>ListFrame</name>
<message>
<location filename="../../view/view_interface.py" line="76"/>
<location filename="../../view/view_interface.py" line="90"/>
<source>Star Platinum</source>
<translation>白金之星</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="76"/>
<location filename="../../view/view_interface.py" line="90"/>
<source>Hierophant Green</source>
<translation>法皇之綠</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="77"/>
<location filename="../../view/view_interface.py" line="91"/>
<source>Made in Haven</source>
<translation>天堂製造</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="77"/>
<location filename="../../view/view_interface.py" line="91"/>
<source>King Crimson</source>
<translation>緋紅之王</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="78"/>
<location filename="../../view/view_interface.py" line="92"/>
<source>Silver Chariot</source>
<translation>銀色戰車</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="78"/>
<location filename="../../view/view_interface.py" line="92"/>
<source>Crazy diamond</source>
<translation>瘋狂鑽石</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="79"/>
<location filename="../../view/view_interface.py" line="93"/>
<source>Metallica</source>
<translation>金屬製品</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="79"/>
<location filename="../../view/view_interface.py" line="93"/>
<source>Another One Bites The Dust</source>
<translation>敗者食塵</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="80"/>
<location filename="../../view/view_interface.py" line="94"/>
<source>Heaven&apos;s Door</source>
<translation>黑蚊子多</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="81"/>
<location filename="../../view/view_interface.py" line="95"/>
<source>The Grateful Dead</source>
<translation>壯烈成仁</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="81"/>
<location filename="../../view/view_interface.py" line="95"/>
<source>Stone Free</source>
<translation>石之自由</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="82"/>
<location filename="../../view/view_interface.py" line="96"/>
<source>The World</source>
<translation>砸瓦魯多</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="82"/>
<location filename="../../view/view_interface.py" line="96"/>
<source>Sticky Fingers</source>
<translation>鋼鏈手指</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="83"/>
<location filename="../../view/view_interface.py" line="97"/>
<source>Ozone Baby</source>
<translation>臭氧寶寶</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="83"/>
<location filename="../../view/view_interface.py" line="97"/>
<source>Love Love Deluxe</source>
<translation>華麗摯愛</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="84"/>
<location filename="../../view/view_interface.py" line="98"/>
<source>Hermit Purple</source>
<translation>隱者之紫</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="84"/>
<location filename="../../view/view_interface.py" line="98"/>
<source>Gold Experience</source>
<translation>黃金體驗</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="85"/>
<location filename="../../view/view_interface.py" line="99"/>
<source>King Nothing</source>
<translation>虛無之王</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="85"/>
<location filename="../../view/view_interface.py" line="99"/>
<source>Paper Moon King</source>
<translation>紙月之王</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="86"/>
<location filename="../../view/view_interface.py" line="100"/>
<source>Scary Monster</source>
<translation>駭人噁獸</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="86"/>
<location filename="../../view/view_interface.py" line="100"/>
<source>Mandom</source>
<translation>男子領域</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="87"/>
<location filename="../../view/view_interface.py" line="101"/>
<source>20th Century Boy</source>
<translation>20世紀男孩</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="87"/>
<location filename="../../view/view_interface.py" line="101"/>
<source>Tusk Act 4</source>
<translation> Act 4</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="88"/>
<location filename="../../view/view_interface.py" line="102"/>
<source>Ball Breaker</source>
<translation>鐵球破壞者</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="88"/>
<location filename="../../view/view_interface.py" line="102"/>
<source>Sex Pistols</source>
<translation>性感手槍</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="89"/>
<location filename="../../view/view_interface.py" line="103"/>
<source>D4C Love Train</source>
<translation>D4C 愛之列車</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="89"/>
<location filename="../../view/view_interface.py" line="103"/>
<source>Born This Way</source>
<translation>天生完美</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="90"/>
<location filename="../../view/view_interface.py" line="104"/>
<source>SOFT &amp; WET</source>
<translation>軟又溼</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="90"/>
<location filename="../../view/view_interface.py" line="104"/>
<source>Paisley Park</source>
<translation>佩斯利公園</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="91"/>
<location filename="../../view/view_interface.py" line="105"/>
<source>Wonder of U</source>
<translation>奇跡於你</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="91"/>
<location filename="../../view/view_interface.py" line="105"/>
<source>Walking Heart</source>
<translation>行走的心</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="92"/>
<location filename="../../view/view_interface.py" line="106"/>
<source>Cream Starter</source>
<translation>護霜旅行者</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="92"/>
<location filename="../../view/view_interface.py" line="106"/>
<source>November Rain</source>
<translation>十一月雨</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="93"/>
<location filename="../../view/view_interface.py" line="107"/>
<source>Smooth Operators</source>
<translation>調情聖手</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="93"/>
<location filename="../../view/view_interface.py" line="107"/>
<source>The Matte Kudasai</source>
<translation>片刻靜候</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="80"/>
<location filename="../../view/view_interface.py" line="94"/>
<source>Killer Queen</source>
<translation>殺手皇後💀</translation>
</message>
......@@ -1475,27 +1475,27 @@ In that case, I would accept it no matter which side the ball falls on.</source>
<context>
<name>TableFrame</name>
<message>
<location filename="../../view/view_interface.py" line="149"/>
<location filename="../../view/view_interface.py" line="163"/>
<source>Title</source>
<translation>標題</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="149"/>
<location filename="../../view/view_interface.py" line="163"/>
<source>Artist</source>
<translation>歌手</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="149"/>
<location filename="../../view/view_interface.py" line="163"/>
<source>Album</source>
<translation>專輯</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="149"/>
<location filename="../../view/view_interface.py" line="163"/>
<source>Year</source>
<translation>年份</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="149"/>
<location filename="../../view/view_interface.py" line="163"/>
<source>Duration</source>
<translation>時長</translation>
</message>
......@@ -1647,32 +1647,32 @@ In that case, I would accept it no matter which side the ball falls on.</source>
<context>
<name>TreeFrame</name>
<message>
<location filename="../../view/view_interface.py" line="108"/>
<location filename="../../view/view_interface.py" line="122"/>
<source>JoJo 1 - Phantom Blood</source>
<translation>JoJo 1 - 幻影之血</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="109"/>
<location filename="../../view/view_interface.py" line="123"/>
<source>Jonathan Joestar</source>
<translation>喬納森·喬斯達</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="109"/>
<location filename="../../view/view_interface.py" line="123"/>
<source>Dio Brando</source>
<translation>迪奧·佈蘭度</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="109"/>
<location filename="../../view/view_interface.py" line="123"/>
<source>Will A. Zeppeli</source>
<translation>威廉·A·齊貝林</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="116"/>
<location filename="../../view/view_interface.py" line="130"/>
<source>JoJo 3 - Stardust Crusaders</source>
<translation>JoJo3 - 星塵鬥士</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="117"/>
<location filename="../../view/view_interface.py" line="131"/>
<source>Jotaro Kujo</source>
<translation></translation>
</message>
......@@ -1699,5 +1699,10 @@ In that case, I would accept it no matter which side the ball falls on.</source>
<source>A simple ListView</source>
<translation>簡單的列表組件</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="61"/>
<source>Flip view</source>
<translation>翻轉視圖</translation>
</message>
</context>
</TS>
......@@ -122,6 +122,10 @@
<file>images/Singer.png</file>
<file>images/MusicNote.png</file>
<file>images/Smiling_with_heart.png</file>
<file>images/Shoko1.jpg</file>
<file>images/Shoko2.jpg</file>
<file>images/Shoko3.jpg</file>
<file>images/Shoko4.jpg</file>
<file>qss/dark/gallery_interface.qss</file>
<file>qss/dark/home_interface.qss</file>
......
......@@ -349,6 +349,14 @@ class HomeInterface(ScrollArea):
routeKey="scrollInterface",
index=0
)
scrollView.addSampleCard(
icon=":/gallery/images/controls/PipsPager.png",
title="PipsPager",
content=self.tr(
"A control to let the user navigate through a paginated collection when the page numbers do not need to be visually known."),
routeKey="scrollInterface",
index=3
)
self.vBoxLayout.addWidget(scrollView)
# state info samples
......@@ -456,4 +464,12 @@ class HomeInterface(ScrollArea):
routeKey="viewInterface",
index=2
)
collectionView.addSampleCard(
icon=":/gallery/images/controls/FlipView.png",
title="FlipView",
content=self.tr(
"Presents a collection of items that the user can flip through,one item at a time."),
routeKey="viewInterface",
index=4
)
self.vBoxLayout.addWidget(collectionView)
......@@ -2,7 +2,7 @@
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import (QListWidgetItem, QFrame, QTreeWidgetItem, QHBoxLayout,
QTreeWidgetItemIterator, QTableWidgetItem)
from qfluentwidgets import TreeWidget, TableWidget, ListWidget
from qfluentwidgets import TreeWidget, TableWidget, ListWidget, HorizontalFlipView
from .gallery_interface import GalleryInterface
from ..common.translator import Translator
......@@ -50,6 +50,20 @@ class ViewInterface(GalleryInterface):
sourcePath='https://github.com/zhiyiYo/PyQt-Fluent-Widgets/blob/master/examples/tree_view/demo.py'
)
# flip view
w = HorizontalFlipView(self)
w.addImages([
":/gallery/images/Shoko1.jpg",
":/gallery/images/Shoko2.jpg",
":/gallery/images/Shoko3.jpg",
":/gallery/images/Shoko4.jpg",
])
self.addExampleCard(
title=self.tr('Flip view'),
widget=w,
sourcePath='https://github.com/zhiyiYo/PyQt-Fluent-Widgets/blob/master/examples/flip_view/demo.py'
)
class Frame(QFrame):
......
# coding: utf-8
from PyQt5.QtCore import Qt
from PyQt5.QtCore import Qt, QSize
from PyQt5.QtDesigner import QPyDesignerCustomWidgetPlugin
from qfluentwidgets import ListWidget, ListView, TreeView, TreeWidget, TableView, TableWidget
from qfluentwidgets import (ListWidget, ListView, TreeView, TreeWidget, TableView, TableWidget,
HorizontalFlipView, VerticalFlipView, HorizontalPipsPager, VerticalPipsPager)
from plugin_base import PluginBase
......@@ -89,3 +90,71 @@ class TreeViewPlugin(ViewPlugin, QPyDesignerCustomWidgetPlugin):
def name(self):
return "TreeView"
class HorizontalFlipViewPlugin(ViewPlugin, QPyDesignerCustomWidgetPlugin):
""" Horizontal flip view plugin """
def createWidget(self, parent):
w = HorizontalFlipView(parent)
w.addImages([
":/qfluentwidgets/images/controls/FlipView.png",
":/qfluentwidgets/images/controls/CommandBar.png",
":/qfluentwidgets/images/controls/Button.png",
])
return w
def icon(self):
return super().icon("FlipView")
def name(self):
return "HorizontalFlipView"
class VerticalFlipViewPlugin(ViewPlugin, QPyDesignerCustomWidgetPlugin):
""" Vertical flip view plugin """
def createWidget(self, parent):
w = VerticalFlipView(parent)
w.addImages([
":/qfluentwidgets/images/controls/FlipView.png",
":/qfluentwidgets/images/controls/CommandBar.png",
":/qfluentwidgets/images/controls/Button.png",
])
return w
def icon(self):
return super().icon("FlipView")
def name(self):
return "VerticalFlipView"
class HorizontalPipsPagerPlugin(ViewPlugin, QPyDesignerCustomWidgetPlugin):
""" Horizontal flip view plugin """
def createWidget(self, parent):
w = HorizontalPipsPager(parent)
w.setPageNumber(5)
return w
def icon(self):
return super().icon("PipsPager")
def name(self):
return "HorizontalPipsPager"
class VerticalPipsPagerPlugin(ViewPlugin, QPyDesignerCustomWidgetPlugin):
""" Vertical flip view plugin """
def createWidget(self, parent):
w = VerticalPipsPager(parent)
w.setPageNumber(5)
return w
def icon(self):
return super().icon("PipsPager")
def name(self):
return "VerticalPipsPager"
FlipView {
background-color: transparent;
border: none;
}
\ No newline at end of file
FlipView {
background-color: transparent;
border: none;
}
\ No newline at end of file
此差异已折叠。
......@@ -393,6 +393,7 @@
<file>qss/dark/info_badge.qss</file>
<file>qss/dark/tab_view.qss</file>
<file>qss/dark/pips_pager.qss</file>
<file>qss/dark/flip_view.qss</file>
<file>qss/light/color_dialog.qss</file>
<file>qss/light/dialog.qss</file>
......@@ -424,6 +425,7 @@
<file>qss/light/info_badge.qss</file>
<file>qss/light/tab_view.qss</file>
<file>qss/light/pips_pager.qss</file>
<file>qss/light/flip_view.qss</file>
<file>i18n/qfluentwidgets.zh_CN.qm</file>
<file>i18n/qfluentwidgets.zh_HK.qm</file>
......
......@@ -97,6 +97,7 @@ class FluentStyleSheet(StyleSheetBase, Enum):
TOOL_TIP = "tool_tip"
CHECK_BOX = "check_box"
COMBO_BOX = "combo_box"
FLIP_VIEW = "flip_view"
LINE_EDIT = "line_edit"
LIST_VIEW = "list_view"
TREE_VIEW = "tree_view"
......
......@@ -9,6 +9,7 @@ from .card_widget import CardWidget, ElevatedCardWidget
from .check_box import CheckBox
from .combo_box import ComboBox, EditableComboBox
from .command_bar import CommandBar, CommandButton, CommandBarView
from .flip_view import FlipView, HorizontalFlipView, VerticalFlipView, FlipImageDelegate
from .line_edit import LineEdit, TextEdit, PlainTextEdit, LineEditButton, SearchLineEdit
from .icon_widget import IconWidget
from .label import (PixmapLabel, CaptionLabel, StrongBodyLabel, BodyLabel, SubtitleLabel, TitleLabel,
......
# coding:utf-8
from typing import List, Union
from PyQt5.QtCore import Qt, pyqtSignal, QModelIndex, QSize, pyqtProperty, QRectF, QPropertyAnimation
from PyQt5.QtGui import QPixmap, QPainter, QColor, QImage, QWheelEvent
from PyQt5.QtWidgets import QStyleOptionViewItem, QWidget, QListWidget, QStyledItemDelegate, QListWidgetItem
from ...common.overload import singledispatchmethod
from ...common.style_sheet import isDarkTheme, FluentStyleSheet
from ...common.icon import drawIcon, FluentIcon
from .scroll_bar import SmoothScrollBar
from .button import ToolButton
class ScrollButton(ToolButton):
""" Scroll button """
def _postInit(self):
self._opacity = 0
self.opacityAni = QPropertyAnimation(self, b'opacity', self)
self.opacityAni.setDuration(150)
@pyqtProperty(float)
def opacity(self):
return self._opacity
@opacity.setter
def opacity(self, o: float):
self._opacity = o
self.update()
def isTransparent(self):
return self.opacity == 0
def fadeIn(self):
self.opacityAni.setStartValue(self.opacity)
self.opacityAni.setEndValue(1)
self.opacityAni.start()
def fadeOut(self):
self.opacityAni.setStartValue(self.opacity)
self.opacityAni.setEndValue(0)
self.opacityAni.start()
def paintEvent(self, e):
painter = QPainter(self)
painter.setRenderHints(QPainter.Antialiasing)
painter.setPen(Qt.NoPen)
painter.setOpacity(self.opacity)
# draw background
if not isDarkTheme():
painter.setBrush(QColor(252, 252, 252, 217))
else:
painter.setBrush(QColor(44, 44, 44, 245))
painter.drawRoundedRect(self.rect(), 4, 4)
# draw icon
if isDarkTheme():
color = QColor(255, 255, 255)
opacity = 0.773 if self.isHover or self.isPressed else 0.541
else:
color = QColor(0, 0, 0)
opacity = 0.616 if self.isHover or self.isPressed else 0.45
painter.setOpacity(self.opacity * opacity)
s = 6 if self.isPressed else 8
w, h = self.width(), self.height()
x, y = (w - s) / 2, (h - s) / 2
drawIcon(self._icon, painter, QRectF(x, y, s, s), fill=color.name())
class FlipImageDelegate(QStyledItemDelegate):
""" Flip view image delegate """
def __init__(self, parent=None):
super().__init__(parent)
def itemSize(self):
return self.parent().itemSize
def paint(self, painter: QPainter, option: QStyleOptionViewItem, index: QModelIndex):
painter.save()
painter.setRenderHints(QPainter.Antialiasing)
painter.setPen(Qt.NoPen)
size = self.itemSize() # type: QSize
# draw image
r = self.parent().devicePixelRatioF()
image = index.data(Qt.UserRole) # type: QImage
image = image.scaled(size* r, Qt.KeepAspectRatio, Qt.SmoothTransformation)
x = option.rect.x() + int((option.rect.width() - size.width()) / 2)
y = option.rect.y() + int((option.rect.height() - size.height()) / 2)
painter.drawImage(QRectF(x, y, size.width(), size.height()), image)
painter.restore()
class FlipView(QListWidget):
""" Flip view """
currentIndexChanged = pyqtSignal(int)
@singledispatchmethod
def __init__(self, parent=None):
super().__init__(parent=parent)
self.orientation = Qt.Horizontal
self._postInit()
@__init__.register
def _(self, orientation: Qt.Orientation, parent=None):
super().__init__(parent=parent)
self.orientation = orientation
self._postInit()
def _postInit(self):
self.isHover = False
self._currentIndex = -1
self._itemSize = QSize(480, 270) # 16:9
self.delegate = FlipImageDelegate(self)
self.scrollBar = SmoothScrollBar(self.orientation, self)
self.scrollBar.setScrollAnimation(500)
self.scrollBar.setForceHidden(True)
self.setUniformItemSizes(True)
self.setGridSize(self.itemSize)
self.setFixedSize(self.itemSize)
self.setItemDelegate(self.delegate)
self.setMovement(QListWidget.Static)
self.setVerticalScrollMode(self.ScrollPerPixel)
self.setHorizontalScrollMode(self.ScrollPerPixel)
self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
FluentStyleSheet.FLIP_VIEW.apply(self)
if self.isHorizontal():
self.setFlow(QListWidget.LeftToRight)
self.preButton = ScrollButton(FluentIcon.CARE_LEFT_SOLID, self)
self.nextButton = ScrollButton(FluentIcon.CARE_RIGHT_SOLID, self)
self.preButton.setFixedSize(16, 38)
self.nextButton.setFixedSize(16, 38)
else:
self.preButton = ScrollButton(FluentIcon.CARE_UP_SOLID, self)
self.nextButton = ScrollButton(FluentIcon.CARE_DOWN_SOLID, self)
self.preButton.setFixedSize(38, 16)
self.nextButton.setFixedSize(38, 16)
# connect signal to slot
self.preButton.clicked.connect(self.scrollPrevious)
self.nextButton.clicked.connect(self.scrollNext)
def isHorizontal(self):
return self.orientation == Qt.Horizontal
def setItemSize(self, size: QSize):
""" set the size of item """
if size == self.itemSize:
return
self._itemSize = size
self.setGridSize(size)
for i in range(self.count()):
item = self.item(i)
item.setSizeHint(size)
self.viewport().update()
def getItemSize(self):
""" get the size of item """
return self._itemSize
def scrollPrevious(self):
""" scroll to previous item """
self.setCurrentIndex(self.currentIndex() - 1)
def scrollNext(self):
""" scroll to next item """
self.setCurrentIndex(self.currentIndex() + 1)
def setCurrentIndex(self, index: int):
""" set current index """
if not 0 <= index < self.count() or index == self.currentIndex():
return
self.scrollToIndex(index)
# update the visibility of scroll button
if index == 0:
self.preButton.fadeOut()
elif self.preButton.isTransparent() and self.isHover:
self.preButton.fadeIn()
if index == self.count() - 1:
self.nextButton.fadeOut()
elif self.nextButton.isTransparent() and self.isHover:
self.nextButton.fadeIn()
# fire signal
self.currentIndexChanged.emit(index)
def scrollToIndex(self, index):
if not 0 <= index < self.count():
return
self._currentIndex = index
if self.isHorizontal():
value = self.itemSize.width() * index
else:
value = self.itemSize.height() * index
self.scrollBar.scrollTo(value)
def currentIndex(self):
return self._currentIndex
def image(self, index: int):
if not 0 <= index < self.count():
return QImage()
return self.item(index).data(Qt.UserRole)
def addImage(self, image: Union[QImage, QPixmap, str]):
""" add image """
self.addImages([image])
def addImages(self, images: List[Union[QImage, QPixmap, str]]):
""" add images """
if not images:
return
N = self.count()
self.addItems([''] * len(images))
for i in range(N, self.count()):
image = images[i - N]
# convert image to QImage
if isinstance(image, str):
image = QImage(image)
elif isinstance(image, QPixmap):
image = image.toImage()
item = self.item(i)
item.setData(Qt.UserRole, image)
item.setSizeHint(self.itemSize)
if self.currentIndex() < 0:
self._currentIndex = 0
def resizeEvent(self, e):
w, h = self.width(), self.height()
bw, bh = self.preButton.width(), self.preButton.height()
if self.isHorizontal():
self.preButton.move(2, int(h / 2 - bh / 2))
self.nextButton.move(w - bw - 2, int(h / 2 - bh / 2))
else:
self.preButton.move(int(w / 2 - bw / 2), 2)
self.nextButton.move(int(w / 2 - bw / 2), h - bh - 2)
def enterEvent(self, e):
super().enterEvent(e)
self.isHover = True
self.preButton.fadeIn()
self.nextButton.fadeIn()
def leaveEvent(self, e):
super().leaveEvent(e)
self.isHover = False
self.preButton.fadeOut()
self.nextButton.fadeOut()
def showEvent(self, e):
self.scrollBar.duration = 0
self.scrollToIndex(self.currentIndex())
self.scrollBar.duration = 500
def wheelEvent(self, e: QWheelEvent):
if self.scrollBar.ani.state() == QPropertyAnimation.Running:
return
if e.angleDelta().y() < 0:
self.scrollNext()
else:
self.scrollPrevious()
itemSize = pyqtProperty(QSize, getItemSize, setItemSize)
class HorizontalFlipView(FlipView):
""" Horizontal flip view """
def __init__(self, parent=None):
super().__init__(Qt.Horizontal, parent)
class VerticalFlipView(FlipView):
""" Vertical flip view """
def __init__(self, parent=None):
super().__init__(Qt.Vertical, parent)
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册