提交 93700c4f 编写于 作者: 之一Yo's avatar 之一Yo

添加表格组件、下拉按钮和状态开关按钮, #145

上级 04539104
...@@ -2,8 +2,9 @@ ...@@ -2,8 +2,9 @@
import sys import sys
from PyQt5.QtCore import Qt, QSize from PyQt5.QtCore import Qt, QSize
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QAction
from qfluentwidgets import PushButton, PrimaryPushButton, HyperlinkButton, setTheme, Theme, ToolButton from qfluentwidgets import (DropDownPushButton, DropDownToolButton, PushButton, PrimaryPushButton,
HyperlinkButton, setTheme, Theme, ToolButton, ToggleButton, RoundMenu)
from qfluentwidgets import FluentIcon as FIF from qfluentwidgets import FluentIcon as FIF
...@@ -25,6 +26,16 @@ class Demo(QWidget): ...@@ -25,6 +26,16 @@ class Demo(QWidget):
self.primaryButton1 = PrimaryPushButton('Accent style button', self) self.primaryButton1 = PrimaryPushButton('Accent style button', self)
self.primaryButton2 = PrimaryPushButton('Accent style button with icon', self, FIF.UPDATE) self.primaryButton2 = PrimaryPushButton('Accent style button with icon', self, FIF.UPDATE)
self.toggleButton = ToggleButton('Toggle Button', self, FIF.SEND)
self.dropDownPushButton = DropDownPushButton('Email', self, FIF.MAIL)
self.dropDownToolButton = DropDownToolButton(FIF.MAIL, self)
self.menu = RoundMenu(parent=self)
self.menu.addAction(QAction(FIF.SEND_FILL.icon(), 'Send'))
self.menu.addAction(QAction(FIF.SAVE.icon(), 'Save'))
self.dropDownPushButton.setMenu(self.menu)
self.dropDownToolButton.setMenu(self.menu)
self.hyperlinkButton = HyperlinkButton( self.hyperlinkButton = HyperlinkButton(
url='https://github.com/zhiyiYo/PyQt-Fluent-Widgets', url='https://github.com/zhiyiYo/PyQt-Fluent-Widgets',
text='Hyper link button', text='Hyper link button',
...@@ -37,10 +48,13 @@ class Demo(QWidget): ...@@ -37,10 +48,13 @@ class Demo(QWidget):
self.vBoxLayout.addWidget(self.pushButton2, 0, Qt.AlignCenter) self.vBoxLayout.addWidget(self.pushButton2, 0, Qt.AlignCenter)
self.vBoxLayout.addWidget(self.primaryButton1, 0, Qt.AlignCenter) self.vBoxLayout.addWidget(self.primaryButton1, 0, Qt.AlignCenter)
self.vBoxLayout.addWidget(self.primaryButton2, 0, Qt.AlignCenter) self.vBoxLayout.addWidget(self.primaryButton2, 0, Qt.AlignCenter)
self.vBoxLayout.addWidget(self.toggleButton, 0, Qt.AlignCenter)
self.vBoxLayout.addWidget(self.dropDownPushButton, 0, Qt.AlignCenter)
self.vBoxLayout.addWidget(self.dropDownToolButton, 0, Qt.AlignCenter)
self.vBoxLayout.addWidget(self.hyperlinkButton, 0, Qt.AlignCenter) self.vBoxLayout.addWidget(self.hyperlinkButton, 0, Qt.AlignCenter)
self.vBoxLayout.setSizeConstraint(QVBoxLayout.SetMinAndMaxSize) self.vBoxLayout.setSizeConstraint(QVBoxLayout.SetMinAndMaxSize)
self.resize(400, 400) self.resize(500, 600)
self.setStyleSheet('Demo{background:white}') self.setStyleSheet('Demo{background:white}')
......
...@@ -4,125 +4,160 @@ ...@@ -4,125 +4,160 @@
<context> <context>
<name>BasicInputInterface</name> <name>BasicInputInterface</name>
<message> <message>
<location filename="../../view/basic_input_interface.py" line="23"/> <location filename="../../view/basic_input_interface.py" line="24"/>
<source>A simple button with text content</source> <source>A simple button with text content</source>
<translation>带有文本的简单按钮</translation> <translation>带有文本的简单按钮</translation>
</message> </message>
<message> <message>
<location filename="../../view/basic_input_interface.py" line="33"/> <location filename="../../view/basic_input_interface.py" line="34"/>
<source>A button with graphical content</source> <source>A button with graphical content</source>
<translation>带有图标的按钮</translation> <translation>带有图标的按钮</translation>
</message> </message>
<message> <message>
<location filename="../../view/basic_input_interface.py" line="40"/> <location filename="../../view/basic_input_interface.py" line="41"/>
<source>Accent style applied to button</source> <source>Accent style applied to button</source>
<translation>使用主题色的按钮</translation> <translation>使用主题色的按钮</translation>
</message> </message>
<message> <message>
<location filename="../../view/basic_input_interface.py" line="47"/> <location filename="../../view/basic_input_interface.py" line="48"/>
<source>A hyperlink button that navigates to a URI</source> <source>A hyperlink button that navigates to a URI</source>
<translation>导航到一个超链接的按钮</translation> <translation>导航到一个超链接的按钮</translation>
</message> </message>
<message> <message>
<location filename="../../view/basic_input_interface.py" line="54"/> <location filename="../../view/basic_input_interface.py" line="55"/>
<source>A 2-state CheckBox</source> <source>A 2-state CheckBox</source>
<translation>双态复选框</translation> <translation>双态复选框</translation>
</message> </message>
<message> <message>
<location filename="../../view/basic_input_interface.py" line="63"/> <location filename="../../view/basic_input_interface.py" line="64"/>
<source>A 3-state CheckBox</source> <source>A 3-state CheckBox</source>
<translation>三态复选框</translation> <translation>三态复选框</translation>
</message> </message>
<message> <message>
<location filename="../../view/basic_input_interface.py" line="74"/> <location filename="../../view/basic_input_interface.py" line="75"/>
<source>A ComboBox with items</source> <source>A ComboBox with items</source>
<translation>下拉框</translation> <translation>下拉框</translation>
</message> </message>
<message> <message>
<location filename="../../view/basic_input_interface.py" line="112"/> <location filename="../../view/basic_input_interface.py" line="133"/>
<source>A group of RadioButton controls in a button group</source> <source>A group of RadioButton controls in a button group</source>
<translation>单选按钮</translation> <translation>单选按钮</translation>
</message> </message>
<message> <message>
<location filename="../../view/basic_input_interface.py" line="123"/> <location filename="../../view/basic_input_interface.py" line="144"/>
<source>A simple horizontal slider</source> <source>A simple horizontal slider</source>
<translation>水平滑动条</translation> <translation>水平滑动条</translation>
</message> </message>
<message> <message>
<location filename="../../view/basic_input_interface.py" line="132"/> <location filename="../../view/basic_input_interface.py" line="153"/>
<source>A simple switch button</source> <source>A simple switch button</source>
<translation>开关按钮</translation> <translation>开关按钮</translation>
</message> </message>
<message> <message>
<location filename="../../view/basic_input_interface.py" line="142"/> <location filename="../../view/basic_input_interface.py" line="170"/>
<source>Off</source> <source>Off</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../../view/basic_input_interface.py" line="140"/> <location filename="../../view/basic_input_interface.py" line="168"/>
<source>On</source> <source>On</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../../view/basic_input_interface.py" line="23"/> <location filename="../../view/basic_input_interface.py" line="24"/>
<source>Standard push button</source> <source>Standard push button</source>
<translation>标准按钮</translation> <translation>标准按钮</translation>
</message> </message>
<message> <message>
<location filename="../../view/basic_input_interface.py" line="40"/> <location filename="../../view/basic_input_interface.py" line="41"/>
<source>Accent style button</source> <source>Accent style button</source>
<translation>主题色按钮</translation> <translation>主题色按钮</translation>
</message> </message>
<message> <message>
<location filename="../../view/basic_input_interface.py" line="54"/> <location filename="../../view/basic_input_interface.py" line="55"/>
<source>Two-state CheckBox</source> <source>Two-state CheckBox</source>
<translation>双态复选框</translation> <translation>双态复选框</translation>
</message> </message>
<message> <message>
<location filename="../../view/basic_input_interface.py" line="61"/> <location filename="../../view/basic_input_interface.py" line="62"/>
<source>Three-state CheckBox</source> <source>Three-state CheckBox</source>
<translation>三态复选框</translation> <translation>三态复选框</translation>
</message> </message>
<message> <message>
<location filename="../../view/basic_input_interface.py" line="47"/> <location filename="../../view/basic_input_interface.py" line="48"/>
<source>GitHub home page</source> <source>GitHub home page</source>
<translation>GItHub 主页</translation> <translation>GItHub 主页</translation>
</message> </message>
<message> <message>
<location filename="../../view/basic_input_interface.py" line="101"/> <location filename="../../view/basic_input_interface.py" line="122"/>
<source>Star Platinum</source> <source>Star Platinum</source>
<translation>白金之星</translation> <translation>白金之星</translation>
</message> </message>
<message> <message>
<location filename="../../view/basic_input_interface.py" line="102"/> <location filename="../../view/basic_input_interface.py" line="123"/>
<source>Crazy Diamond</source> <source>Crazy Diamond</source>
<translation>疯狂钻石</translation> <translation>疯狂钻石</translation>
</message> </message>
<message> <message>
<location filename="../../view/basic_input_interface.py" line="103"/> <location filename="../../view/basic_input_interface.py" line="124"/>
<source>Soft and Wet</source> <source>Soft and Wet</source>
<translation>软又湿</translation> <translation>软又湿</translation>
</message> </message>
<message> <message>
<location filename="../../view/basic_input_interface.py" line="82"/> <location filename="../../view/basic_input_interface.py" line="83"/>
<source>Gold Experience</source> <source>Gold Experience</source>
<translation>黄金体验</translation> <translation>黄金体验</translation>
</message> </message>
<message> <message>
<location filename="../../view/basic_input_interface.py" line="82"/> <location filename="../../view/basic_input_interface.py" line="83"/>
<source>Sticky Fingers</source> <source>Sticky Fingers</source>
<translation>钢链手指</translation> <translation>钢链手指</translation>
</message> </message>
<message> <message>
<location filename="../../view/basic_input_interface.py" line="88"/> <location filename="../../view/basic_input_interface.py" line="89"/>
<source>Choose your stand</source> <source>Choose your stand</source>
<translation>选择你的替身</translation> <translation>选择你的替身</translation>
</message> </message>
<message> <message>
<location filename="../../view/basic_input_interface.py" line="90"/> <location filename="../../view/basic_input_interface.py" line="91"/>
<source>An editable ComboBox</source> <source>An editable ComboBox</source>
<translation>可编辑的下拉框</translation> <translation>可编辑的下拉框</translation>
</message> </message>
<message>
<location filename="../../view/basic_input_interface.py" line="99"/>
<source>Send</source>
<translation>发送</translation>
</message>
<message>
<location filename="../../view/basic_input_interface.py" line="100"/>
<source>Save</source>
<translation>保存</translation>
</message>
<message>
<location filename="../../view/basic_input_interface.py" line="101"/>
<source>Email</source>
<translation>邮件</translation>
</message>
<message>
<location filename="../../view/basic_input_interface.py" line="103"/>
<source>A push button with drop down menu</source>
<translation>带下拉菜单的按钮</translation>
</message>
<message>
<location filename="../../view/basic_input_interface.py" line="111"/>
<source>A tool button with drop down menu</source>
<translation>带下拉菜单的工具按钮</translation>
</message>
<message>
<location filename="../../view/basic_input_interface.py" line="160"/>
<source>A simple ToggleButton with text content</source>
<translation>带文本的状态开关按钮</translation>
</message>
<message>
<location filename="../../view/basic_input_interface.py" line="160"/>
<source>Start practicing</source>
<translation>开始练习</translation>
</message>
</context> </context>
<context> <context>
<name>DateTimeInterface</name> <name>DateTimeInterface</name>
...@@ -843,6 +878,34 @@ ...@@ -843,6 +878,34 @@
<translation>不要让肌肉察觉</translation> <translation>不要让肌肉察觉</translation>
</message> </message>
</context> </context>
<context>
<name>TableFrame</name>
<message>
<location filename="../../view/view_interface.py" line="107"/>
<source>Title</source>
<translation>标题</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="107"/>
<source>Artist</source>
<translation>歌手</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="107"/>
<source>Album</source>
<translation>专辑</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="107"/>
<source>Year</source>
<translation>年份</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="107"/>
<source>Duration</source>
<translation>时长</translation>
</message>
</context>
<context> <context>
<name>TextInterface</name> <name>TextInterface</name>
<message> <message>
...@@ -970,32 +1033,32 @@ ...@@ -970,32 +1033,32 @@
<context> <context>
<name>TreeFrame</name> <name>TreeFrame</name>
<message> <message>
<location filename="../../view/view_interface.py" line="59"/> <location filename="../../view/view_interface.py" line="66"/>
<source>JoJo 1 - Phantom Blood</source> <source>JoJo 1 - Phantom Blood</source>
<translation>JoJo 1 - 幻影之血</translation> <translation>JoJo 1 - 幻影之血</translation>
</message> </message>
<message> <message>
<location filename="../../view/view_interface.py" line="60"/> <location filename="../../view/view_interface.py" line="67"/>
<source>Jonathan Joestar</source> <source>Jonathan Joestar</source>
<translation>乔纳森·乔斯达</translation> <translation>乔纳森·乔斯达</translation>
</message> </message>
<message> <message>
<location filename="../../view/view_interface.py" line="60"/> <location filename="../../view/view_interface.py" line="67"/>
<source>Dio Brando</source> <source>Dio Brando</source>
<translation>迪奥·布兰度</translation> <translation>迪奥·布兰度</translation>
</message> </message>
<message> <message>
<location filename="../../view/view_interface.py" line="60"/> <location filename="../../view/view_interface.py" line="67"/>
<source>Will A. Zeppeli</source> <source>Will A. Zeppeli</source>
<translation>威廉·A·齐贝林</translation> <translation>威廉·A·齐贝林</translation>
</message> </message>
<message> <message>
<location filename="../../view/view_interface.py" line="67"/> <location filename="../../view/view_interface.py" line="74"/>
<source>JoJo 3 - Stardust Crusaders</source> <source>JoJo 3 - Stardust Crusaders</source>
<translation>JoJo3 - 星尘斗士</translation> <translation>JoJo3 - 星尘斗士</translation>
</message> </message>
<message> <message>
<location filename="../../view/view_interface.py" line="68"/> <location filename="../../view/view_interface.py" line="75"/>
<source>Jotaro Kujo</source> <source>Jotaro Kujo</source>
<translation></translation> <translation></translation>
</message> </message>
...@@ -1003,14 +1066,19 @@ ...@@ -1003,14 +1066,19 @@
<context> <context>
<name>ViewInterface</name> <name>ViewInterface</name>
<message> <message>
<location filename="../../view/view_interface.py" line="23"/> <location filename="../../view/view_interface.py" line="31"/>
<source>A simple TreeView</source> <source>A simple TreeView</source>
<translation>简单的树状组件</translation> <translation>简单的树状组件</translation>
</message> </message>
<message> <message>
<location filename="../../view/view_interface.py" line="30"/> <location filename="../../view/view_interface.py" line="38"/>
<source>A TreeView with Multi-selection enabled</source> <source>A TreeView with Multi-selection enabled</source>
<translation>启用复选框的树状组件</translation> <translation>启用复选框的树状组件</translation>
</message> </message>
<message>
<location filename="../../view/view_interface.py" line="23"/>
<source>A simple TableView</source>
<translation>简单的表格组件</translation>
</message>
</context> </context>
</TS> </TS>
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS> <!DOCTYPE TS>
<TS version="2.1" language="zh_HK" sourcelanguage="en_US"> <TS version="2.1" language="zh_CN" sourcelanguage="en_US">
<context> <context>
<name>BasicInputInterface</name> <name>BasicInputInterface</name>
<message> <message>
<location filename="../../view/basic_input_interface.py" line="23"/> <location filename="../../view/basic_input_interface.py" line="24"/>
<source>A simple button with text content</source> <source>A simple button with text content</source>
<translation>帶有文本的簡單按鈕</translation> <translation>帶有文本的簡單按鈕</translation>
</message> </message>
<message> <message>
<location filename="../../view/basic_input_interface.py" line="33"/> <location filename="../../view/basic_input_interface.py" line="34"/>
<source>A button with graphical content</source> <source>A button with graphical content</source>
<translation>帶有圖標的按鈕</translation> <translation>帶有圖標的按鈕</translation>
</message> </message>
<message> <message>
<location filename="../../view/basic_input_interface.py" line="40"/> <location filename="../../view/basic_input_interface.py" line="41"/>
<source>Accent style applied to button</source> <source>Accent style applied to button</source>
<translation>使用主題色的按鈕</translation> <translation>使用主題色的按鈕</translation>
</message> </message>
<message> <message>
<location filename="../../view/basic_input_interface.py" line="47"/> <location filename="../../view/basic_input_interface.py" line="48"/>
<source>A hyperlink button that navigates to a URI</source> <source>A hyperlink button that navigates to a URI</source>
<translation>導航到一個超鏈接的按鈕</translation> <translation>導航到一個超鏈接的按鈕</translation>
</message> </message>
<message> <message>
<location filename="../../view/basic_input_interface.py" line="54"/> <location filename="../../view/basic_input_interface.py" line="55"/>
<source>A 2-state CheckBox</source> <source>A 2-state CheckBox</source>
<translation>雙態複選框</translation> <translation>雙態複選框</translation>
</message> </message>
<message> <message>
<location filename="../../view/basic_input_interface.py" line="63"/> <location filename="../../view/basic_input_interface.py" line="64"/>
<source>A 3-state CheckBox</source> <source>A 3-state CheckBox</source>
<translation>三態複選框</translation> <translation>三態複選框</translation>
</message> </message>
<message> <message>
<location filename="../../view/basic_input_interface.py" line="74"/> <location filename="../../view/basic_input_interface.py" line="75"/>
<source>A ComboBox with items</source> <source>A ComboBox with items</source>
<translation>下拉框</translation> <translation>下拉框</translation>
</message> </message>
<message> <message>
<location filename="../../view/basic_input_interface.py" line="112"/> <location filename="../../view/basic_input_interface.py" line="133"/>
<source>A group of RadioButton controls in a button group</source> <source>A group of RadioButton controls in a button group</source>
<translation>單選按鈕</translation> <translation>單選按鈕</translation>
</message> </message>
<message> <message>
<location filename="../../view/basic_input_interface.py" line="123"/> <location filename="../../view/basic_input_interface.py" line="144"/>
<source>A simple horizontal slider</source> <source>A simple horizontal slider</source>
<translation>水平滑動條</translation> <translation>水平滑動條</translation>
</message> </message>
<message> <message>
<location filename="../../view/basic_input_interface.py" line="132"/> <location filename="../../view/basic_input_interface.py" line="153"/>
<source>A simple switch button</source> <source>A simple switch button</source>
<translation>開關按鈕</translation> <translation>開關按鈕</translation>
</message> </message>
<message> <message>
<location filename="../../view/basic_input_interface.py" line="142"/> <location filename="../../view/basic_input_interface.py" line="170"/>
<source>Off</source> <source>Off</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../../view/basic_input_interface.py" line="140"/> <location filename="../../view/basic_input_interface.py" line="168"/>
<source>On</source> <source>On</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../../view/basic_input_interface.py" line="23"/> <location filename="../../view/basic_input_interface.py" line="24"/>
<source>Standard push button</source> <source>Standard push button</source>
<translation>標準按鈕</translation> <translation>標準按鈕</translation>
</message> </message>
<message> <message>
<location filename="../../view/basic_input_interface.py" line="40"/> <location filename="../../view/basic_input_interface.py" line="41"/>
<source>Accent style button</source> <source>Accent style button</source>
<translation>主題色按鈕</translation> <translation>主題色按鈕</translation>
</message> </message>
<message> <message>
<location filename="../../view/basic_input_interface.py" line="54"/> <location filename="../../view/basic_input_interface.py" line="55"/>
<source>Two-state CheckBox</source> <source>Two-state CheckBox</source>
<translation>雙態複選框</translation> <translation>雙態複選框</translation>
</message> </message>
<message> <message>
<location filename="../../view/basic_input_interface.py" line="61"/> <location filename="../../view/basic_input_interface.py" line="62"/>
<source>Three-state CheckBox</source> <source>Three-state CheckBox</source>
<translation>三態複選框</translation> <translation>三態複選框</translation>
</message> </message>
<message> <message>
<location filename="../../view/basic_input_interface.py" line="47"/> <location filename="../../view/basic_input_interface.py" line="48"/>
<source>GitHub home page</source> <source>GitHub home page</source>
<translation>GItHub 主頁</translation> <translation>GItHub 主頁</translation>
</message> </message>
<message> <message>
<location filename="../../view/basic_input_interface.py" line="101"/> <location filename="../../view/basic_input_interface.py" line="122"/>
<source>Star Platinum</source> <source>Star Platinum</source>
<translation>白金之星</translation> <translation>白金之星</translation>
</message> </message>
<message> <message>
<location filename="../../view/basic_input_interface.py" line="102"/> <location filename="../../view/basic_input_interface.py" line="123"/>
<source>Crazy Diamond</source> <source>Crazy Diamond</source>
<translation>瘋狂鑽石</translation> <translation>瘋狂鑽石</translation>
</message> </message>
<message> <message>
<location filename="../../view/basic_input_interface.py" line="103"/> <location filename="../../view/basic_input_interface.py" line="124"/>
<source>Soft and Wet</source> <source>Soft and Wet</source>
<translation>軟又溼</translation> <translation>軟又溼</translation>
</message> </message>
<message> <message>
<location filename="../../view/basic_input_interface.py" line="82"/> <location filename="../../view/basic_input_interface.py" line="83"/>
<source>Gold Experience</source> <source>Gold Experience</source>
<translation>黃金體驗</translation> <translation>黃金體驗</translation>
</message> </message>
<message> <message>
<location filename="../../view/basic_input_interface.py" line="82"/> <location filename="../../view/basic_input_interface.py" line="83"/>
<source>Sticky Fingers</source> <source>Sticky Fingers</source>
<translation>鋼鏈手指</translation> <translation>鋼鏈手指</translation>
</message> </message>
<message> <message>
<location filename="../../view/basic_input_interface.py" line="88"/> <location filename="../../view/basic_input_interface.py" line="89"/>
<source>Choose your stand</source> <source>Choose your stand</source>
<translation>選擇你的替身</translation> <translation>選擇你的替身</translation>
</message> </message>
<message> <message>
<location filename="../../view/basic_input_interface.py" line="90"/> <location filename="../../view/basic_input_interface.py" line="91"/>
<source>An editable ComboBox</source> <source>An editable ComboBox</source>
<translation>可編輯的下拉框</translation> <translation>可編輯的下拉框</translation>
</message> </message>
<message>
<location filename="../../view/basic_input_interface.py" line="99"/>
<source>Send</source>
<translation>髮送</translation>
</message>
<message>
<location filename="../../view/basic_input_interface.py" line="100"/>
<source>Save</source>
<translation>保存</translation>
</message>
<message>
<location filename="../../view/basic_input_interface.py" line="101"/>
<source>Email</source>
<translation>郵件</translation>
</message>
<message>
<location filename="../../view/basic_input_interface.py" line="103"/>
<source>A push button with drop down menu</source>
<translation>帶下拉菜單的按鈕</translation>
</message>
<message>
<location filename="../../view/basic_input_interface.py" line="111"/>
<source>A tool button with drop down menu</source>
<translation>帶下拉菜單的工具按鈕</translation>
</message>
<message>
<location filename="../../view/basic_input_interface.py" line="160"/>
<source>A simple ToggleButton with text content</source>
<translation>帶文本的狀態開關按鈕</translation>
</message>
<message>
<location filename="../../view/basic_input_interface.py" line="160"/>
<source>Start practicing</source>
<translation>開始練習</translation>
</message>
</context> </context>
<context> <context>
<name>DateTimeInterface</name> <name>DateTimeInterface</name>
...@@ -843,6 +878,34 @@ ...@@ -843,6 +878,34 @@
<translation>不要讓肌肉察覺</translation> <translation>不要讓肌肉察覺</translation>
</message> </message>
</context> </context>
<context>
<name>TableFrame</name>
<message>
<location filename="../../view/view_interface.py" line="107"/>
<source>Title</source>
<translation>標題</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="107"/>
<source>Artist</source>
<translation>歌手</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="107"/>
<source>Album</source>
<translation>專輯</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="107"/>
<source>Year</source>
<translation>年份</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="107"/>
<source>Duration</source>
<translation>時長</translation>
</message>
</context>
<context> <context>
<name>TextInterface</name> <name>TextInterface</name>
<message> <message>
...@@ -970,32 +1033,32 @@ ...@@ -970,32 +1033,32 @@
<context> <context>
<name>TreeFrame</name> <name>TreeFrame</name>
<message> <message>
<location filename="../../view/view_interface.py" line="59"/> <location filename="../../view/view_interface.py" line="66"/>
<source>JoJo 1 - Phantom Blood</source> <source>JoJo 1 - Phantom Blood</source>
<translation>JoJo 1 - 幻影之血</translation> <translation>JoJo 1 - 幻影之血</translation>
</message> </message>
<message> <message>
<location filename="../../view/view_interface.py" line="60"/> <location filename="../../view/view_interface.py" line="67"/>
<source>Jonathan Joestar</source> <source>Jonathan Joestar</source>
<translation>喬納森·喬斯達</translation> <translation>喬納森·喬斯達</translation>
</message> </message>
<message> <message>
<location filename="../../view/view_interface.py" line="60"/> <location filename="../../view/view_interface.py" line="67"/>
<source>Dio Brando</source> <source>Dio Brando</source>
<translation>迪奧·佈蘭度</translation> <translation>迪奧·佈蘭度</translation>
</message> </message>
<message> <message>
<location filename="../../view/view_interface.py" line="60"/> <location filename="../../view/view_interface.py" line="67"/>
<source>Will A. Zeppeli</source> <source>Will A. Zeppeli</source>
<translation>威廉·A·齊貝林</translation> <translation>威廉·A·齊貝林</translation>
</message> </message>
<message> <message>
<location filename="../../view/view_interface.py" line="67"/> <location filename="../../view/view_interface.py" line="74"/>
<source>JoJo 3 - Stardust Crusaders</source> <source>JoJo 3 - Stardust Crusaders</source>
<translation>JoJo3 - 星塵鬥士</translation> <translation>JoJo3 - 星塵鬥士</translation>
</message> </message>
<message> <message>
<location filename="../../view/view_interface.py" line="68"/> <location filename="../../view/view_interface.py" line="75"/>
<source>Jotaro Kujo</source> <source>Jotaro Kujo</source>
<translation></translation> <translation></translation>
</message> </message>
...@@ -1003,14 +1066,19 @@ ...@@ -1003,14 +1066,19 @@
<context> <context>
<name>ViewInterface</name> <name>ViewInterface</name>
<message> <message>
<location filename="../../view/view_interface.py" line="23"/> <location filename="../../view/view_interface.py" line="31"/>
<source>A simple TreeView</source> <source>A simple TreeView</source>
<translation>簡單的樹狀組件</translation> <translation>簡單的樹狀組件</translation>
</message> </message>
<message> <message>
<location filename="../../view/view_interface.py" line="30"/> <location filename="../../view/view_interface.py" line="38"/>
<source>A TreeView with Multi-selection enabled</source> <source>A TreeView with Multi-selection enabled</source>
<translation>啟用複選框的樹狀組件</translation> <translation>啟用複選框的樹狀組件</translation>
</message> </message>
<message>
<location filename="../../view/view_interface.py" line="23"/>
<source>A simple TableView</source>
<translation>簡單的表格組件</translation>
</message>
</context> </context>
</TS> </TS>
...@@ -60,12 +60,11 @@ QScrollBar { ...@@ -60,12 +60,11 @@ QScrollBar {
margin-top: 0px; margin-top: 0px;
} }
/*隐藏上箭头*/
QScrollBar::sub-line { QScrollBar::sub-line {
background: transparent; background: transparent;
} }
/*隐藏下箭头*/
QScrollBar::add-line { QScrollBar::add-line {
background: transparent; background: transparent;
} }
......
# coding:utf-8 # coding:utf-8
from PyQt5.QtCore import Qt, QSize from PyQt5.QtCore import Qt, QSize
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QButtonGroup from PyQt5.QtWidgets import QAction, QWidget, QVBoxLayout, QButtonGroup
from qfluentwidgets import (PushButton, ToolButton, PrimaryPushButton, HyperlinkButton, from qfluentwidgets import (Action, DropDownPushButton, DropDownToolButton, PushButton, ToolButton, PrimaryPushButton,
ComboBox, RadioButton, CheckBox, Slider, SwitchButton, EditableComboBox) HyperlinkButton, ComboBox, RadioButton, CheckBox, Slider, SwitchButton, EditableComboBox,
ToggleButton, RoundMenu, FluentIcon)
from .gallery_interface import GalleryInterface from .gallery_interface import GalleryInterface
from ..common.translator import Translator from ..common.translator import Translator
...@@ -93,6 +94,26 @@ class BasicInputInterface(GalleryInterface): ...@@ -93,6 +94,26 @@ class BasicInputInterface(GalleryInterface):
'https://github.com/zhiyiYo/PyQt-Fluent-Widgets/blob/master/examples/combo_box/demo.py' 'https://github.com/zhiyiYo/PyQt-Fluent-Widgets/blob/master/examples/combo_box/demo.py'
) )
# drop down button
menu = RoundMenu(parent=self)
menu.addAction(Action(FluentIcon.SEND, self.tr('Send')))
menu.addAction(Action(FluentIcon.SAVE, self.tr('Save')))
button = DropDownPushButton(self.tr('Email'), self, FluentIcon.MAIL)
button.setMenu(menu)
self.addExampleCard(
self.tr('A push button with drop down menu'),
button,
'https://github.com/zhiyiYo/PyQt-Fluent-Widgets/blob/master/examples/button/demo.py'
)
button = DropDownToolButton(FluentIcon.MAIL, self)
button.setMenu(menu)
self.addExampleCard(
self.tr('A tool button with drop down menu'),
button,
'https://github.com/zhiyiYo/PyQt-Fluent-Widgets/blob/master/examples/button/demo.py'
)
# radio button # radio button
radioWidget = QWidget() radioWidget = QWidget()
radioLayout = QVBoxLayout(radioWidget) radioLayout = QVBoxLayout(radioWidget)
...@@ -135,6 +156,13 @@ class BasicInputInterface(GalleryInterface): ...@@ -135,6 +156,13 @@ class BasicInputInterface(GalleryInterface):
'https://github.com/zhiyiYo/PyQt-Fluent-Widgets/blob/master/examples/switch_button/demo.py' 'https://github.com/zhiyiYo/PyQt-Fluent-Widgets/blob/master/examples/switch_button/demo.py'
) )
# toggle button
self.addExampleCard(
self.tr('A simple ToggleButton with text content'),
ToggleButton(self.tr('Start practicing'), self, FluentIcon.BASKETBALL),
'https://github.com/zhiyiYo/PyQt-Fluent-Widgets/blob/master/examples/button/demo.py'
)
def onSwitchCheckedChanged(self, isChecked): def onSwitchCheckedChanged(self, isChecked):
if isChecked: if isChecked:
self.switchButton.setText(self.tr('On')) self.switchButton.setText(self.tr('On'))
......
...@@ -139,13 +139,21 @@ class HomeInterface(ScrollArea): ...@@ -139,13 +139,21 @@ class HomeInterface(ScrollArea):
routeKey="basicInputInterface", routeKey="basicInputInterface",
index=6 index=6
) )
basicInputView.addSampleCard(
icon=":/gallery/images/controls/DropDownButton.png",
title="DropDownButton",
content=self.tr(
"A button that displays a flyout of choices when clicked."),
routeKey="basicInputInterface",
index=8
)
basicInputView.addSampleCard( basicInputView.addSampleCard(
icon=":/gallery/images/controls/RadioButton.png", icon=":/gallery/images/controls/RadioButton.png",
title="RadioButton", title="RadioButton",
content=self.tr( content=self.tr(
"A control that allows a user to select a single option from a group of options."), "A control that allows a user to select a single option from a group of options."),
routeKey="basicInputInterface", routeKey="basicInputInterface",
index=7 index=10
) )
basicInputView.addSampleCard( basicInputView.addSampleCard(
icon=":/gallery/images/controls/Slider.png", icon=":/gallery/images/controls/Slider.png",
...@@ -153,7 +161,7 @@ class HomeInterface(ScrollArea): ...@@ -153,7 +161,7 @@ class HomeInterface(ScrollArea):
content=self.tr( content=self.tr(
"A control that lets the user select from a range of values by moving a Thumb control along a track."), "A control that lets the user select from a range of values by moving a Thumb control along a track."),
routeKey="basicInputInterface", routeKey="basicInputInterface",
index=8 index=11
) )
basicInputView.addSampleCard( basicInputView.addSampleCard(
icon=":/gallery/images/controls/ToggleSwitch.png", icon=":/gallery/images/controls/ToggleSwitch.png",
...@@ -161,7 +169,15 @@ class HomeInterface(ScrollArea): ...@@ -161,7 +169,15 @@ class HomeInterface(ScrollArea):
content=self.tr( content=self.tr(
"A switch that can be toggled between 2 states."), "A switch that can be toggled between 2 states."),
routeKey="basicInputInterface", routeKey="basicInputInterface",
index=9 index=12
)
basicInputView.addSampleCard(
icon=":/gallery/images/controls/ToggleButton.png",
title="ToggleButton",
content=self.tr(
"A button that can be switched between two states like a CheckBox."),
routeKey="basicInputInterface",
index=13
) )
self.vBoxLayout.addWidget(basicInputView) self.vBoxLayout.addWidget(basicInputView)
...@@ -314,12 +330,20 @@ class HomeInterface(ScrollArea): ...@@ -314,12 +330,20 @@ class HomeInterface(ScrollArea):
# view samples # view samples
collectionView = SampleCardView(self.tr('View samples'), self.view) collectionView = SampleCardView(self.tr('View samples'), self.view)
collectionView.addSampleCard(
icon=":/gallery/images/controls/DataGrid.png",
title="TableView",
content=self.tr(
"The DataGrid control provides a flexible way to display a collection of data in rows and columns."),
routeKey="viewInterface",
index=0
)
collectionView.addSampleCard( collectionView.addSampleCard(
icon=":/gallery/images/controls/TreeView.png", icon=":/gallery/images/controls/TreeView.png",
title="TreeView", title="TreeView",
content=self.tr( content=self.tr(
"The TreeView control is a hierarchical list pattern with expanding and collapsing nodes that contain nested items."), "The TreeView control is a hierarchical list pattern with expanding and collapsing nodes that contain nested items."),
routeKey="viewInterface", routeKey="viewInterface",
index=0 index=1
) )
self.vBoxLayout.addWidget(collectionView) self.vBoxLayout.addWidget(collectionView)
# coding:utf-8 # coding:utf-8
from PyQt5.QtCore import QPoint from PyQt5.QtCore import QPoint
from PyQt5.QtWidgets import QAction from PyQt5.QtWidgets import QAction
from qfluentwidgets import RoundMenu, PushButton from qfluentwidgets import RoundMenu, PushButton, Action
from qfluentwidgets import FluentIcon as FIF from qfluentwidgets import FluentIcon as FIF
from .gallery_interface import GalleryInterface from .gallery_interface import GalleryInterface
...@@ -33,22 +33,22 @@ class MenuInterface(GalleryInterface): ...@@ -33,22 +33,22 @@ class MenuInterface(GalleryInterface):
menu = RoundMenu(parent=self) menu = RoundMenu(parent=self)
# add actions # add actions
menu.addAction(QAction(FIF.COPY.icon(), self.tr('Copy'))) menu.addAction(Action(FIF.COPY, self.tr('Copy')))
menu.addAction(QAction(FIF.CUT.icon(), self.tr('Cut'))) menu.addAction(Action(FIF.CUT, self.tr('Cut')))
# add sub menu # add sub menu
submenu = RoundMenu(self.tr("Add to"), self) submenu = RoundMenu(self.tr("Add to"), self)
submenu.setIcon(FIF.ADD.icon()) submenu.setIcon(FIF.ADD)
submenu.addActions([ submenu.addActions([
QAction(FIF.VIDEO.icon(), self.tr('Video')), Action(FIF.VIDEO, self.tr('Video')),
QAction(FIF.MUSIC.icon(), self.tr('Music')), Action(FIF.MUSIC, self.tr('Music')),
]) ])
menu.addMenu(submenu) menu.addMenu(submenu)
# add actions # add actions
menu.addActions([ menu.addActions([
QAction(FIF.PASTE.icon(), self.tr('Paste')), Action(FIF.PASTE, self.tr('Paste')),
QAction(FIF.CANCEL.icon(), self.tr('Undo')) Action(FIF.CANCEL, self.tr('Undo'))
]) ])
# add separator # add separator
...@@ -57,14 +57,13 @@ class MenuInterface(GalleryInterface): ...@@ -57,14 +57,13 @@ class MenuInterface(GalleryInterface):
# insert actions # insert actions
menu.insertAction( menu.insertAction(
menu.menuActions()[-1], QAction(FIF.SETTING.icon(), self.tr('Settings'))) menu.menuActions()[-1], Action(FIF.SETTING, self.tr('Settings')))
menu.insertActions( menu.insertActions(
menu.menuActions()[-1], menu.menuActions()[-1],
[ [
QAction(FIF.HELP.icon(), self.tr('Help')), Action(FIF.HELP, self.tr('Help')),
QAction(FIF.FEEDBACK.icon(), self.tr('Feedback')) Action(FIF.FEEDBACK, self.tr('Feedback'))
] ]
) )
# show menu
menu.exec(pos, ani=True) menu.exec(pos, ani=True)
# coding: utf-8 # coding: utf-8
from PyQt5.QtCore import Qt from PyQt5.QtCore import Qt
from PyQt5.QtGui import QIcon from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QLabel from PyQt5.QtWidgets import QLabel, QHBoxLayout, QVBoxLayout
from qframelesswindow import TitleBar from qframelesswindow import TitleBar
...@@ -10,19 +10,36 @@ class CustomTitleBar(TitleBar): ...@@ -10,19 +10,36 @@ class CustomTitleBar(TitleBar):
def __init__(self, parent): def __init__(self, parent):
super().__init__(parent) super().__init__(parent)
self.setFixedHeight(48)
self.hBoxLayout.removeWidget(self.minBtn)
self.hBoxLayout.removeWidget(self.maxBtn)
self.hBoxLayout.removeWidget(self.closeBtn)
# add window icon # add window icon
self.iconLabel = QLabel(self) self.iconLabel = QLabel(self)
self.iconLabel.setFixedSize(18, 18) self.iconLabel.setFixedSize(18, 18)
self.hBoxLayout.insertSpacing(0, 10) self.hBoxLayout.insertSpacing(0, 10)
self.hBoxLayout.insertWidget(1, self.iconLabel, 0, Qt.AlignLeft | Qt.AlignBottom) self.hBoxLayout.insertWidget(1, self.iconLabel, 0, Qt.AlignLeft | Qt.AlignVCenter)
self.window().windowIconChanged.connect(self.setIcon) self.window().windowIconChanged.connect(self.setIcon)
# add title label # add title label
self.titleLabel = QLabel(self) self.titleLabel = QLabel(self)
self.hBoxLayout.insertWidget(2, self.titleLabel, 0, Qt.AlignLeft | Qt.AlignBottom) self.hBoxLayout.insertWidget(2, self.titleLabel, 0, Qt.AlignLeft | Qt.AlignVCenter)
self.titleLabel.setObjectName('titleLabel') self.titleLabel.setObjectName('titleLabel')
self.window().windowTitleChanged.connect(self.setTitle) self.window().windowTitleChanged.connect(self.setTitle)
self.vBoxLayout = QVBoxLayout()
self.buttonLayout = QHBoxLayout()
self.buttonLayout.setSpacing(0)
self.buttonLayout.setContentsMargins(0, 0, 0, 0)
self.buttonLayout.setAlignment(Qt.AlignTop)
self.buttonLayout.addWidget(self.minBtn)
self.buttonLayout.addWidget(self.maxBtn)
self.buttonLayout.addWidget(self.closeBtn)
self.vBoxLayout.addLayout(self.buttonLayout)
self.vBoxLayout.addStretch(1)
self.hBoxLayout.addLayout(self.vBoxLayout, 0)
def setTitle(self, title): def setTitle(self, title):
self.titleLabel.setText(title) self.titleLabel.setText(title)
self.titleLabel.adjustSize() self.titleLabel.adjustSize()
......
# coding:utf-8 # coding:utf-8
from PyQt5.QtCore import Qt from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QWidget, QFrame, QTreeWidgetItem, QHBoxLayout, QTreeWidgetItemIterator from PyQt5.QtWidgets import QWidget, QFrame, QTreeWidgetItem, QHBoxLayout, QTreeWidgetItemIterator, QTableWidgetItem
from qfluentwidgets import TreeWidget from qfluentwidgets import TreeWidget, TableWidget
from .gallery_interface import GalleryInterface from .gallery_interface import GalleryInterface
from ..common.translator import Translator from ..common.translator import Translator
...@@ -19,6 +19,14 @@ class ViewInterface(GalleryInterface): ...@@ -19,6 +19,14 @@ class ViewInterface(GalleryInterface):
parent=parent parent=parent
) )
# table view
self.addExampleCard(
title=self.tr('A simple TableView'),
widget=TableFrame(self),
sourcePath='https://github.com/zhiyiYo/PyQt-Fluent-Widgets/blob/master/examples/table_view/demo.py'
)
# tree view
frame = TreeFrame(self) frame = TreeFrame(self)
self.addExampleCard( self.addExampleCard(
title=self.tr('A simple TreeView'), title=self.tr('A simple TreeView'),
...@@ -34,7 +42,6 @@ class ViewInterface(GalleryInterface): ...@@ -34,7 +42,6 @@ class ViewInterface(GalleryInterface):
) )
class Frame(QFrame): class Frame(QFrame):
def __init__(self, parent=None): def __init__(self, parent=None):
...@@ -85,3 +92,59 @@ class TreeFrame(Frame): ...@@ -85,3 +92,59 @@ class TreeFrame(Frame):
while(it.value()): while(it.value()):
it.value().setCheckState(0, Qt.Unchecked) it.value().setCheckState(0, Qt.Unchecked)
it += 1 it += 1
class TableFrame(Frame):
def __init__(self, parent=None):
super().__init__(parent)
self.table = TableWidget(self)
self.addWidget(self.table)
self.table.verticalHeader().hide()
self.table.setColumnCount(5)
self.table.setRowCount(60)
self.table.setHorizontalHeaderLabels([
self.tr('Title'), self.tr('Artist'), self.tr('Album'),
self.tr('Year'), self.tr('Duration')
])
songInfos = [
['かばん', 'aiko', 'かばん', '2004', '5:04'],
['爱你', '王心凌', '爱你', '2004', '3:39'],
['星のない世界', 'aiko', '星のない世界/横顔', '2007', '5:30'],
['横顔', 'aiko', '星のない世界/横顔', '2007', '5:06'],
['秘密', 'aiko', '秘密', '2008', '6:27'],
['シアワセ', 'aiko', '秘密', '2008', '5:25'],
['二人', 'aiko', '二人', '2008', '5:00'],
['スパークル', 'RADWIMPS', '君の名は。', '2016', '8:54'],
['なんでもないや', 'RADWIMPS', '君の名は。', '2016', '3:16'],
['前前前世', 'RADWIMPS', '人間開花', '2016', '4:35'],
['恋をしたのは', 'aiko', '恋をしたのは', '2016', '6:02'],
['夏バテ', 'aiko', '恋をしたのは', '2016', '4:41'],
['もっと', 'aiko', 'もっと', '2016', '4:50'],
['問題集', 'aiko', 'もっと', '2016', '4:18'],
['半袖', 'aiko', 'もっと', '2016', '5:50'],
['ひねくれ', '鎖那', 'Hush a by little girl', '2017', '3:54'],
['シュテルン', '鎖那', 'Hush a by little girl', '2017', '3:16'],
['愛は勝手', 'aiko', '湿った夏の始まり', '2018', '5:31'],
['ドライブモード', 'aiko', '湿った夏の始まり', '2018', '3:37'],
['うん。', 'aiko', '湿った夏の始まり', '2018', '5:48'],
['キラキラ', 'aikoの詩。', '2019', '5:08', 'aiko'],
['恋のスーパーボール', 'aiko', 'aikoの詩。', '2019', '4:31'],
['磁石', 'aiko', 'どうしたって伝えられないから', '2021', '4:24'],
['食べた愛', 'aiko', '食べた愛/あたしたち', '2021', '5:17'],
['列車', 'aiko', '食べた愛/あたしたち', '2021', '4:18'],
['花の塔', 'さユり', '花の塔', '2022', '4:35'],
['夏恋のライフ', 'aiko', '夏恋のライフ', '2022', '5:03'],
['あかときリロード', 'aiko', 'あかときリロード', '2023', '4:04'],
['荒れた唇は恋を失くす', 'aiko', '今の二人をお互いが見てる', '2023', '4:07'],
['ワンツースリー', 'aiko', '今の二人をお互いが見てる', '2023', '4:47'],
]
songInfos += songInfos
for i, songInfo in enumerate(songInfos):
for j in range(5):
self.table.setItem(i, j, QTableWidgetItem(songInfo[j]))
self.setFixedSize(650, 440)
self.table.resizeColumnsToContents()
\ No newline at end of file
...@@ -14,5 +14,5 @@ SOURCES += app/view/main_window.py \ ...@@ -14,5 +14,5 @@ SOURCES += app/view/main_window.py \
app/view/view_interface.py \ app/view/view_interface.py \
app/view/date_time_interface.py \ app/view/date_time_interface.py \
TRANSLATIONS += app/resource/i18n/gallery_zh.ts \ TRANSLATIONS += app/resource/i18n/gallery.zh_CN.ts \
app/resource/i18n/gallery_hk.ts app/resource/i18n/gallery.zh_HK.ts
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
import sys import sys
from PyQt5.QtCore import Qt from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication, QWidget, QAction, QHBoxLayout, QLabel from PyQt5.QtWidgets import QApplication, QWidget, QAction, QHBoxLayout, QLabel
from qfluentwidgets import RoundMenu, setTheme, Theme from qfluentwidgets import RoundMenu, setTheme, Theme, Action
from qfluentwidgets import FluentIcon as FIF from qfluentwidgets import FluentIcon as FIF
...@@ -18,28 +18,28 @@ class Demo(QWidget): ...@@ -18,28 +18,28 @@ class Demo(QWidget):
self.setStyleSheet('Demo{background: white} QLabel{font-size: 20px}') self.setStyleSheet('Demo{background: white} QLabel{font-size: 20px}')
# setTheme(Theme.DARK) setTheme(Theme.DARK)
def contextMenuEvent(self, e): def contextMenuEvent(self, e):
menu = RoundMenu(parent=self) menu = RoundMenu(parent=self)
# add actions # add actions
menu.addAction(QAction(FIF.COPY.icon(), 'Copy')) menu.addAction(Action(FIF.COPY, 'Copy'))
menu.addAction(QAction(FIF.CUT.icon(), 'Cut')) menu.addAction(Action(FIF.CUT, 'Cut'))
# add sub menu # add sub menu
submenu = RoundMenu("Add to", self) submenu = RoundMenu("Add to", self)
submenu.setIcon(FIF.ADD.icon()) submenu.setIcon(FIF.ADD)
submenu.addActions([ submenu.addActions([
QAction(FIF.VIDEO.icon(), 'Video'), Action(FIF.VIDEO, 'Video'),
QAction(FIF.MUSIC.icon(), 'Music'), Action(FIF.MUSIC, 'Music'),
]) ])
menu.addMenu(submenu) menu.addMenu(submenu)
# add actions # add actions
menu.addActions([ menu.addActions([
QAction(FIF.PASTE.icon(), 'Paste'), Action(FIF.PASTE, 'Paste'),
QAction(FIF.CANCEL.icon(), 'Undo') Action(FIF.CANCEL, 'Undo')
]) ])
# add separator # add separator
...@@ -48,10 +48,10 @@ class Demo(QWidget): ...@@ -48,10 +48,10 @@ class Demo(QWidget):
# insert actions # insert actions
menu.insertAction( menu.insertAction(
menu.menuActions()[-1], QAction(FIF.SETTING.icon(), 'Settings')) menu.menuActions()[-1], Action(FIF.SETTING, 'Settings'))
menu.insertActions( menu.insertActions(
menu.menuActions()[-1], menu.menuActions()[-1],
[QAction(FIF.HELP.icon(), 'Help'), QAction(FIF.FEEDBACK.icon(), 'Feedback')] [Action(FIF.HELP, 'Help'), Action(FIF.FEEDBACK, 'Feedback')]
) )
# show menu # show menu
......
...@@ -5,7 +5,7 @@ from PyQt5.QtCore import Qt, QLocale ...@@ -5,7 +5,7 @@ from PyQt5.QtCore import Qt, QLocale
from PyQt5.QtGui import QGuiApplication, QFont from PyQt5.QtGui import QGuiApplication, QFont
from qfluentwidgets import (qconfig, QConfig, ConfigItem, OptionsConfigItem, BoolValidator, from qfluentwidgets import (qconfig, QConfig, ConfigItem, OptionsConfigItem, BoolValidator,
ColorConfigItem, OptionsValidator, RangeConfigItem, RangeValidator, ColorConfigItem, OptionsValidator, RangeConfigItem, RangeValidator,
FolderListValidator, EnumSerializer, FolderValidator, ConfigSerializer) FolderListValidator, EnumSerializer, FolderValidator, ConfigSerializer, __version__)
class SongQuality(Enum): class SongQuality(Enum):
...@@ -110,7 +110,7 @@ class Config(QConfig): ...@@ -110,7 +110,7 @@ class Config(QConfig):
YEAR = 2023 YEAR = 2023
AUTHOR = "zhiyiYo" AUTHOR = "zhiyiYo"
VERSION = "v0.2.0" VERSION = __version__
HELP_URL = "https://pyqt-fluent-widgets.readthedocs.io" HELP_URL = "https://pyqt-fluent-widgets.readthedocs.io"
FEEDBACK_URL = "https://github.com/zhiyiYo/PyQt-Fluent-Widgets/issues" FEEDBACK_URL = "https://github.com/zhiyiYo/PyQt-Fluent-Widgets/issues"
RELEASE_URL = "https://github.com/zhiyiYo/PyQt-Fluent-Widgets/releases/latest" RELEASE_URL = "https://github.com/zhiyiYo/PyQt-Fluent-Widgets/releases/latest"
......
...@@ -200,7 +200,7 @@ class SettingInterface(ScrollArea): ...@@ -200,7 +200,7 @@ class SettingInterface(ScrollArea):
FIF.INFO, FIF.INFO,
self.tr('About'), self.tr('About'),
'© ' + self.tr('Copyright') + f" {YEAR}, {AUTHOR}. " + '© ' + self.tr('Copyright') + f" {YEAR}, {AUTHOR}. " +
self.tr('Version') + f" {VERSION[1:]}", self.tr('Version') + f" {VERSION}",
self.aboutGroup self.aboutGroup
) )
......
# coding: utf-8
import sys
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication, QHeaderView, QTableWidgetItem, QWidget, QHBoxLayout
from qfluentwidgets import TableWidget, setTheme, Theme, TableView
class Demo(QWidget):
def __init__(self):
super().__init__()
# setTheme(Theme.DARK)
self.hBoxLayout = QHBoxLayout(self)
self.tableView = TableWidget(self)
self.tableView.setWordWrap(False)
self.tableView.setRowCount(60)
self.tableView.setColumnCount(5)
songInfos = [
['かばん', 'aiko', 'かばん', '2004', '5:04'],
['爱你', '王心凌', '爱你', '2004', '3:39'],
['星のない世界', 'aiko', '星のない世界/横顔', '2007', '5:30'],
['横顔', 'aiko', '星のない世界/横顔', '2007', '5:06'],
['秘密', 'aiko', '秘密', '2008', '6:27'],
['シアワセ', 'aiko', '秘密', '2008', '5:25'],
['二人', 'aiko', '二人', '2008', '5:00'],
['スパークル', 'RADWIMPS', '君の名は。', '2016', '8:54'],
['なんでもないや', 'RADWIMPS', '君の名は。', '2016', '3:16'],
['前前前世', 'RADWIMPS', '人間開花', '2016', '4:35'],
['恋をしたのは', 'aiko', '恋をしたのは', '2016', '6:02'],
['夏バテ', 'aiko', '恋をしたのは', '2016', '4:41'],
['もっと', 'aiko', 'もっと', '2016', '4:50'],
['問題集', 'aiko', 'もっと', '2016', '4:18'],
['半袖', 'aiko', 'もっと', '2016', '5:50'],
['ひねくれ', '鎖那', 'Hush a by little girl', '2017', '3:54'],
['シュテルン', '鎖那', 'Hush a by little girl', '2017', '3:16'],
['愛は勝手', 'aiko', '湿った夏の始まり', '2018', '5:31'],
['ドライブモード', 'aiko', '湿った夏の始まり', '2018', '3:37'],
['うん。', 'aiko', '湿った夏の始まり', '2018', '5:48'],
['キラキラ', 'aikoの詩。', '2019', '5:08', 'aiko'],
['恋のスーパーボール', 'aiko', 'aikoの詩。', '2019', '4:31'],
['磁石', 'aiko', 'どうしたって伝えられないから', '2021', '4:24'],
['食べた愛', 'aiko', '食べた愛/あたしたち', '2021', '5:17'],
['列車', 'aiko', '食べた愛/あたしたち', '2021', '4:18'],
['花の塔', 'さユり', '花の塔', '2022', '4:35'],
['夏恋のライフ', 'aiko', '夏恋のライフ', '2022', '5:03'],
['あかときリロード', 'aiko', 'あかときリロード', '2023', '4:04'],
['荒れた唇は恋を失くす', 'aiko', '今の二人をお互いが見てる', '2023', '4:07'],
['ワンツースリー', 'aiko', '今の二人をお互いが見てる', '2023', '4:47'],
]
songInfos += songInfos
for i, songInfo in enumerate(songInfos):
for j in range(5):
self.tableView.setItem(i, j, QTableWidgetItem(songInfo[j]))
self.tableView.verticalHeader().hide()
self.tableView.setHorizontalHeaderLabels(['标题', '艺人', '专辑', '年份', '时长'])
# self.tableView.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
# self.tableView.setSortingEnabled(True)
self.setStyleSheet("Demo{background: rgb(249, 249, 249)} ")
self.hBoxLayout.setContentsMargins(0, 0, 0, 0)
self.hBoxLayout.addWidget(self.tableView)
self.resize(800, 700)
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()
...@@ -12,7 +12,7 @@ Examples are available at https://github.com/zhiyiYo/PyQt-Fluent-Widgets/tree/ma ...@@ -12,7 +12,7 @@ Examples are available at https://github.com/zhiyiYo/PyQt-Fluent-Widgets/tree/ma
:license: GPLv3, see LICENSE for more details. :license: GPLv3, see LICENSE for more details.
""" """
__version__ = "0.7.6" __version__ = "0.8.0"
from .components import * from .components import *
from .common import * from .common import *
......
<?xml version="1.0" encoding="utf-8"?>
<svg id="ic_fluent_sport_basketball_20_regular" width="16" height="16"
style="width:16px;height:16px;" version="1.1" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 500 500" enable-background="new 0 0 500 500" xml:space="preserve"><path fill="#000000" d="M250.47 227.1 l33.64 -33.64 q-18.69 -23.68 -33.02 -60.44 q-14.33 -36.76 -24.3 -86.6 l-2.49 -13.71 q-66.04 8.72 -117.13 52.34 l143.3 142.05 ZM306.54 215.89 l-33.64 33.64 l142.05 143.3 q43.62 -51.09 52.34 -117.13 l-13.71 -2.49 q-48.6 -9.97 -85.98 -24.3 q-37.38 -14.33 -61.06 -33.02 ZM468.54 244.55 q-1.25 -38.63 -14.95 -74.15 q-13.71 -35.51 -38.64 -64.17 l-85.98 87.23 q18.69 14.95 49.85 26.17 q33.64 13.7 80.99 22.43 l8.73 2.49 ZM306.54 171.03 l87.23 -85.98 q-28.66 -24.93 -64.17 -38.63 q-35.52 -13.7 -74.15 -14.95 l2.49 8.73 q8.73 47.35 22.43 80.99 q11.22 31.16 26.17 49.85 ZM250.47 271.96 l-33.65 33.65 q18.69 22.43 33.02 60.44 q14.33 38 24.3 86.6 l2.5 13.71 q66.04 -8.73 117.13 -52.34 l-143.3 -142.06 ZM194.39 326.79 l-87.22 87.23 q28.66 24.92 64.17 38.63 q35.51 13.71 74.14 14.95 l-2.49 -8.72 q-8.72 -47.35 -22.43 -81 q-11.21 -31.15 -26.17 -49.84 l0 -1.25 ZM171.96 305.61 q-18.69 -14.96 -49.84 -26.17 q-34.89 -13.71 -81 -22.43 l-8.72 -2.49 q1.24 38.63 14.95 74.14 q13.71 35.51 38.63 64.17 l85.98 -87.22 ZM194.39 283.18 l33.65 -33.65 l-142.06 -143.3 q-43.61 51.09 -52.34 117.13 l13.71 2.5 q48.6 9.97 85.99 24.3 q37.38 14.33 61.05 33.02 ZM426.17 425.23 q-46.11 48.6 -110.91 66.04 q-64.79 17.45 -129.59 0 q-64.8 -17.44 -112.15 -64.79 q-47.35 -47.35 -64.8 -112.15 q-17.45 -64.8 0 -129.59 q17.45 -64.8 65.42 -112.15 q47.97 -47.35 112.15 -64.17 q64.17 -16.82 128.35 0 q64.18 16.82 112.15 64.8 q47.98 47.98 64.8 112.15 q16.82 64.17 0 128.35 q-16.82 64.18 -65.42 111.53 Z"/></svg>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<svg id="ic_fluent_sport_basketball_20_regular" width="16" height="16"
style="width:16px;height:16px;" version="1.1" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 500 500" enable-background="new 0 0 500 500" xml:space="preserve"><path fill="#ffffff" d="M250.47 227.1 l33.64 -33.64 q-18.69 -23.68 -33.02 -60.44 q-14.33 -36.76 -24.3 -86.6 l-2.49 -13.71 q-66.04 8.72 -117.13 52.34 l143.3 142.05 ZM306.54 215.89 l-33.64 33.64 l142.05 143.3 q43.62 -51.09 52.34 -117.13 l-13.71 -2.49 q-48.6 -9.97 -85.98 -24.3 q-37.38 -14.33 -61.06 -33.02 ZM468.54 244.55 q-1.25 -38.63 -14.95 -74.15 q-13.71 -35.51 -38.64 -64.17 l-85.98 87.23 q18.69 14.95 49.85 26.17 q33.64 13.7 80.99 22.43 l8.73 2.49 ZM306.54 171.03 l87.23 -85.98 q-28.66 -24.93 -64.17 -38.63 q-35.52 -13.7 -74.15 -14.95 l2.49 8.73 q8.73 47.35 22.43 80.99 q11.22 31.16 26.17 49.85 ZM250.47 271.96 l-33.65 33.65 q18.69 22.43 33.02 60.44 q14.33 38 24.3 86.6 l2.5 13.71 q66.04 -8.73 117.13 -52.34 l-143.3 -142.06 ZM194.39 326.79 l-87.22 87.23 q28.66 24.92 64.17 38.63 q35.51 13.71 74.14 14.95 l-2.49 -8.72 q-8.72 -47.35 -22.43 -81 q-11.21 -31.15 -26.17 -49.84 l0 -1.25 ZM171.96 305.61 q-18.69 -14.96 -49.84 -26.17 q-34.89 -13.71 -81 -22.43 l-8.72 -2.49 q1.24 38.63 14.95 74.14 q13.71 35.51 38.63 64.17 l85.98 -87.22 ZM194.39 283.18 l33.65 -33.65 l-142.06 -143.3 q-43.61 51.09 -52.34 117.13 l13.71 2.5 q48.6 9.97 85.99 24.3 q37.38 14.33 61.05 33.02 ZM426.17 425.23 q-46.11 48.6 -110.91 66.04 q-64.79 17.45 -129.59 0 q-64.8 -17.44 -112.15 -64.79 q-47.35 -47.35 -64.8 -112.15 q-17.45 -64.8 0 -129.59 q17.45 -64.8 65.42 -112.15 q47.97 -47.35 112.15 -64.17 q64.17 -16.82 128.35 0 q64.18 16.82 112.15 64.8 q47.98 47.98 64.8 112.15 q16.82 64.17 0 128.35 q-16.82 64.18 -65.42 111.53 Z"/></svg>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<svg id="" width="12" height="12" style="width:12px;height:12px;" version="1.1"
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2500 2500" enable-background="new 0 0 2048 2048"
xml:space="preserve"><path fill="#000000" transform="translate(200, 700)" d="M0 170.67 q0 -34.67 13.34 -66 q13.34 -31.33 36.66 -54.66 q23.33 -23.33 54.66 -36.66 q31.34 -13.34 66 -13.34 q33.33 0 65.33 14 q32 14 54.67 36.67 l732 733.33 l733.33 -733.33 q50.67 -50.67 121.33 -50.67 q34.67 0 65.34 14 q30.66 14 54 37.34 q23.34 23.34 37.34 54 q14 30.66 14 65.33 q0 70.66 -50.67 121.33 l-853.33 853.33 q-24 24 -55.34 37.34 q-31.34 13.34 -66 13.34 q-69.34 0 -120 -50.67 l-853.34 -853.33 q-49.33 -49.33 -49.33 -121.33 Z"/></svg>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<svg id="" width="12" height="12" style="width:12px;height:12px;" version="1.1"
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2500 2500" enable-background="new 0 0 2048 2048"
xml:space="preserve"><path fill="#ffffff" transform="translate(200, 700)" d="M0 170.67 q0 -34.67 13.34 -66 q13.34 -31.33 36.66 -54.66 q23.33 -23.33 54.66 -36.66 q31.34 -13.34 66 -13.34 q33.33 0 65.33 14 q32 14 54.67 36.67 l732 733.33 l733.33 -733.33 q50.67 -50.67 121.33 -50.67 q34.67 0 65.34 14 q30.66 14 54 37.34 q23.34 23.34 37.34 54 q14 30.66 14 65.33 q0 70.66 -50.67 121.33 l-853.33 853.33 q-24 24 -55.34 37.34 q-31.34 13.34 -66 13.34 q-69.34 0 -120 -50.67 l-853.34 -853.33 q-49.33 -49.33 -49.33 -121.33 Z"/></svg>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<svg id="" width="12" height="12" style="width:12px;height:12px;" version="1.1"
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2500 2500" enable-background="new 0 0 2048 2048"
xml:space="preserve"><path fill="#000000" transform="translate(200, 600)" d="M1022.67 413.33 l-732 732 q-24 24 -55.34 36.67 q-31.34 12.67 -64.67 12.67 q-36 0 -67.33 -12.67 q-31.33 -12.67 -54.67 -36 q-23.34 -23.33 -36 -54.66 q-12.66 -31.34 -12.66 -67.34 q0 -33.33 12.66 -64.66 q12.66 -31.34 36.66 -55.34 l853.34 -853.33 q50.66 -50.67 121.33 -50.67 q33.33 0 65.33 14 q32 14 54.67 36.67 l853.33 853.33 q22.67 22.67 36.67 54.67 q14 32 14 65.33 q0 34.67 -14 66 q-14 31.33 -37.34 54.66 q-23.34 23.34 -54.66 37.34 q-31.33 14 -66 14 q-69.33 0 -120 -50.67 l-733.33 -732 Z"/></svg>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<svg id="" width="12" height="12" style="width:12px;height:12px;" version="1.1"
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2500 2500" enable-background="new 0 0 2048 2048"
xml:space="preserve"><path fill="#ffffff" transform="translate(200, 600)" d="M1022.67 413.33 l-732 732 q-24 24 -55.34 36.67 q-31.34 12.67 -64.67 12.67 q-36 0 -67.33 -12.67 q-31.33 -12.67 -54.67 -36 q-23.34 -23.33 -36 -54.66 q-12.66 -31.34 -12.66 -67.34 q0 -33.33 12.66 -64.66 q12.66 -31.34 36.66 -55.34 l853.34 -853.33 q50.66 -50.67 121.33 -50.67 q33.33 0 65.33 14 q32 14 54.67 36.67 l853.33 853.33 q22.67 22.67 36.67 54.67 q14 32 14 65.33 q0 34.67 -14 66 q-14 31.33 -37.34 54.66 q-23.34 23.34 -54.66 37.34 q-31.33 14 -66 14 q-69.33 0 -120 -50.67 l-733.33 -732 Z"/></svg>
\ No newline at end of file
PushButton, ToolButton { PushButton, ToolButton, ToggleButton {
background: rgba(255, 255, 255, 0.0605); background: rgba(255, 255, 255, 0.0605);
border: 1px solid rgba(255, 255, 255, 0.053); border: 1px solid rgba(255, 255, 255, 0.053);
border-top: 1px solid rgba(255, 255, 255, 0.08); border-top: 1px solid rgba(255, 255, 255, 0.08);
...@@ -21,17 +21,29 @@ PushButton[hasIcon=true] { ...@@ -21,17 +21,29 @@ PushButton[hasIcon=true] {
padding: 5px 12px 6px 36px; padding: 5px 12px 6px 36px;
} }
PushButton:hover, ToolButton:hover { DropDownToolButton {
padding: 5px 31px 6px 8px;
}
DropDownPushButton[hasIcon=false] {
padding: 5px 31px 6px 12px;
}
DropDownPushButton[hasIcon=true] {
padding: 5px 31px 6px 36px;
}
PushButton:hover, ToolButton:hover, ToggleButton:hover {
background: rgba(255, 255, 255, 0.0837); background: rgba(255, 255, 255, 0.0837);
} }
PushButton:pressed, ToolButton:pressed { PushButton:pressed, ToolButton:pressed, ToggleButton:pressed {
color: rgba(255, 255, 255, 0.786); color: rgba(255, 255, 255, 0.786);
background: rgba(255, 255, 255, 0.0326); background: rgba(255, 255, 255, 0.0326);
border-top: 1px solid rgba(255, 255, 255, 0.053); border-top: 1px solid rgba(255, 255, 255, 0.053);
} }
PushButton:disabled, ToolButton:disabled { PushButton:disabled, ToolButton:disabled, ToggleButton:disabled {
color: rgba(255, 255, 255, 0.3628); color: rgba(255, 255, 255, 0.3628);
background: rgba(255, 255, 255, 0.0419); background: rgba(255, 255, 255, 0.0419);
border: 1px solid rgba(255, 255, 255, 0.053); border: 1px solid rgba(255, 255, 255, 0.053);
...@@ -39,26 +51,26 @@ PushButton:disabled, ToolButton:disabled { ...@@ -39,26 +51,26 @@ PushButton:disabled, ToolButton:disabled {
} }
PrimaryPushButton { PrimaryPushButton, ToggleButton:checked {
color: black; color: black;
background-color: --ThemeColorPrimary; background-color: --ThemeColorPrimary;
border: 1px solid --ThemeColorLight1; border: 1px solid --ThemeColorLight1;
border-bottom: 1px solid --ThemeColorLight2; border-bottom: 1px solid --ThemeColorLight2;
} }
PrimaryPushButton:hover { PrimaryPushButton:hover, ToggleButton:checked:hover {
background-color: --ThemeColorDark1; background-color: --ThemeColorDark1;
border: 1px solid --ThemeColorLight1; border: 1px solid --ThemeColorLight1;
border-bottom: 1px solid --ThemeColorLight2; border-bottom: 1px solid --ThemeColorLight2;
} }
PrimaryPushButton:pressed { PrimaryPushButton:pressed, ToggleButton:checked:pressed {
color: rgba(0, 0, 0, 0.63); color: rgba(0, 0, 0, 0.63);
background-color: --ThemeColorDark2; background-color: --ThemeColorDark2;
border: 1px solid --ThemeColorDark2; border: 1px solid --ThemeColorDark2;
} }
PrimaryPushButton:disabled { PrimaryPushButton:disabled, ToggleButton:checked:disabled {
color: rgba(255, 255, 255, 0.43); color: rgba(255, 255, 255, 0.43);
background-color: rgb(52, 52, 52); background-color: rgb(52, 52, 52);
border: 1px solid rgb(52, 52, 52); border: 1px solid rgb(52, 52, 52);
......
...@@ -3,26 +3,27 @@ CheckBox { ...@@ -3,26 +3,27 @@ CheckBox {
font: 14px 'Segoe UI', 'Microsoft YaHei'; font: 14px 'Segoe UI', 'Microsoft YaHei';
spacing: 8px; spacing: 8px;
min-width: 28px; min-width: 28px;
min-height: 20px; min-height: 22px;
outline: none; outline: none;
margin-left: 1px;
} }
CheckBox::indicator { CheckBox::indicator {
width: 18px; width: 18px;
height: 18px; height: 18px;
border-radius: 5px; border-radius: 5px;
border: 1px solid rgb(159, 159, 159); border: 1px solid rgba(255, 255, 255, 0.5547);
background-color: rgb(42, 42, 42); background-color: rgba(0, 0, 0, 0.1);
} }
CheckBox::indicator:hover { CheckBox::indicator:hover {
border: 1px solid rgb(161, 161, 161); border: 1px solid rgba(255, 255, 255, 0.5547);
background-color: rgb(56, 56, 56); background-color: rgba(255, 255, 255, 0.0419);
} }
CheckBox::indicator:pressed { CheckBox::indicator:pressed {
border: 1px solid rgb(86, 86, 86); border: 1px solid rgba(255, 255, 255, 0.1581);
background-color: rgb(62, 62, 62); background-color: rgba(255, 255, 255, 0.0698);
} }
CheckBox::indicator:checked, CheckBox::indicator:checked,
...@@ -49,8 +50,8 @@ CheckBox:disabled { ...@@ -49,8 +50,8 @@ CheckBox:disabled {
} }
CheckBox::indicator:disabled { CheckBox::indicator:disabled {
border: 1px solid rgb(82, 82, 82); border: 1px solid rgba(255, 255, 255, 0.1581);
background-color: rgb(45, 45, 45); background-color: transparent
} }
CheckBox::indicator:checked:disabled, CheckBox::indicator:checked:disabled,
......
...@@ -18,11 +18,15 @@ LineEdit:hover, TextEdit:hover, PlainTextEdit:hover { ...@@ -18,11 +18,15 @@ LineEdit:hover, TextEdit:hover, PlainTextEdit:hover {
background: rgba(255, 255, 255, 0.0837); background: rgba(255, 255, 255, 0.0837);
} }
LineEdit:focus { LineEdit:focus[transparent=true] {
background: rgba(30, 30, 30, 0.7); background: rgba(30, 30, 30, 0.7);
border-bottom: 1px solid rgba(255, 255, 255, 0.08); border-bottom: 1px solid rgba(255, 255, 255, 0.08);
} }
LineEdit[transparent=false]:focus {
background: rgb(31, 31, 31);
}
TextEdit:focus, PlainTextEdit:focus { TextEdit:focus, PlainTextEdit:focus {
border-bottom: 1px solid --ThemeColorPrimary; border-bottom: 1px solid --ThemeColorPrimary;
background-color: rgba(30, 30, 30, 0.7); background-color: rgba(30, 30, 30, 0.7);
......
...@@ -50,14 +50,16 @@ MenuActionListWidget::item { ...@@ -50,14 +50,16 @@ MenuActionListWidget::item {
border-radius: 5px; border-radius: 5px;
border: none; border: none;
color: white; color: white;
margin-left: 6px;
margin-right: 6px;
} }
MenuActionListWidget::disbled { MenuActionListWidget::item:disabled {
padding-left: 10px; padding-left: 10px;
padding-right: 10px; padding-right: 10px;
border-radius: 5px; border-radius: 5px;
border: none; border: none;
color: white; color: rgba(255, 255, 255, 0.5);
} }
MenuActionListWidget::item:hover { MenuActionListWidget::item:hover {
......
QTableView {
background: transparent;
outline: none;
border: none;
font: 13px 'Segoe UI', 'Microsoft YaHei';
}
QTableView::item {
background: transparent;
border: 0px;
padding-left: 16px;
padding-right: 16px;
color: white;
height: 35px;
}
QTableView::item:selected {
color: white
}
QTableView::indicator {
width: 18px;
height: 18px;
border-radius: 5px;
border: 1px solid rgba(255, 255, 255, 0.5547);
background-color: rgba(0, 0, 0, 0.1);
}
QTableView::indicator:hover {
border: 1px solid rgba(255, 255, 255, 0.5547);
background-color: rgba(255, 255, 255, 0.0419);
}
QTableView::indicator:pressed {
border: 1px solid rgba(255, 255, 255, 0.1581);
background-color: rgba(255, 255, 255, 0.0698);
}
QTableView::indicator:checked,
QTableView::indicator:indeterminate {
border: 1px solid --ThemeColorPrimary;
background-color: --ThemeColorPrimary;
}
QTableView::indicator:checked {
image: url(:/qfluentwidgets/images/check_box/Accept_black.svg);
}
QTableView::indicator:indeterminate {
image: url(:/qfluentwidgets/images/check_box/PartialAccept_black.svg);
}
QTableView::indicator:checked:hover,
QTableView::indicator:indeterminate:hover {
border: 1px solid --ThemeColorLight1;
background-color: --ThemeColorLight1;
}
QTableView::indicator:checked:pressed,
QTableView::indicator:indeterminate:pressed {
border: 1px solid --ThemeColorLight3;
background-color: --ThemeColorLight3;
}
QTableView::indicator:disabled {
border: 1px solid rgba(255, 255, 255, 0.1581);
background-color: transparent
}
QTableView::indicator:checked:disabled,
QTableView::indicator:indeterminate:disabled {
border: 1px solid rgb(82, 82, 82);
background-color: rgb(82, 82, 82);
}
QHeaderView {
background-color: transparent;
}
QHeaderView::section {
background-color: transparent;
color: white;
padding-left: 5px;
padding-right: 5px;
border: 1px solid rgba(0, 0, 0, 57);
font: 13px 'Segoe UI', 'Microsoft YaHei';
}
QHeaderView::section:horizontal {
border-left: none;
border-bottom: 1px solid rgba(0, 0, 0, 89);
height: 40px;
}
QHeaderView::section:horizontal:last {
border-right: none;
}
QHeaderView::section:vertical {
border-top: none;
}
QHeaderView::section:checked {
background-color: transparent;
}
QHeaderView::down-arrow {
subcontrol-origin: padding;
subcontrol-position: center right;
margin-right: 6px;
image: url(:/qfluentwidgets/images/table_view/Down_white.svg);
}
QHeaderView::up-arrow {
subcontrol-origin: padding;
subcontrol-position: center right;
margin-right: 6px;
image: url(:/qfluentwidgets/images/table_view/Up_white.svg);
}
QScrollBar:vertical {
background: transparent;
width: 4px;
margin-top: 50px;
margin-bottom: 0;
padding-right: 2px;
}
QScrollBar:horizontal {
background: transparent;
height: 4px;
padding-bottom: 2px;
}
QScrollBar::sub-line {
background: transparent;
}
QScrollBar::add-line {
background: transparent;
}
QScrollBar::handle {
background: rgb(122, 122, 122);
border: 2px solid rgb(128, 128, 128);
border-radius: 1px;
}
QScrollBar::handle:vertical {
min-height: 32px;
}
QScrollBar::handle:horizontal {
min-width: 32px;
}
QScrollBar::add-page:vertical,
QScrollBar::sub-page:vertical,
QScrollBar::add-page:horizontal,
QScrollBar::sub-page:horizontal {
background: none;
}
\ No newline at end of file
...@@ -36,18 +36,18 @@ QTreeView::indicator { ...@@ -36,18 +36,18 @@ QTreeView::indicator {
width: 18px; width: 18px;
height: 18px; height: 18px;
border-radius: 5px; border-radius: 5px;
border: 1px solid rgb(159, 159, 159); border: 1px solid rgba(255, 255, 255, 0.5547);
background-color: rgb(42, 42, 42); background-color: rgba(0, 0, 0, 0.1);
} }
QTreeView::indicator:hover { QTreeView::indicator:hover {
border: 1px solid rgb(161, 161, 161); border: 1px solid rgba(255, 255, 255, 0.5547);
background-color: rgb(56, 56, 56); background-color: rgba(255, 255, 255, 0.0419);
} }
QTreeView::indicator:pressed { QTreeView::indicator:pressed {
border: 1px solid rgb(86, 86, 86); border: 1px solid rgba(255, 255, 255, 0.1581);
background-color: rgb(62, 62, 62); background-color: rgba(255, 255, 255, 0.0698);
} }
QTreeView::indicator:checked, QTreeView::indicator:checked,
...@@ -77,8 +77,8 @@ QTreeView::indicator:indeterminate:pressed { ...@@ -77,8 +77,8 @@ QTreeView::indicator:indeterminate:pressed {
} }
QTreeView::indicator:disabled { QTreeView::indicator:disabled {
border: 1px solid rgb(82, 82, 82); border: 1px solid rgba(255, 255, 255, 0.1581);
background-color: rgb(45, 45, 45); background-color: transparent
} }
QTreeView::indicator:checked:disabled, QTreeView::indicator:checked:disabled,
...@@ -86,15 +86,20 @@ QTreeView::indicator:indeterminate:disabled { ...@@ -86,15 +86,20 @@ QTreeView::indicator:indeterminate:disabled {
border: 1px solid rgb(82, 82, 82); border: 1px solid rgb(82, 82, 82);
background-color: rgb(82, 82, 82); background-color: rgb(82, 82, 82);
} }
QScrollBar:vertical {
QScrollBar {
background: transparent; background: transparent;
width: 4px; width: 4px;
margin-top: 12px; margin-top: 50px;
margin-bottom: 0; margin-bottom: 0;
padding-right: 2px; padding-right: 2px;
} }
QScrollBar:horizontal {
background: transparent;
height: 4px;
padding-bottom: 2px;
}
QScrollBar::sub-line { QScrollBar::sub-line {
background: transparent; background: transparent;
} }
...@@ -107,10 +112,19 @@ QScrollBar::handle { ...@@ -107,10 +112,19 @@ QScrollBar::handle {
background: rgb(122, 122, 122); background: rgb(122, 122, 122);
border: 2px solid rgb(128, 128, 128); border: 2px solid rgb(128, 128, 128);
border-radius: 1px; border-radius: 1px;
}
QScrollBar::handle:vertical {
min-height: 32px; min-height: 32px;
} }
QScrollBar::handle:horizontal {
min-width: 32px;
}
QScrollBar::add-page:vertical, QScrollBar::add-page:vertical,
QScrollBar::sub-page:vertical { QScrollBar::sub-page:vertical,
QScrollBar::add-page:horizontal,
QScrollBar::sub-page:horizontal {
background: none; background: none;
} }
\ No newline at end of file
PushButton, ToolButton { PushButton, ToolButton, ToggleButton {
color: black; color: black;
background: rgba(255, 255, 255, 0.7); background: rgba(255, 255, 255, 0.7);
border: 1px solid rgba(0, 0, 0, 0.073); border: 1px solid rgba(0, 0, 0, 0.073);
...@@ -21,17 +21,29 @@ PushButton[hasIcon=true] { ...@@ -21,17 +21,29 @@ PushButton[hasIcon=true] {
padding: 5px 12px 6px 36px; padding: 5px 12px 6px 36px;
} }
PushButton:hover, ToolButton:hover { DropDownToolButton {
padding: 5px 31px 6px 8px;
}
DropDownPushButton[hasIcon=false] {
padding: 5px 31px 6px 12px;
}
DropDownPushButton[hasIcon=true] {
padding: 5px 31px 6px 36px;
}
PushButton:hover, ToolButton:hover, ToggleButton:hover {
background: rgba(249, 249, 249, 0.5); background: rgba(249, 249, 249, 0.5);
} }
PushButton:pressed, ToolButton:pressed { PushButton:pressed, ToolButton:pressed, ToggleButton:pressed {
color: rgba(0, 0, 0, 0.63); color: rgba(0, 0, 0, 0.63);
background: rgba(249, 249, 249, 0.3); background: rgba(249, 249, 249, 0.3);
border-bottom: 1px solid rgba(0, 0, 0, 0.073); border-bottom: 1px solid rgba(0, 0, 0, 0.073);
} }
PushButton:disabled, ToolButton:disabled { PushButton:disabled, ToolButton:disabled, ToggleButton:disabled {
color: rgba(0, 0, 0, 0.36); color: rgba(0, 0, 0, 0.36);
background: rgba(249, 249, 249, 0.3); background: rgba(249, 249, 249, 0.3);
border: 1px solid rgba(0, 0, 0, 0.06); border: 1px solid rgba(0, 0, 0, 0.06);
...@@ -39,26 +51,30 @@ PushButton:disabled, ToolButton:disabled { ...@@ -39,26 +51,30 @@ PushButton:disabled, ToolButton:disabled {
} }
PrimaryPushButton { PrimaryPushButton,
ToggleButton:checked {
color: white; color: white;
background-color: --ThemeColorPrimary; background-color: --ThemeColorPrimary;
border: 1px solid --ThemeColorLight1; border: 1px solid --ThemeColorLight1;
border-bottom: 1px solid --ThemeColorDark1; border-bottom: 1px solid --ThemeColorDark1;
} }
PrimaryPushButton:hover { PrimaryPushButton:hover,
ToggleButton:checked:hover {
background-color: --ThemeColorLight1; background-color: --ThemeColorLight1;
border: 1px solid --ThemeColorLight2; border: 1px solid --ThemeColorLight2;
border-bottom: 1px solid --ThemeColorDark1; border-bottom: 1px solid --ThemeColorDark1;
} }
PrimaryPushButton:pressed { PrimaryPushButton:pressed,
ToggleButton:checked:pressed {
color: rgba(255, 255, 255, 0.63); color: rgba(255, 255, 255, 0.63);
background-color: --ThemeColorLight3; background-color: --ThemeColorLight3;
border: 1px solid --ThemeColorLight3; border: 1px solid --ThemeColorLight3;
} }
PrimaryPushButton:disabled { PrimaryPushButton:disabled,
ToggleButton:checked:disabled {
color: rgba(255, 255, 255, 0.9); color: rgba(255, 255, 255, 0.9);
background-color: rgb(205, 205, 205); background-color: rgb(205, 205, 205);
border: 1px solid rgb(205, 205, 205); border: 1px solid rgb(205, 205, 205);
......
...@@ -3,8 +3,9 @@ CheckBox { ...@@ -3,8 +3,9 @@ CheckBox {
font: 14px 'Segoe UI', 'Microsoft YaHei'; font: 14px 'Segoe UI', 'Microsoft YaHei';
spacing: 8px; spacing: 8px;
min-width: 28px; min-width: 28px;
min-height: 20px; min-height: 22px;
outline: none; outline: none;
margin-left: 1px;
} }
CheckBox::indicator { CheckBox::indicator {
......
...@@ -47,6 +47,8 @@ MenuActionListWidget::item { ...@@ -47,6 +47,8 @@ MenuActionListWidget::item {
padding-right: 10px; padding-right: 10px;
border-radius: 5px; border-radius: 5px;
border: none; border: none;
margin-left: 6px;
margin-right: 6px;
} }
MenuActionListWidget::item:disabled { MenuActionListWidget::item:disabled {
...@@ -54,7 +56,6 @@ MenuActionListWidget::item:disabled { ...@@ -54,7 +56,6 @@ MenuActionListWidget::item:disabled {
padding-right: 10px; padding-right: 10px;
border-radius: 5px; border-radius: 5px;
border: none; border: none;
color: black;
} }
MenuActionListWidget::item:hover { MenuActionListWidget::item:hover {
......
QTableView {
background: transparent;
outline: none;
border: none;
font: 13px 'Segoe UI', 'Microsoft YaHei';
}
QTableView::item {
background: transparent;
border: 0px;
padding-left: 16px;
padding-right: 16px;
color: black;
height: 35px;
}
QTableView::item:selected {
color: black
}
QTableView::indicator {
width: 18px;
height: 18px;
border-radius: 5px;
border: 1px solid rgba(0, 0, 0, 0.48);
background-color: rgba(0, 0, 0, 0.022);
}
QTableView::indicator:hover {
border: 1px solid rgba(0, 0, 0, 0.56);
background-color: rgba(0, 0, 0, 0.05);
}
QTableView::indicator:pressed {
border: 1px solid rgba(0, 0, 0, 0.27);
background-color: rgba(0, 0, 0, 0.12);
}
QTableView::indicator:checked,
QTableView::indicator:indeterminate {
border: 1px solid --ThemeColorPrimary;
background-color: --ThemeColorPrimary;
}
QTableView::indicator:checked {
image: url(:/qfluentwidgets/images/check_box/Accept_white.svg);
}
QTableView::indicator:indeterminate {
image: url(:/qfluentwidgets/images/check_box/PartialAccept_white.svg);
}
QTableView::indicator:checked:hover,
QTableView::indicator:indeterminate:hover {
border: 1px solid --ThemeColorLight1;
background-color: --ThemeColorLight1;
}
QTableView::indicator:checked:pressed,
QTableView::indicator:indeterminate:pressed {
border: 1px solid --ThemeColorLight3;
background-color: --ThemeColorLight3;
}
QTableView::indicator:disabled {
border: 1px solid rgba(0, 0, 0, 0.27);
background-color: transparent;
}
QTableView::indicator:checked:disabled,
QTableView::indicator:indeterminate:disabled {
border: 1px solid rgb(199, 199, 199);
background-color: rgb(199, 199, 199);
}
QHeaderView {
background-color: transparent;
}
QHeaderView::section {
background-color: transparent;
color: black;
padding-left: 5px;
padding-right: 5px;
border: 1px solid rgba(0, 0, 0, 19);
font: 13px 'Segoe UI', 'Microsoft YaHei';
}
QHeaderView::section:horizontal {
border-bottom: 1px solid rgba(0, 0, 0, 7);
border-left: none;
height: 40px;
}
QHeaderView::section:horizontal:last {
border-right: none;
}
QHeaderView::section:vertical {
border-top: none;
}
QHeaderView::section:checked {
background-color: transparent;
}
QHeaderView::down-arrow {
subcontrol-origin: padding;
subcontrol-position: center right;
margin-right: 6px;
image: url(:/qfluentwidgets/images/table_view/Down_black.svg);
}
QHeaderView::up-arrow {
subcontrol-origin: padding;
subcontrol-position: center right;
margin-right: 6px;
image: url(:/qfluentwidgets/images/table_view/Up_black.svg);
}
QScrollBar:vertical {
background: transparent;
width: 4px;
margin-top: 50px;
margin-bottom: 0;
padding-right: 2px;
}
QScrollBar:horizontal {
background: transparent;
height: 4px;
padding-bottom: 2px;
}
QScrollBar::sub-line {
background: transparent;
}
QScrollBar::add-line {
background: transparent;
}
QScrollBar::handle {
background: rgb(122, 122, 122);
border: 2px solid rgb(128, 128, 128);
border-radius: 1px;
}
QScrollBar::handle:vertical {
min-height: 32px;
}
QScrollBar::handle:horizontal {
min-width: 32px;
}
QScrollBar::add-page:vertical,
QScrollBar::sub-page:vertical,
QScrollBar::add-page:horizontal,
QScrollBar::sub-page:horizontal {
background: none;
}
\ No newline at end of file
...@@ -35,18 +35,18 @@ QTreeView::indicator { ...@@ -35,18 +35,18 @@ QTreeView::indicator {
width: 18px; width: 18px;
height: 18px; height: 18px;
border-radius: 5px; border-radius: 5px;
border: 1px solid rgb(135, 135, 135); border: 1px solid rgba(0, 0, 0, 0.48);
background-color: rgb(241, 241, 241); background-color: rgba(0, 0, 0, 0.022);
} }
QTreeView::indicator:hover { QTreeView::indicator:hover {
border: 1px solid rgb(132, 132, 132); border: 1px solid rgba(0, 0, 0, 0.56);
background-color: rgb(232, 232, 232); background-color: rgba(0, 0, 0, 0.05);
} }
QTreeView::indicator:pressed { QTreeView::indicator:pressed {
border: 1px solid rgb(184, 184, 184); border: 1px solid rgba(0, 0, 0, 0.27);
background-color: rgb(224, 224, 224); background-color: rgba(0, 0, 0, 0.12);
} }
QTreeView::indicator:checked, QTreeView::indicator:checked,
...@@ -76,8 +76,8 @@ QTreeView::indicator:indeterminate:pressed { ...@@ -76,8 +76,8 @@ QTreeView::indicator:indeterminate:pressed {
} }
QTreeView::indicator:disabled { QTreeView::indicator:disabled {
border: 1px solid #bbbbbb; border: 1px solid rgba(0, 0, 0, 0.27);
background-color: rgb(224, 224, 224); background-color: transparent;
} }
QTreeView::indicator:checked:disabled, QTreeView::indicator:checked:disabled,
...@@ -86,15 +86,20 @@ QTreeView::indicator:indeterminate:disabled { ...@@ -86,15 +86,20 @@ QTreeView::indicator:indeterminate:disabled {
background-color: rgb(199, 199, 199); background-color: rgb(199, 199, 199);
} }
QScrollBar:vertical {
QScrollBar {
background: transparent; background: transparent;
width: 4px; width: 4px;
margin-top: 12px; margin-top: 50px;
margin-bottom: 0; margin-bottom: 0;
padding-right: 2px; padding-right: 2px;
} }
QScrollBar:horizontal {
background: transparent;
height: 4px;
padding-bottom: 2px;
}
QScrollBar::sub-line { QScrollBar::sub-line {
background: transparent; background: transparent;
} }
...@@ -107,10 +112,19 @@ QScrollBar::handle { ...@@ -107,10 +112,19 @@ QScrollBar::handle {
background: rgb(122, 122, 122); background: rgb(122, 122, 122);
border: 2px solid rgb(128, 128, 128); border: 2px solid rgb(128, 128, 128);
border-radius: 1px; border-radius: 1px;
}
QScrollBar::handle:vertical {
min-height: 32px; min-height: 32px;
} }
QScrollBar::handle:horizontal {
min-width: 32px;
}
QScrollBar::add-page:vertical, QScrollBar::add-page:vertical,
QScrollBar::sub-page:vertical { QScrollBar::sub-page:vertical,
QScrollBar::add-page:horizontal,
QScrollBar::sub-page:horizontal {
background: none; background: none;
} }
\ No newline at end of file
此差异已折叠。
...@@ -163,6 +163,8 @@ ...@@ -163,6 +163,8 @@
<file>images/icons/Accept_white.svg</file> <file>images/icons/Accept_white.svg</file>
<file>images/icons/DateTime_black.svg</file> <file>images/icons/DateTime_black.svg</file>
<file>images/icons/DateTime_white.svg</file> <file>images/icons/DateTime_white.svg</file>
<file>images/icons/Basketball_black.svg</file>
<file>images/icons/Basketball_white.svg</file>
<file>images/acrylic/noise.png</file> <file>images/acrylic/noise.png</file>
<file>images/folder_list_dialog/Close_white.png</file> <file>images/folder_list_dialog/Close_white.png</file>
<file>images/folder_list_dialog/Close_black.png</file> <file>images/folder_list_dialog/Close_black.png</file>
...@@ -192,6 +194,10 @@ ...@@ -192,6 +194,10 @@
<file>images/time_picker/Up_black.svg</file> <file>images/time_picker/Up_black.svg</file>
<file>images/time_picker/Down_white.svg</file> <file>images/time_picker/Down_white.svg</file>
<file>images/time_picker/Down_black.svg</file> <file>images/time_picker/Down_black.svg</file>
<file>images/table_view/Up_black.svg</file>
<file>images/table_view/Up_white.svg</file>
<file>images/table_view/Down_black.svg</file>
<file>images/table_view/Down_white.svg</file>
<file>qss/dark/color_dialog.qss</file> <file>qss/dark/color_dialog.qss</file>
<file>qss/dark/dialog.qss</file> <file>qss/dark/dialog.qss</file>
...@@ -213,6 +219,7 @@ ...@@ -213,6 +219,7 @@
<file>qss/dark/info_bar.qss</file> <file>qss/dark/info_bar.qss</file>
<file>qss/dark/spin_box.qss</file> <file>qss/dark/spin_box.qss</file>
<file>qss/dark/tree_view.qss</file> <file>qss/dark/tree_view.qss</file>
<file>qss/dark/table_view.qss</file>
<file>qss/dark/time_picker.qss</file> <file>qss/dark/time_picker.qss</file>
<file>qss/light/color_dialog.qss</file> <file>qss/light/color_dialog.qss</file>
...@@ -234,6 +241,7 @@ ...@@ -234,6 +241,7 @@
<file>qss/light/check_box.qss</file> <file>qss/light/check_box.qss</file>
<file>qss/light/info_bar.qss</file> <file>qss/light/info_bar.qss</file>
<file>qss/light/spin_box.qss</file> <file>qss/light/spin_box.qss</file>
<file>qss/light/table_view.qss</file>
<file>qss/light/tree_view.qss</file> <file>qss/light/tree_view.qss</file>
<file>qss/light/time_picker.qss</file> <file>qss/light/time_picker.qss</file>
......
from .config import * from .config import *
from .auto_wrap import TextWrap from .auto_wrap import TextWrap
from .icon import Icon, getIconColor, drawSvgIcon, FluentIcon, drawIcon, FluentIconBase, writeSvg from .icon import Action, Icon, getIconColor, drawSvgIcon, FluentIcon, drawIcon, FluentIconBase, writeSvg
from .style_sheet import (setStyleSheet, getStyleSheet, setTheme, ThemeColor, themeColor, from .style_sheet import (setStyleSheet, getStyleSheet, setTheme, ThemeColor, themeColor,
setThemeColor, applyThemeColor, FluentStyleSheet, StyleSheetBase) setThemeColor, applyThemeColor, FluentStyleSheet, StyleSheetBase)
from .smooth_scroll import SmoothScroll, SmoothMode from .smooth_scroll import SmoothScroll, SmoothMode
......
# coding:utf-8 # coding:utf-8
from enum import Enum from enum import Enum
from typing import Union
from PyQt5 import QtGui
from PyQt5.QtXml import QDomDocument from PyQt5.QtXml import QDomDocument
from PyQt5.QtCore import QPoint, QRect, QRectF, Qt, QFile from PyQt5.QtCore import QRectF, Qt, QFile, QObject
from PyQt5.QtGui import QIcon, QIconEngine, QImage, QPainter, QPixmap, QColor from PyQt5.QtGui import QIcon, QIconEngine
from PyQt5.QtWidgets import QAction
from PyQt5.QtSvg import QSvgRenderer from PyQt5.QtSvg import QSvgRenderer
from .config import isDarkTheme, Theme from .config import isDarkTheme, Theme
from .overload import singledispatchmethod
class IconEngine(QIconEngine):
""" Icon engine """
def __init__(self, iconPath):
self.iconPath = iconPath
super().__init__()
def paint(self, painter, rect, mode, state):
painter.setRenderHints(QPainter.Antialiasing |
QPainter.SmoothPixmapTransform)
if not self.iconPath.lower().endswith('svg'):
painter.drawImage(rect, QImage(self.iconPath))
else:
drawSvgIcon(self.iconPath, painter, rect)
def pixmap(self, size, mode, state):
pixmap = QPixmap(size)
pixmap.fill(Qt.transparent)
self.paint(QPainter(pixmap), QRect(QPoint(0, 0), size), mode, state)
return pixmap
class Icon(QIcon):
def __init__(self, iconPath):
self.iconPath = iconPath
super().__init__(IconEngine(iconPath))
class MenuIconEngine(QIconEngine): class MenuIconEngine(QIconEngine):
...@@ -45,7 +21,19 @@ class MenuIconEngine(QIconEngine): ...@@ -45,7 +21,19 @@ class MenuIconEngine(QIconEngine):
self.icon = icon self.icon = icon
def paint(self, painter, rect, mode, state): def paint(self, painter, rect, mode, state):
self.icon.paint(painter, rect, Qt.AlignHCenter, QIcon.Normal, state) painter.save()
if mode == QIcon.Disabled:
painter.setOpacity(0.5)
elif mode == QIcon.Selected:
painter.setOpacity(0.7)
icon = self.icon
if isinstance(self.icon, Icon):
icon = self.icon.fluentIcon.icon()
icon.paint(painter, rect, Qt.AlignHCenter, QIcon.Normal, state)
painter.restore()
def getIconColor(theme=Theme.AUTO, reverse=False): def getIconColor(theme=Theme.AUTO, reverse=False):
...@@ -286,6 +274,7 @@ class FluentIcon(FluentIconBase, Enum): ...@@ -286,6 +274,7 @@ class FluentIcon(FluentIconBase, Enum):
FOLDER_ADD = "FolderAdd" FOLDER_ADD = "FolderAdd"
PENCIL_INK = "PencilInk" PENCIL_INK = "PencilInk"
ZIP_FOLDER = "ZipFolder" ZIP_FOLDER = "ZipFolder"
BASKETBALL = "Basketball"
MICROPHONE = "Microphone" MICROPHONE = "Microphone"
ARROW_DOWN = "ChevronDown" ARROW_DOWN = "ChevronDown"
TRANSPARENT = "Transparent" TRANSPARENT = "Transparent"
...@@ -295,3 +284,47 @@ class FluentIcon(FluentIconBase, Enum): ...@@ -295,3 +284,47 @@ class FluentIcon(FluentIconBase, Enum):
def path(self, theme=Theme.AUTO): def path(self, theme=Theme.AUTO):
return f':/qfluentwidgets/images/icons/{self.value}_{getIconColor(theme)}.svg' return f':/qfluentwidgets/images/icons/{self.value}_{getIconColor(theme)}.svg'
class Icon(QIcon):
def __init__(self, fluentIcon: FluentIcon):
super().__init__(fluentIcon.path())
self.fluentIcon = fluentIcon
class Action(QAction):
""" Fluent action """
@singledispatchmethod
def __init__(self, parent: QObject = None, **kwargs):
super().__init__(parent, **kwargs)
self.fluentIcon = None
@__init__.register
def _(self, text: str, parent: QObject = None, **kwargs):
super().__init__(text, parent, **kwargs)
self.fluentIcon = None
@__init__.register
def _(self, icon: QIcon, text: str, parent: QObject = None, **kwargs):
super().__init__(icon, text, parent, **kwargs)
self.fluentIcon = None
@__init__.register
def _(self, icon: FluentIconBase, text: str, parent: QObject = None, **kwargs):
super().__init__(icon.icon(), text, parent, **kwargs)
self.fluentIcon = icon
def icon(self) -> QIcon:
if self.fluentIcon:
return Icon(self.fluentIcon)
return super().icon()
def setIcon(self, icon: Union[FluentIconBase, QIcon]):
if isinstance(icon, FluentIconBase):
self.fluentIcon = icon
icon = icon.icon()
super().setIcon(icon)
\ No newline at end of file
...@@ -41,7 +41,8 @@ class SmoothScroll: ...@@ -41,7 +41,8 @@ class SmoothScroll:
def wheelEvent(self, e): def wheelEvent(self, e):
# only process the wheel events triggered by mouse, fixes issue #75 # only process the wheel events triggered by mouse, fixes issue #75
if self.smoothMode == SmoothMode.NO_SMOOTH or abs(e.angleDelta().y()) % 120 != 0: delta = e.angleDelta().y() if e.angleDelta().y() != 0 else e.angleDelta().x()
if self.smoothMode == SmoothMode.NO_SMOOTH or abs(delta) % 120 != 0:
QAbstractScrollArea.wheelEvent(self.widget, e) QAbstractScrollArea.wheelEvent(self.widget, e)
return return
...@@ -62,7 +63,7 @@ class SmoothScroll: ...@@ -62,7 +63,7 @@ class SmoothScroll:
self.stepsTotal = self.fps * self.duration / 1000 self.stepsTotal = self.fps * self.duration / 1000
# get the moving distance corresponding to each event # get the moving distance corresponding to each event
delta = e.angleDelta().y() * self.stepRatio delta = delta* self.stepRatio
if self.acceleration > 0: if self.acceleration > 0:
delta += delta * self.acceleration * accerationRatio delta += delta * self.acceleration * accerationRatio
......
...@@ -97,6 +97,7 @@ class FluentStyleSheet(StyleSheetBase, Enum): ...@@ -97,6 +97,7 @@ class FluentStyleSheet(StyleSheetBase, Enum):
COMBO_BOX = "combo_box" COMBO_BOX = "combo_box"
LINE_EDIT = "line_edit" LINE_EDIT = "line_edit"
TREE_VIEW = "tree_view" TREE_VIEW = "tree_view"
TABLE_VIEW = "table_view"
TIME_PICKER = "time_picker" TIME_PICKER = "time_picker"
SETTING_CARD = "setting_card" SETTING_CARD = "setting_card"
COLOR_DIALOG = "color_dialog" COLOR_DIALOG = "color_dialog"
......
from .button import PrimaryPushButton, PushButton, RadioButton, HyperlinkButton, ToolButton, TransparentToolButton from .button import (DropDownPushButton, DropDownToolButton, PrimaryPushButton, PushButton, RadioButton,
HyperlinkButton, ToolButton, TransparentToolButton, ToggleButton)
from .check_box import CheckBox from .check_box import CheckBox
from .combo_box import ComboBox, EditableComboBox from .combo_box import ComboBox, EditableComboBox
from .line_edit import LineEdit, TextEdit, PlainTextEdit, LineEditButton, SearchLineEdit from .line_edit import LineEdit, TextEdit, PlainTextEdit, LineEditButton, SearchLineEdit
...@@ -12,6 +13,7 @@ from .spin_box import SpinBox, DoubleSpinBox, DateEdit, DateTimeEdit, TimeEdit ...@@ -12,6 +13,7 @@ from .spin_box import SpinBox, DoubleSpinBox, DateEdit, DateTimeEdit, TimeEdit
from .stacked_widget import PopUpAniStackedWidget, OpacityAniStackedWidget from .stacked_widget import PopUpAniStackedWidget, OpacityAniStackedWidget
from .state_tool_tip import StateToolTip from .state_tool_tip import StateToolTip
from .switch_button import SwitchButton, IndicatorPosition from .switch_button import SwitchButton, IndicatorPosition
from .table_view import TableView, TableWidget, TableItemDelegate
from .tool_tip import ToolTip, ToolTipFilter from .tool_tip import ToolTip, ToolTipFilter
from .tree_view import TreeWidget, TreeView from .tree_view import TreeWidget, TreeView
from .cycle_list_widget import CycleListWidget from .cycle_list_widget import CycleListWidget
\ No newline at end of file
# coding:utf-8 # coding:utf-8
from typing import Union from typing import Union
from PyQt5.QtCore import QUrl, Qt, QRectF, QSize from PyQt5.QtCore import QEvent, QUrl, Qt, QRectF, QSize, QPoint
from PyQt5.QtGui import QDesktopServices, QIcon, QPainter from PyQt5.QtGui import QDesktopServices, QIcon, QPainter
from PyQt5.QtWidgets import QPushButton, QRadioButton, QToolButton, QApplication, QWidget from PyQt5.QtWidgets import QMenu, QPushButton, QRadioButton, QToolButton, QApplication, QWidget
from ...common.icon import FluentIconBase, drawIcon, isDarkTheme, Theme from ...common.icon import FluentIconBase, drawIcon, isDarkTheme, Theme
from ...common.icon import FluentIcon as FIF
from ...common.style_sheet import FluentStyleSheet from ...common.style_sheet import FluentStyleSheet
from ...common.overload import singledispatchmethod from ...common.overload import singledispatchmethod
from .menu import RoundMenu
class PushButton(QPushButton): class PushButton(QPushButton):
...@@ -18,6 +20,7 @@ class PushButton(QPushButton): ...@@ -18,6 +20,7 @@ class PushButton(QPushButton):
super().__init__(parent) super().__init__(parent)
FluentStyleSheet.BUTTON.apply(self) FluentStyleSheet.BUTTON.apply(self)
self.isPressed = False self.isPressed = False
self.isHover = False
self.setIconSize(QSize(16, 16)) self.setIconSize(QSize(16, 16))
self.setIcon(None) self.setIcon(None)
...@@ -49,6 +52,14 @@ class PushButton(QPushButton): ...@@ -49,6 +52,14 @@ class PushButton(QPushButton):
self.isPressed = False self.isPressed = False
super().mouseReleaseEvent(e) super().mouseReleaseEvent(e)
def enterEvent(self, e):
self.isHover = True
self.update()
def leaveEvent(self, e):
self.isHover = False
self.update()
def _drawIcon(self, icon, painter, rect): def _drawIcon(self, icon, painter, rect):
""" draw icon """ """ draw icon """
drawIcon(icon, painter, rect) drawIcon(icon, painter, rect)
...@@ -87,7 +98,28 @@ class PrimaryPushButton(PushButton): ...@@ -87,7 +98,28 @@ class PrimaryPushButton(PushButton):
painter.setOpacity(0.786 if isDarkTheme() else 0.9) painter.setOpacity(0.786 if isDarkTheme() else 0.9)
icon = icon.icon(Theme.DARK) icon = icon.icon(Theme.DARK)
super()._drawIcon(icon, painter, rect) PushButton._drawIcon(self, icon, painter, rect)
class ToggleButton(PushButton):
@singledispatchmethod
def __init__(self, parent: QWidget = None):
super().__init__(parent)
self.setCheckable(True)
super().setChecked(False)
@__init__.register
def _(self, text: str, parent: QWidget = None, icon: Union[QIcon, str, FluentIconBase] = None):
self.__init__(parent=parent)
self.setText(text)
self.setIcon(icon)
def _drawIcon(self, icon, painter, rect):
if not self.isChecked():
return PushButton._drawIcon(self, icon, painter, rect)
PrimaryPushButton._drawIcon(self, icon, painter, rect)
class HyperlinkButton(QPushButton): class HyperlinkButton(QPushButton):
...@@ -133,6 +165,7 @@ class ToolButton(QToolButton): ...@@ -133,6 +165,7 @@ class ToolButton(QToolButton):
super().__init__(parent) super().__init__(parent)
FluentStyleSheet.BUTTON.apply(self) FluentStyleSheet.BUTTON.apply(self)
self.isPressed = False self.isPressed = False
self.isHover = False
self.setIcon(QIcon()) self.setIcon(QIcon())
@__init__.register @__init__.register
...@@ -170,6 +203,14 @@ class ToolButton(QToolButton): ...@@ -170,6 +203,14 @@ class ToolButton(QToolButton):
self.isPressed = False self.isPressed = False
super().mouseReleaseEvent(e) super().mouseReleaseEvent(e)
def enterEvent(self, e):
self.isHover = True
self.update()
def leaveEvent(self, e):
self.isHover = False
self.update()
def _drawIcon(self, icon, painter, rect): def _drawIcon(self, icon, painter, rect):
""" draw icon """ """ draw icon """
drawIcon(icon, painter, rect) drawIcon(icon, painter, rect)
...@@ -196,3 +237,85 @@ class ToolButton(QToolButton): ...@@ -196,3 +237,85 @@ class ToolButton(QToolButton):
class TransparentToolButton(ToolButton): class TransparentToolButton(ToolButton):
""" Transparent background tool button """ """ Transparent background tool button """
class DropDownButtonBase:
""" Drop down button base class """
def __init__(self, *args, **kwargs):
self._menu = None
def setMenu(self, menu: RoundMenu):
self._menu = menu
def menu(self) -> RoundMenu:
return self._menu
def _showMenu(self):
if not self.menu():
return
menu = self.menu()
# show menu
x = -menu.width()//2 + menu.layout().contentsMargins().left() + self.width()//2
y = self.height()
menu.exec(self.mapToGlobal(QPoint(x, y)))
def _hideMenu(self):
if self.menu():
self.menu().hide()
def paintEvent(self, e):
painter = QPainter(self)
painter.setRenderHints(QPainter.Antialiasing)
if self.isHover:
painter.setOpacity(0.8)
elif self.isPressed:
painter.setOpacity(0.7)
rect = QRectF(self.width()-22, self.height()/2-5, 10, 10)
if isDarkTheme():
FIF.ARROW_DOWN.render(painter, rect)
else:
FIF.ARROW_DOWN.render(painter, rect, fill="#646464")
class DropDownPushButton(PushButton, DropDownButtonBase):
""" Drop down push button """
def setMenu(self, menu: RoundMenu):
DropDownButtonBase.setMenu(self, menu)
def mouseReleaseEvent(self, e):
super().mouseReleaseEvent(e)
self._showMenu()
def menu(self):
return DropDownButtonBase.menu(self)
def paintEvent(self, e):
PushButton.paintEvent(self, e)
DropDownButtonBase.paintEvent(self, e)
class DropDownToolButton(ToolButton, DropDownButtonBase):
""" Drop down tool button """
def setMenu(self, menu: RoundMenu):
DropDownButtonBase.setMenu(self, menu)
def mouseReleaseEvent(self, e):
super().mouseReleaseEvent(e)
self._showMenu()
def menu(self):
return DropDownButtonBase.menu(self)
def _drawIcon(self, icon, painter, rect: QRectF):
rect.moveLeft(12)
return super()._drawIcon(icon, painter, rect)
def paintEvent(self, e):
ToolButton.paintEvent(self, e)
DropDownButtonBase.paintEvent(self, e)
\ No newline at end of file
...@@ -5,7 +5,7 @@ from PyQt5.QtCore import Qt, pyqtSignal, QRectF, QPoint, QObject, QEvent ...@@ -5,7 +5,7 @@ from PyQt5.QtCore import Qt, pyqtSignal, QRectF, QPoint, QObject, QEvent
from PyQt5.QtGui import QPainter, QCursor, QIcon from PyQt5.QtGui import QPainter, QCursor, QIcon
from PyQt5.QtWidgets import QAction, QPushButton, QStyledItemDelegate, QStyle from PyQt5.QtWidgets import QAction, QPushButton, QStyledItemDelegate, QStyle
from .menu import RoundMenu from .menu import RoundMenu, MenuItemDelegate
from .line_edit import LineEdit, LineEditButton from .line_edit import LineEdit, LineEditButton
from ...common.icon import FluentIconBase, isDarkTheme from ...common.icon import FluentIconBase, isDarkTheme
from ...common.icon import FluentIcon as FIF from ...common.icon import FluentIcon as FIF
...@@ -397,7 +397,7 @@ class EditableComboBox(LineEdit, ComboBoxBase): ...@@ -397,7 +397,7 @@ class EditableComboBox(LineEdit, ComboBoxBase):
self.dropMenu = None self.dropMenu = None
class ComboMenuItemDelegate(QStyledItemDelegate): class ComboMenuItemDelegate(MenuItemDelegate):
""" Combo box drop menu item delegate """ """ Combo box drop menu item delegate """
def paint(self, painter: QPainter, option, index): def paint(self, painter: QPainter, option, index):
......
...@@ -58,6 +58,7 @@ class LineEdit(QLineEdit): ...@@ -58,6 +58,7 @@ class LineEdit(QLineEdit):
super().__init__(parent=parent) super().__init__(parent=parent)
self._isClearButtonEnabled = False self._isClearButtonEnabled = False
self.setProperty("transparent", True)
FluentStyleSheet.LINE_EDIT.apply(self) FluentStyleSheet.LINE_EDIT.apply(self)
self.setFixedHeight(33) self.setFixedHeight(33)
self.setAttribute(Qt.WA_MacShowFocusRect, False) self.setAttribute(Qt.WA_MacShowFocusRect, False)
......
# coding:utf-8 # coding:utf-8
from typing import List, Union
from qframelesswindow import WindowEffect from qframelesswindow import WindowEffect
from PyQt5.QtCore import (QEasingCurve, QEvent, QPropertyAnimation, QRect, from PyQt5.QtCore import (QEasingCurve, QEvent, QPropertyAnimation, QRect,
Qt, QSize, QRectF, pyqtSignal, QPoint, QTimer) Qt, QSize, QRectF, pyqtSignal, QPoint, QTimer, QModelIndex)
from PyQt5.QtGui import QIcon, QColor, QPainter, QPen, QPixmap, QRegion, QCursor, QTextCursor from PyQt5.QtGui import QIcon, QColor, QPainter, QPen, QPixmap, QRegion, QCursor, QTextCursor, QHoverEvent
from PyQt5.QtWidgets import (QAction, QApplication, QMenu, QProxyStyle, QStyle, from PyQt5.QtWidgets import (QAction, QApplication, QMenu, QProxyStyle, QStyle,
QGraphicsDropShadowEffect, QListWidget, QWidget, QHBoxLayout, QGraphicsDropShadowEffect, QListWidget, QWidget, QHBoxLayout,
QListWidgetItem, QLineEdit, QTextEdit) QListWidgetItem, QLineEdit, QTextEdit, QStyledItemDelegate, QStyleOptionViewItem)
from ...common.smooth_scroll import SmoothScroll from ...common.smooth_scroll import SmoothScroll
from ...common.icon import FluentIcon as FIF from ...common.icon import FluentIcon as FIF
from ...common.icon import MenuIconEngine from ...common.icon import MenuIconEngine, Action, FluentIconBase, Icon
from ...common.style_sheet import FluentStyleSheet from ...common.style_sheet import FluentStyleSheet
from ...common.config import isDarkTheme from ...common.config import isDarkTheme
...@@ -52,21 +54,6 @@ class DWMMenu(QMenu): ...@@ -52,21 +54,6 @@ class DWMMenu(QMenu):
return QMenu.event(self, e) return QMenu.event(self, e)
class MenuSeparator(QWidget):
""" Menu separator """
def __init__(self, parent=None):
super().__init__(parent=parent)
self.setFixedHeight(9)
def paintEvent(self, e):
painter = QPainter(self)
c = 0 if not isDarkTheme() else 255
pen = QPen(QColor(c, c, c, 25), 1)
pen.setCosmetic(True)
painter.setPen(pen)
painter.drawLine(0, 4, self.width(), 4)
class SubMenuItemWidget(QWidget): class SubMenuItemWidget(QWidget):
""" Sub menu item """ """ Sub menu item """
...@@ -103,12 +90,32 @@ class SubMenuItemWidget(QWidget): ...@@ -103,12 +90,32 @@ class SubMenuItemWidget(QWidget):
self.width()-10, self.height()/2-9/2, 9, 9)) self.width()-10, self.height()/2-9/2, 9, 9))
class MenuItemDelegate(QStyledItemDelegate):
""" Menu item delegate """
def paint(self, painter, option, index):
if index.model().data(index, Qt.DecorationRole) != "seperator":
return super().paint(painter, option, index)
# draw seperator
painter.save()
c = 0 if not isDarkTheme() else 255
pen = QPen(QColor(c, c, c, 25), 1)
pen.setCosmetic(True)
painter.setPen(pen)
rect = option.rect
painter.drawLine(0, rect.y() + 4, rect.width() + 12, rect.y() + 4)
painter.restore()
class MenuActionListWidget(QListWidget): class MenuActionListWidget(QListWidget):
""" Menu action list widget """ """ Menu action list widget """
def __init__(self, parent=None): def __init__(self, parent=None):
super().__init__(parent) super().__init__(parent)
self.setViewportMargins(5, 6, 5, 6) self.setViewportMargins(0, 6, 0, 6)
self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.setTextElideMode(Qt.ElideNone) self.setTextElideMode(Qt.ElideNone)
...@@ -116,6 +123,8 @@ class MenuActionListWidget(QListWidget): ...@@ -116,6 +123,8 @@ class MenuActionListWidget(QListWidget):
self.setMouseTracking(True) self.setMouseTracking(True)
self.setVerticalScrollMode(self.ScrollPerPixel) self.setVerticalScrollMode(self.ScrollPerPixel)
self.setIconSize(QSize(14, 14)) self.setIconSize(QSize(14, 14))
self.setItemDelegate(MenuItemDelegate(self))
self.smoothScroll = SmoothScroll(self) self.smoothScroll = SmoothScroll(self)
self.setStyleSheet( self.setStyleSheet(
'MenuActionListWidget{font: 14px "Segoe UI", "Microsoft YaHei"}') 'MenuActionListWidget{font: 14px "Segoe UI", "Microsoft YaHei"}')
...@@ -179,7 +188,7 @@ class RoundMenu(QWidget): ...@@ -179,7 +188,7 @@ class RoundMenu(QWidget):
super().__init__(parent=parent) super().__init__(parent=parent)
self._title = title self._title = title
self._icon = QIcon() self._icon = QIcon()
self._actions = [] self._actions = [] # type: List[QAction]
self._subMenus = [] self._subMenus = []
self.isSubMenu = False self.isSubMenu = False
self.parentMenu = None self.parentMenu = None
...@@ -253,11 +262,14 @@ class RoundMenu(QWidget): ...@@ -253,11 +262,14 @@ class RoundMenu(QWidget):
for i in range(len(self._actions)-1, -1, -1): for i in range(len(self._actions)-1, -1, -1):
self.removeAction(self._actions[i]) self.removeAction(self._actions[i])
def setIcon(self, icon): def setIcon(self, icon: Union[QIcon, FluentIconBase]):
""" set the icon of menu """ """ set the icon of menu """
if isinstance(icon, FluentIconBase):
icon = Icon(icon)
self._icon = icon self._icon = icon
def addAction(self, action): def addAction(self, action: Union[QAction, Action]):
""" add action to menu """ add action to menu
Parameters Parameters
...@@ -310,7 +322,7 @@ class RoundMenu(QWidget): ...@@ -310,7 +322,7 @@ class RoundMenu(QWidget):
return icon return icon
def insertAction(self, before, action): def insertAction(self, before: Union[QAction, Action], action: Union[QAction, Action]):
""" inserts action to menu, before the action before """ """ inserts action to menu, before the action before """
if before not in self._actions: if before not in self._actions:
return return
...@@ -324,7 +336,7 @@ class RoundMenu(QWidget): ...@@ -324,7 +336,7 @@ class RoundMenu(QWidget):
self.view.insertItem(index, item) self.view.insertItem(index, item)
self.adjustSize() self.adjustSize()
def addActions(self, actions): def addActions(self, actions: List[Union[QAction, Action]]):
""" add actions to menu """ add actions to menu
Parameters Parameters
...@@ -335,12 +347,12 @@ class RoundMenu(QWidget): ...@@ -335,12 +347,12 @@ class RoundMenu(QWidget):
for action in actions: for action in actions:
self.addAction(action) self.addAction(action)
def insertActions(self, before, actions): def insertActions(self, before: Union[QAction, Action], actions: List[Union[QAction, Action]]):
""" inserts the actions actions to menu, before the action before """ """ inserts the actions actions to menu, before the action before """
for action in actions: for action in actions:
self.insertAction(before, action) self.insertAction(before, action)
def removeAction(self, action): def removeAction(self, action: Union[QAction, Action]):
""" remove action from menu """ """ remove action from menu """
if action not in self._actions: if action not in self._actions:
return return
...@@ -356,7 +368,7 @@ class RoundMenu(QWidget): ...@@ -356,7 +368,7 @@ class RoundMenu(QWidget):
if widget: if widget:
widget.deleteLater() widget.deleteLater()
def setDefaultAction(self, action): def setDefaultAction(self, action: Union[QAction, Action]):
""" set the default action """ """ set the default action """
if action not in self._actions: if action not in self._actions:
return return
...@@ -380,7 +392,7 @@ class RoundMenu(QWidget): ...@@ -380,7 +392,7 @@ class RoundMenu(QWidget):
self.view.setItemWidget(item, w) self.view.setItemWidget(item, w)
self.adjustSize() self.adjustSize()
def insertMenu(self, before, menu): def insertMenu(self, before: Union[QAction, Action], menu):
""" insert menu before action `before` """ """ insert menu before action `before` """
if not isinstance(menu, RoundMenu): if not isinstance(menu, RoundMenu):
raise ValueError('`menu` should be an instance of `RoundMenu`.') raise ValueError('`menu` should be an instance of `RoundMenu`.')
...@@ -398,11 +410,11 @@ class RoundMenu(QWidget): ...@@ -398,11 +410,11 @@ class RoundMenu(QWidget):
item = QListWidgetItem(self._createItemIcon(menu), menu.title()) item = QListWidgetItem(self._createItemIcon(menu), menu.title())
if not self._hasItemIcon(): if not self._hasItemIcon():
w = 48 + self.view.fontMetrics().width(menu.title()) w = 60 + self.view.fontMetrics().width(menu.title())
else: else:
# add a blank character to increase space between icon and text # add a blank character to increase space between icon and text
item.setText(" " + item.text()) item.setText(" " + item.text())
w = 60 + self.view.fontMetrics().width(item.text()) w = 72 + self.view.fontMetrics().width(item.text())
# add submenu item # add submenu item
menu._setParentMenu(self, item) menu._setParentMenu(self, item)
...@@ -439,16 +451,12 @@ class RoundMenu(QWidget): ...@@ -439,16 +451,12 @@ class RoundMenu(QWidget):
m = self.view.viewportMargins() m = self.view.viewportMargins()
w = self.view.width()-m.left()-m.right() w = self.view.width()-m.left()-m.right()
# icon separator
separator = MenuSeparator(self.view)
separator.resize(w, separator.height())
# add separator to list widget # add separator to list widget
item = QListWidgetItem(self.view) item = QListWidgetItem(self.view)
item.setFlags(Qt.NoItemFlags) item.setFlags(Qt.NoItemFlags)
item.setSizeHint(QSize(w, separator.height())) item.setSizeHint(QSize(w, 9))
self.view.addItem(item) self.view.addItem(item)
self.view.setItemWidget(item, separator) item.setData(Qt.DecorationRole, "seperator")
self.adjustSize() self.adjustSize()
def _onItemClicked(self, item): def _onItemClicked(self, item):
...@@ -468,12 +476,10 @@ class RoundMenu(QWidget): ...@@ -468,12 +476,10 @@ class RoundMenu(QWidget):
def _closeParentMenu(self): def _closeParentMenu(self):
menu = self menu = self
while menu.parentMenu: while menu:
menu.close() menu.close()
menu = menu.parentMenu menu = menu.parentMenu
menu.close()
def _onItemEntered(self, item): def _onItemEntered(self, item):
self.lastHoverItem = item self.lastHoverItem = item
if not isinstance(item.data(Qt.UserRole), RoundMenu): if not isinstance(item.data(Qt.UserRole), RoundMenu):
...@@ -499,6 +505,7 @@ class RoundMenu(QWidget): ...@@ -499,6 +505,7 @@ class RoundMenu(QWidget):
def closeEvent(self, e): def closeEvent(self, e):
e.accept() e.accept()
self.closedSignal.emit() self.closedSignal.emit()
self.view.clearSelection()
def menuActions(self): def menuActions(self):
return self._actions return self._actions
...@@ -525,13 +532,6 @@ class RoundMenu(QWidget): ...@@ -525,13 +532,6 @@ class RoundMenu(QWidget):
view.clearSelection() view.clearSelection()
self._hideMenu(False) self._hideMenu(False)
# update style
index = view.row(self.menuItem)
if index > 0:
view.item(index-1).setFlags(Qt.ItemIsEnabled)
if index < view.count()-1:
view.item(index+1).setFlags(Qt.ItemIsEnabled)
def _onActionChanged(self): def _onActionChanged(self):
""" action changed slot """ """ action changed slot """
action = self.sender() action = self.sender()
...@@ -557,6 +557,12 @@ class RoundMenu(QWidget): ...@@ -557,6 +557,12 @@ class RoundMenu(QWidget):
y = self.ani.endValue().y() - pos.y() y = self.ani.endValue().y() - pos.y()
self.setMask(QRegion(0, y, w, h)) self.setMask(QRegion(0, y, w, h))
# update view port
self.view.viewport().update()
self.view.setAttribute(Qt.WA_UnderMouse, True)
e = QHoverEvent(QEvent.HoverEnter, QPoint(), QPoint(1, 1))
QApplication.sendEvent(self.view, e)
def exec(self, pos, ani=True): def exec(self, pos, ani=True):
""" show menu """ show menu
...@@ -588,18 +594,8 @@ class RoundMenu(QWidget): ...@@ -588,18 +594,8 @@ class RoundMenu(QWidget):
self.show() self.show()
if not self.isSubMenu: if self.isSubMenu:
return self.menuItem.setSelected(True)
self.menuItem.setSelected(True)
# temporarily disable item to change style
view = self.parentMenu.view
index = view.row(self.menuItem)
if index > 0:
view.item(index-1).setFlags(Qt.NoItemFlags)
if index < view.count()-1:
view.item(index+1).setFlags(Qt.NoItemFlags)
def exec_(self, pos: QPoint, ani=True): def exec_(self, pos: QPoint, ani=True):
""" show menu """ show menu
......
# coding: utf-8 # coding: utf-8
from enum import Enum from enum import Enum
from PyQt5.QtCore import Qt, QTimer, pyqtProperty, pyqtSignal from PyQt5.QtCore import Qt, QTimer, pyqtProperty, pyqtSignal, QEvent, QPoint
from PyQt5.QtGui import QColor, QPainter from PyQt5.QtGui import QColor, QPainter, QHoverEvent
from PyQt5.QtWidgets import QHBoxLayout, QLabel, QToolButton, QWidget from PyQt5.QtWidgets import QApplication, QHBoxLayout, QLabel, QToolButton, QWidget
from ...common.style_sheet import FluentStyleSheet from ...common.style_sheet import FluentStyleSheet
from ...common.overload import singledispatchmethod from ...common.overload import singledispatchmethod
...@@ -58,6 +58,9 @@ class Indicator(QToolButton): ...@@ -58,6 +58,9 @@ class Indicator(QToolButton):
self.padding if isChecked else self.padding self.padding if isChecked else self.padding
self.timer.start(5) self.timer.start(5)
def toggle(self):
self.setChecked(not self.isChecked())
def mouseReleaseEvent(self, e): def mouseReleaseEvent(self, e):
""" toggle checked state when mouse release""" """ toggle checked state when mouse release"""
super().mouseReleaseEvent(e) super().mouseReleaseEvent(e)
...@@ -170,10 +173,11 @@ class SwitchButton(QWidget): ...@@ -170,10 +173,11 @@ class SwitchButton(QWidget):
def __initWidget(self): def __initWidget(self):
""" initialize widgets """ """ initialize widgets """
self.setAttribute(Qt.WA_StyledBackground) self.setAttribute(Qt.WA_StyledBackground)
self.installEventFilter(self)
# set layout # set layout
self.hBox.setSpacing(self.__spacing) self.hBox.setSpacing(self.__spacing)
self.hBox.setContentsMargins(0, 0, 0, 0) self.hBox.setContentsMargins(2, 0, 0, 0)
if self.indicatorPos == IndicatorPosition.LEFT: if self.indicatorPos == IndicatorPosition.LEFT:
self.hBox.addWidget(self.indicator) self.hBox.addWidget(self.indicator)
...@@ -188,7 +192,25 @@ class SwitchButton(QWidget): ...@@ -188,7 +192,25 @@ class SwitchButton(QWidget):
FluentStyleSheet.SWITCH_BUTTON.apply(self) FluentStyleSheet.SWITCH_BUTTON.apply(self)
# connect signal to slot # connect signal to slot
self.indicator.checkedChanged.connect(self.checkedChanged) self.indicator.toggled.connect(self.checkedChanged)
def eventFilter(self, obj, e: QEvent):
if obj is self:
if e.type() == QEvent.MouseButtonPress:
self.indicator.setDown(True)
elif e.type() == QEvent.MouseButtonRelease:
self.indicator.setDown(False)
self.indicator.toggle()
elif e.type() == QEvent.Enter:
self.indicator.setAttribute(Qt.WA_UnderMouse, True)
e = QHoverEvent(QEvent.HoverEnter, QPoint(), QPoint(1, 1))
QApplication.sendEvent(self.indicator, e)
elif e.type() == QEvent.Leave:
self.indicator.setAttribute(Qt.WA_UnderMouse, False)
e = QHoverEvent(QEvent.HoverLeave, QPoint(1, 1), QPoint())
QApplication.sendEvent(self.indicator, e)
return super().eventFilter(obj, e)
def isChecked(self): def isChecked(self):
return self.indicator.isChecked() return self.indicator.isChecked()
......
# coding: utf-8
from PyQt5 import QtGui
from PyQt5.QtCore import Qt, QMargins, QModelIndex
from PyQt5.QtGui import QPainter, QColor
from PyQt5.QtWidgets import (QStyledItemDelegate, QApplication, QStyleOptionViewItem,
QTableView, QTableWidget, QWidget)
from ...common.smooth_scroll import SmoothScroll
from ...common.style_sheet import isDarkTheme, FluentStyleSheet, themeColor
from .line_edit import LineEdit
from .scroll_area import SmoothScrollBar
class TableItemDelegate(QStyledItemDelegate):
def __init__(self, parent: QTableView):
super().__init__(parent)
self.margin = 2
self.hoverRow = -1
self.pressedRow = -1
self.currentRow = -1
def setHoverRow(self, row: int):
self.hoverRow = row
def setPressedRow(self, row: int):
self.pressedRow = row
def setCurrentRow(self, row: int):
self.currentRow = row
if row == self.pressedRow:
self.pressedRow = -1
def sizeHint(self, option, index):
# increase original sizeHint to accommodate space needed for border
size = super().sizeHint(option, index)
size = size.grownBy(QMargins(0, self.margin, 0, self.margin))
return size
def createEditor(self, parent: QWidget, option: QStyleOptionViewItem, index: QModelIndex) -> QWidget:
lineEdit = LineEdit(parent)
lineEdit.setProperty("transparent", False)
lineEdit.setStyle(QApplication.style())
lineEdit.setText(option.text)
lineEdit.setClearButtonEnabled(True)
return lineEdit
def updateEditorGeometry(self, editor: QWidget, option: QStyleOptionViewItem, index: QModelIndex):
rect = option.rect
h = super().sizeHint(option, index).height()
y = rect.y() + self.margin + (h - editor.height()) // 2
x, w = max(4, rect.x()), rect.width()
if index.column() == 0:
w -= 4
editor.setGeometry(x, y, w, rect.height())
def _drawBackground(self, painter: QPainter, option: QStyleOptionViewItem, index: QModelIndex):
""" draw row background """
r = 5
if index.column() == 0:
rect = option.rect.adjusted(4, 0, r + 1, 0)
painter.drawRoundedRect(rect, r, r)
elif index.column() == index.model().columnCount(index.parent()) - 1:
rect = option.rect.adjusted(-r - 1, 0, -4, 0)
painter.drawRoundedRect(rect, r, r)
else:
rect = option.rect.adjusted(-1, 0, 1, 0)
painter.drawRect(rect)
def paint(self, painter, option, index):
painter.save()
painter.setPen(Qt.NoPen)
painter.setRenderHint(QPainter.Antialiasing)
# set clipping rect of painter to avoid painting outside the borders
painter.setClipping(True)
painter.setClipRect(option.rect)
# call original paint method where option.rect is adjusted to account for border
option.rect.adjust(0, self.margin, 0, -self.margin)
# draw highlight background
isHover = self.hoverRow == index.row()
isPressed = self.pressedRow == index.row()
isAlternate = index.row() % 2 == 0
isDark = isDarkTheme()
c = 255 if isDark else 0
alpha = 0
if self.currentRow != index.row():
if isPressed:
alpha = 9 if isDark else 6
elif isHover:
alpha = 12
elif isAlternate:
alpha = 5
else:
if isPressed:
alpha = 15 if isDark else 9
elif isHover:
alpha = 25
else:
alpha = 17
# draw indicator
if index.column() == 0 and self.parent().horizontalScrollBar().value() == 0:
y, h = option.rect.y() ,option.rect.height()
ph = round(0.35*h if isPressed else 0.257*h)
painter.setBrush(themeColor())
painter.drawRoundedRect(4, ph + y, 3, h - 2*ph, 1.5, 1.5)
painter.setBrush(QColor(c, c, c, alpha))
self._drawBackground(painter, option, index)
painter.restore()
super().paint(painter, option, index)
class TableBase:
""" Table base class """
def __init__(self, *args, **kwargs):
self.delegate = TableItemDelegate(self)
self.verticalSmoothScroll = SmoothScroll(self, Qt.Vertical)
self.horizonSmoothScroll = SmoothScroll(self, Qt.Horizontal)
# set style sheet
FluentStyleSheet.TABLE_VIEW.apply(self)
FluentStyleSheet.TABLE_VIEW.apply(self.verticalScrollBar())
FluentStyleSheet.TABLE_VIEW.apply(self.horizontalScrollBar())
self.setShowGrid(False)
self.setMouseTracking(True)
self.setItemDelegate(self.delegate)
self.setVerticalScrollMode(QTableView.ScrollPerPixel)
self.setHorizontalScrollMode(QTableView.ScrollPerPixel)
self.entered.connect(lambda i: self.setHoverRow(i.row()))
self.pressed.connect(lambda i: self.setPressedRow(i.row()))
def showEvent(self, e):
QTableView.showEvent(self, e)
self.resizeRowsToContents()
def setHoverRow(self, row: int):
""" set hovered row """
self.delegate.setHoverRow(row)
self.viewport().update()
def setPressedRow(self, row: int):
""" set pressed row """
self.delegate.setPressedRow(row)
self.viewport().update()
def setCurrentRow(self, row: int):
self.delegate.setCurrentRow(row)
self.viewport().update()
def leaveEvent(self, e):
QTableView.leaveEvent(self, e)
self.setHoverRow(-1)
def resizeEvent(self, e):
QTableView.resizeEvent(self, e)
self.viewport().update()
def wheelEvent(self, e):
if e.angleDelta().y() != 0:
self.verticalSmoothScroll.wheelEvent(e)
else:
self.horizonSmoothScroll.wheelEvent(e)
e.setAccepted(True)
def mouseReleaseEvent(self, e):
row = self.indexAt(e.pos()).row()
if row >= 0 and e.button() != Qt.RightButton:
self.setCurrentRow(row)
else:
self.setPressedRow(-1)
return TableView.mouseReleaseEvent(self, e)
class TableWidget(QTableWidget, TableBase):
""" Table widget """
def __init__(self, parent=None):
super().__init__(parent)
class TableView(QTableView, TableBase):
""" Table view """
def __init__(self, parent=None):
super().__init__(parent)
# coding:utf-8 # coding:utf-8
import typing
from PyQt5 import QtCore
from PyQt5.QtCore import Qt, QSize from PyQt5.QtCore import Qt, QSize
from PyQt5.QtGui import QPainter, QColor from PyQt5.QtGui import QPainter, QColor
from PyQt5.QtWidgets import QWidget, QTreeWidget, QStyledItemDelegate, QStyle, QTreeView from PyQt5.QtWidgets import QWidget, QTreeWidget, QStyledItemDelegate, QStyle, QTreeView
...@@ -10,6 +12,9 @@ from ...common.smooth_scroll import SmoothScroll ...@@ -10,6 +12,9 @@ from ...common.smooth_scroll import SmoothScroll
class TreeItemDelegate(QStyledItemDelegate): class TreeItemDelegate(QStyledItemDelegate):
""" Tree item delegate """ """ Tree item delegate """
def __init__(self, parent: QTreeView):
super().__init__(parent)
def paint(self, painter, option, index): def paint(self, painter, option, index):
painter.setRenderHints( painter.setRenderHints(
QPainter.Antialiasing | QPainter.TextAntialiasing) QPainter.Antialiasing | QPainter.TextAntialiasing)
...@@ -29,55 +34,51 @@ class TreeItemDelegate(QStyledItemDelegate): ...@@ -29,55 +34,51 @@ class TreeItemDelegate(QStyledItemDelegate):
4, option.rect.y() + 2, self.parent().width() - 8, h, 4, 4) 4, option.rect.y() + 2, self.parent().width() - 8, h, 4, 4)
# draw indicator # draw indicator
if option.state & QStyle.State_Selected: if option.state & QStyle.State_Selected and self.parent().horizontalScrollBar().value() == 0:
painter.setBrush(themeColor()) painter.setBrush(themeColor())
painter.drawRoundedRect(4, 9+option.rect.y(), 3, h - 13, 1.5, 1.5) painter.drawRoundedRect(4, 9+option.rect.y(), 3, h - 13, 1.5, 1.5)
painter.restore() painter.restore()
class TreeWidget(QTreeWidget): class TreeViewBase:
""" Tree widget """ """ Tree view base class """
def __init__(self, parent=None): def __init__(self, *args, **kwargs):
super().__init__(parent=parent)
self.verticalSmoothScroll = SmoothScroll(self, Qt.Vertical) self.verticalSmoothScroll = SmoothScroll(self, Qt.Vertical)
self.horizonSmoothScroll = SmoothScroll(self, Qt.Horizontal) self.horizonSmoothScroll = SmoothScroll(self, Qt.Horizontal)
self.setHorizontalScrollMode(QTreeView.ScrollPerPixel)
self.setVerticalScrollMode(QTreeView.ScrollPerPixel)
self.setItemDelegate(TreeItemDelegate(self)) self.setItemDelegate(TreeItemDelegate(self))
self.setIconSize(QSize(16, 16)) self.setIconSize(QSize(16, 16))
FluentStyleSheet.TREE_VIEW.apply(self) FluentStyleSheet.TREE_VIEW.apply(self)
FluentStyleSheet.TREE_VIEW.apply(self.verticalScrollBar())
FluentStyleSheet.TREE_VIEW.apply(self.horizontalScrollBar())
def drawBranches(self, painter, rect, index): def drawBranches(self, painter, rect, index):
rect.moveLeft(15) rect.moveLeft(15)
return super().drawBranches(painter, rect, index) return QTreeView.drawBranches(self, painter, rect, index)
def wheelEvent(self, e): def wheelEvent(self, e):
if e.modifiers() == Qt.NoModifier: if e.angleDelta().y() != 0:
self.verticalSmoothScroll.wheelEvent(e) self.verticalSmoothScroll.wheelEvent(e)
else: else:
self.horizonSmoothScroll.wheelEvent(e) self.horizonSmoothScroll.wheelEvent(e)
e.setAccepted(True)
class TreeView(QTreeView):
""" Tree view """ class TreeWidget(QTreeWidget, TreeViewBase):
""" Tree widget """
def __init__(self, parent=None): def __init__(self, parent=None):
super().__init__(parent=parent) super().__init__(parent=parent)
self.verticalSmoothScroll = SmoothScroll(self, Qt.Vertical)
self.horizonSmoothScroll = SmoothScroll(self, Qt.Horizontal)
self.setItemDelegate(TreeItemDelegate(self))
self.setIconSize(QSize(16, 16))
FluentStyleSheet.TREE_VIEW.apply(self)
FluentStyleSheet.TREE_VIEW.apply(self.verticalScrollBar())
def drawBranches(self, painter, rect, index): class TreeView(QTreeView, TreeViewBase):
rect.moveLeft(15) """ Tree view """
return super().drawBranches(painter, rect, index)
def wheelEvent(self, e): def __init__(self, parent=None):
if e.modifiers() == Qt.NoModifier: super().__init__(parent=parent)
self.verticalSmoothScroll.wheelEvent(e)
else:
self.horizonSmoothScroll.wheelEvent(e)
...@@ -6,7 +6,7 @@ with open('README.md', encoding='utf-8') as f: ...@@ -6,7 +6,7 @@ with open('README.md', encoding='utf-8') as f:
setuptools.setup( setuptools.setup(
name="PyQt-Fluent-Widgets", name="PyQt-Fluent-Widgets",
version="0.7.6", version="0.8.0",
keywords="pyqt fluent widgets", keywords="pyqt fluent widgets",
author="zhiyiYo", author="zhiyiYo",
author_email="shokokawaii@outlook.com", author_email="shokokawaii@outlook.com",
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册