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

添加日历组件

上级 d557dfd2
# coding:utf-8
import sys
from time import time
from PyQt5.QtCore import Qt, QCalendar, QDate
from PyQt5.QtWidgets import QApplication, QWidget, QHBoxLayout
from qfluentwidgets import CalendarPicker, setTheme, Theme
class Demo(QWidget):
def __init__(self):
super().__init__()
# setTheme(Theme.DARK)
self.setStyleSheet('Demo{background: white}')
self.picker = CalendarPicker(self)
self.picker.dateChanged.connect(print)
# set date
# self.picker.setDate(QDate(2023, 5, 30))
# customize date format
# self.picker.setDateFormat(Qt.TextDate)
# self.picker.setDateFormat('yyyy-M-d')
self.hBoxLayout = QHBoxLayout(self)
self.hBoxLayout.addWidget(self.picker, 0, Qt.AlignCenter)
self.resize(500, 500)
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)
t0 = time()
w = Demo()
t1 = time()
print('耗时:', t1-t0)
w.show()
app.exec_()
\ No newline at end of file
因为 它太大了无法显示 source diff 。你可以改为 查看blob
......@@ -217,30 +217,40 @@
<context>
<name>DateTimeInterface</name>
<message>
<location filename="../../view/date_time_interface.py" line="21"/>
<location filename="../../view/date_time_interface.py" line="36"/>
<source>A simple DatePicker</source>
<translation>日期选择器</translation>
</message>
<message>
<location filename="../../view/date_time_interface.py" line="27"/>
<location filename="../../view/date_time_interface.py" line="42"/>
<source>A DatePicker in another format</source>
<translation>另一种格式的日期选择器</translation>
</message>
<message>
<location filename="../../view/date_time_interface.py" line="34"/>
<location filename="../../view/date_time_interface.py" line="49"/>
<source>A simple TimePicker</source>
<translation>时间选择器</translation>
</message>
<message>
<location filename="../../view/date_time_interface.py" line="41"/>
<location filename="../../view/date_time_interface.py" line="56"/>
<source>A TimePicker using a 24-hour clock</source>
<translation>24 小时制的时间选择器</translation>
</message>
<message>
<location filename="../../view/date_time_interface.py" line="48"/>
<location filename="../../view/date_time_interface.py" line="63"/>
<source>A TimePicker with seconds column</source>
<translation>显示秒的时间选择器</translation>
</message>
<message>
<location filename="../../view/date_time_interface.py" line="21"/>
<source>A simple CalendarPicker</source>
<translation>日历选择器</translation>
</message>
<message>
<location filename="../../view/date_time_interface.py" line="29"/>
<source>A CalendarPicker in another format</source>
<translation>自定义格式的日历选择器</translation>
</message>
</context>
<context>
<name>DialogInterface</name>
......
......@@ -16,7 +16,7 @@
<message>
<location filename="../../view/basic_input_interface.py" line="56"/>
<source>A hyperlink button that navigates to a URI</source>
<translation>導航到一個超鏈接的按鈕</translation>
<translation>導航到一個超連結的按鈕</translation>
</message>
<message>
<location filename="../../view/basic_input_interface.py" line="63"/>
......@@ -96,7 +96,7 @@
<message>
<location filename="../../view/basic_input_interface.py" line="149"/>
<source>Soft and Wet</source>
<translation>軟又</translation>
<translation>軟又</translation>
</message>
<message>
<location filename="../../view/basic_input_interface.py" line="241"/>
......@@ -121,7 +121,7 @@
<message>
<location filename="../../view/basic_input_interface.py" line="107"/>
<source>Send</source>
<translation></translation>
<translation></translation>
</message>
<message>
<location filename="../../view/basic_input_interface.py" line="108"/>
......@@ -217,30 +217,40 @@
<context>
<name>DateTimeInterface</name>
<message>
<location filename="../../view/date_time_interface.py" line="21"/>
<location filename="../../view/date_time_interface.py" line="36"/>
<source>A simple DatePicker</source>
<translation>日期選擇器</translation>
</message>
<message>
<location filename="../../view/date_time_interface.py" line="27"/>
<location filename="../../view/date_time_interface.py" line="42"/>
<source>A DatePicker in another format</source>
<translation>另一種格式的日期選擇器</translation>
</message>
<message>
<location filename="../../view/date_time_interface.py" line="34"/>
<location filename="../../view/date_time_interface.py" line="49"/>
<source>A simple TimePicker</source>
<translation>時間選擇器</translation>
</message>
<message>
<location filename="../../view/date_time_interface.py" line="41"/>
<location filename="../../view/date_time_interface.py" line="56"/>
<source>A TimePicker using a 24-hour clock</source>
<translation>24 小時的時間選擇器</translation>
<translation>24 小時的時間選擇器</translation>
</message>
<message>
<location filename="../../view/date_time_interface.py" line="48"/>
<location filename="../../view/date_time_interface.py" line="63"/>
<source>A TimePicker with seconds column</source>
<translation>顯示秒的時間選擇器</translation>
</message>
<message>
<location filename="../../view/date_time_interface.py" line="21"/>
<source>A simple CalendarPicker</source>
<translation>日曆選擇器</translation>
</message>
<message>
<location filename="../../view/date_time_interface.py" line="29"/>
<source>A CalendarPicker in another format</source>
<translation>自定義格式的日曆選擇器</translation>
</message>
</context>
<context>
<name>DialogInterface</name>
......@@ -290,7 +300,7 @@
<message>
<location filename="../../view/gallery_interface.py" line="114"/>
<source>Source code</source>
<translation>源代</translation>
<translation>原始</translation>
</message>
</context>
<context>
......@@ -354,7 +364,7 @@
<message>
<location filename="../../view/layout_interface.py" line="38"/>
<source>Killer Queen</source>
<translation>殺手皇💀</translation>
<translation>殺手皇💀</translation>
</message>
<message>
<location filename="../../view/layout_interface.py" line="39"/>
......@@ -382,7 +392,7 @@
<message>
<location filename="../../view/icon_interface.py" line="21"/>
<source>Search icons</source>
<translation>索圖標</translation>
<translation>索圖標</translation>
</message>
</context>
<context>
......@@ -485,7 +495,7 @@
<message>
<location filename="../../view/view_interface.py" line="85"/>
<source>Scary Monster</source>
<translation>駭人</translation>
<translation>駭人</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="85"/>
......@@ -525,7 +535,7 @@
<message>
<location filename="../../view/view_interface.py" line="89"/>
<source>SOFT &amp; WET</source>
<translation>軟又</translation>
<translation>軟又</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="89"/>
......@@ -535,7 +545,7 @@
<message>
<location filename="../../view/view_interface.py" line="90"/>
<source>Wonder of U</source>
<translation>於你</translation>
<translation>於你</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="90"/>
......@@ -565,7 +575,7 @@
<message>
<location filename="../../view/view_interface.py" line="79"/>
<source>Killer Queen</source>
<translation>殺手皇💀</translation>
<translation>殺手皇💀</translation>
</message>
</context>
<context>
......@@ -839,7 +849,7 @@
<message>
<location filename="../../view/setting_interface.py" line="85"/>
<source>Use system setting</source>
<translation>跟隨統設置</translation>
<translation>跟隨統設置</translation>
</message>
<message>
<location filename="../../view/setting_interface.py" line="67"/>
......@@ -854,7 +864,7 @@
<message>
<location filename="../../view/setting_interface.py" line="74"/>
<source>Interface zoom</source>
<translation>縮放</translation>
<translation>縮放</translation>
</message>
<message>
<location filename="../../view/setting_interface.py" line="74"/>
......@@ -869,7 +879,7 @@
<message>
<location filename="../../view/setting_interface.py" line="85"/>
<source>Set your preferred language for UI</source>
<translation>選擇界所使用的語言</translation>
<translation>選擇界所使用的語言</translation>
</message>
<message>
<location filename="../../view/setting_interface.py" line="95"/>
......@@ -894,7 +904,7 @@
<message>
<location filename="../../view/setting_interface.py" line="108"/>
<source>Check for updates when the application starts</source>
<translation>在應用程啟動時檢查更新</translation>
<translation>在應用程啟動時檢查更新</translation>
</message>
<message>
<location filename="../../view/setting_interface.py" line="108"/>
......@@ -909,7 +919,7 @@
<message>
<location filename="../../view/setting_interface.py" line="118"/>
<source>Open help page</source>
<translation>打開幫助頁</translation>
<translation>打開幫助頁</translation>
</message>
<message>
<location filename="../../view/setting_interface.py" line="118"/>
......@@ -919,7 +929,7 @@
<message>
<location filename="../../view/setting_interface.py" line="118"/>
<source>Discover new features and learn useful tips about PyQt-Fluent-Widgets</source>
<translation>現新功能並了解有關 PyQt-Fluent-Widgets 的使用技巧</translation>
<translation>現新功能並了解有關 PyQt-Fluent-Widgets 的使用技巧</translation>
</message>
<message>
<location filename="../../view/setting_interface.py" line="127"/>
......@@ -1002,7 +1012,7 @@
<message>
<location filename="../../view/status_info_interface.py" line="179"/>
<source>Please wait patiently</source>
<translation>心急吃不了熱請耐心等待哦~</translation>
<translation>心急吃不了熱請耐心等待哦~</translation>
</message>
<message>
<location filename="../../view/status_info_interface.py" line="181"/>
......@@ -1067,7 +1077,7 @@
<message>
<location filename="../../view/status_info_interface.py" line="75"/>
<source>My name is kira yoshikake, 33 years old. Living in the villa area northeast of duwangting, unmarried. I work in Guiyou chain store. Every day I have to work overtime until 8 p.m. to go home. I don&apos;t smoke. The wine is only for a taste. Sleep at 11 p.m. for 8 hours a day. Before I go to bed, I must drink a cup of warm milk, then do 20 minutes of soft exercise, get on the bed, and immediately fall asleep. Never leave fatigue and stress until the next day. Doctors say I&apos;m normal.</source>
<translation>我的名字是吉良吉影年齡33歲家住杜王町東北部別墅區未婚我在龜友百貨連鎖公司上班每天最晚也是八點前回家不吸菸酒也是淺嚐輒止晚上十一點上床保証八個小時的充足睡眠睡前喝一盃熱牛奶再做二十分鐘伸展運動暖身然後再睡覺基本可以熟睡到天亮像嬰兒一樣不留下疲勞與壓力迎來第二天的早晨健康檢查結果也顯示我很健康我的意思是我是一個隨時都想追求平靜生活的人不拘泥於勝負與煩惱不樹立令我夜不能寐的敵人這就是我對於這個社會的生活態度我也清楚這就是我的幸福</translation>
<translation>我的名字是吉良吉影年齡33歲家住杜王町東北部別墅區未婚我在龜友百貨連鎖公司上班每天最晚也是八點前回家不吸煙酒也是淺嘗輒止晚上十一點上床保證八個小時的充足睡眠睡前喝一杯熱牛奶再做二十分鐘伸展運動暖身然後再睡覺基本可以熟睡到天亮像嬰兒一樣不留下疲勞與壓力迎來第二天的早晨健康檢查結果也顯示我很健康我的意思是我是一個隨時都想追求平靜生活的人不拘泥於勝負與煩惱不樹立令我夜不能寐的敵人這就是我對於這個社會的生活態度我也清楚這就是我的幸福</translation>
</message>
<message>
<location filename="../../view/status_info_interface.py" line="186"/>
......@@ -1077,16 +1087,16 @@
<message>
<location filename="../../view/status_info_interface.py" line="186"/>
<source>Believe in the spin, just keep believing!</source>
<translation>相信回旋吧管相信就是了</translation>
<translation>相信迴旋吧管相信就是了</translation>
</message>
<message>
<location filename="../../view/status_info_interface.py" line="198"/>
<source>With respect, let&apos;s advance towards a new stage of the spin.</source>
<translation>表達敬意吧表達出敬意然後邁向旋的另一個全新階段</translation>
<translation>表達敬意吧表達出敬意然後邁向旋的另一個全新階段</translation>
</message>
<message>
<location filename="../../view/status_info_interface.py" line="209"/>
<source>路を行けば最短ルート</source>
<source>路を行けば最短ルート</source>
<translation>最短的捷徑就是繞遠路繞遠路才是我的最短捷徑</translation>
</message>
<message>
......@@ -1251,7 +1261,7 @@
<message>
<location filename="../../view/gallery_interface.py" line="43"/>
<source>Source</source>
<translation>源代</translation>
<translation>原始</translation>
</message>
<message>
<location filename="../../view/gallery_interface.py" line="80"/>
......@@ -1347,7 +1357,7 @@
<message>
<location filename="../../view/view_interface.py" line="108"/>
<source>Dio Brando</source>
<translation>迪奧·蘭度</translation>
<translation>迪奧·蘭度</translation>
</message>
<message>
<location filename="../../view/view_interface.py" line="108"/>
......
# coding:utf-8
from PyQt5.QtCore import Qt
from qfluentwidgets import DatePicker, TimePicker, AMTimePicker, ZhDatePicker
from qfluentwidgets import DatePicker, TimePicker, AMTimePicker, ZhDatePicker, CalendarPicker
from .gallery_interface import GalleryInterface
from ..common.translator import Translator
......@@ -17,6 +17,21 @@ class DateTimeInterface(GalleryInterface):
parent=parent
)
# calendar picker
self.addExampleCard(
title=self.tr('A simple CalendarPicker'),
widget=CalendarPicker(self),
sourcePath='https://github.com/zhiyiYo/PyQt-Fluent-Widgets/blob/master/examples/calendar_picker/demo.py'
)
w = CalendarPicker(self)
w.setDateFormat(Qt.TextDate)
self.addExampleCard(
title=self.tr('A CalendarPicker in another format'),
widget=w,
sourcePath='https://github.com/zhiyiYo/PyQt-Fluent-Widgets/blob/master/examples/calendar_picker/demo.py'
)
# date picker
self.addExampleCard(
title=self.tr('A simple DatePicker'),
......
......@@ -194,12 +194,19 @@ class HomeInterface(ScrollArea):
# date time samples
dateTimeView = SampleCardView(self.tr('Date & time samples'), self.view)
dateTimeView.addSampleCard(
icon=":/gallery/images/controls/CalendarDatePicker.png",
title="CalendarPicker",
content=self.tr("A control that lets a user pick a date value using a calendar."),
routeKey="dateTimeInterface",
index=0
)
dateTimeView.addSampleCard(
icon=":/gallery/images/controls/DatePicker.png",
title="DatePicker",
content=self.tr("A control that lets a user pick a date value."),
routeKey="dateTimeInterface",
index=0
index=2
)
dateTimeView.addSampleCard(
icon=":/gallery/images/controls/TimePicker.png",
......@@ -207,7 +214,7 @@ class HomeInterface(ScrollArea):
content=self.tr(
"A configurable control that lets a user pick a time value."),
routeKey="dateTimeInterface",
index=2
index=4
)
self.vBoxLayout.addWidget(dateTimeView)
......
......@@ -28,7 +28,7 @@ class StatusInfoInterface(GalleryInterface):
self.addExampleCard(
self.tr('State tool tip'),
button,
'https://github.com/zhiyiYo/PyQt-Fluent-Widgets/blob/master/examples/status_tool_tip/demo.py'
'https://github.com/zhiyiYo/PyQt-Fluent-Widgets/blob/master/examples/state_tool_tip/demo.py'
)
# tool tip
......
......@@ -5,7 +5,7 @@ from qfluentwidgets import (PrimaryPushButton, SplitPushButton, DropDownPushButt
ToolButton, SplitToolButton, DropDownToolButton, FluentIcon, ToggleButton,
SwitchButton, RadioButton, CheckBox, HyperlinkButton, Slider, ComboBox, IconWidget,
EditableComboBox, PixmapLabel, PushButton, PrimaryToolButton, PrimarySplitToolButton,
PrimarySplitPushButton, PrimaryDropDownPushButton, PrimaryDropDownToolButton)
PrimarySplitPushButton, PrimaryDropDownPushButton, PrimaryDropDownToolButton, TransparentToolButton)
from plugin_base import PluginBase
from task_menu_factory import EditTextTaskMenuFactory
......@@ -206,6 +206,19 @@ class PrimaryToolButtonPlugin(BasicInputPlugin, QPyDesignerCustomWidgetPlugin):
return "PrimaryToolButton"
class TransparentToolButtonPlugin(BasicInputPlugin, QPyDesignerCustomWidgetPlugin):
""" Primary color tool button plugin """
def createWidget(self, parent):
return TransparentToolButton(FluentIcon.BASKETBALL, parent)
def icon(self):
return super().icon('Button')
def name(self):
return "TransparentToolButton"
class DropDownToolButtonPlugin(BasicInputPlugin, QPyDesignerCustomWidgetPlugin):
""" Drop down tool button plugin """
......
......@@ -2,7 +2,7 @@
from PyQt5.QtCore import Qt
from PyQt5.QtDesigner import QPyDesignerCustomWidgetPlugin
from qfluentwidgets import DatePicker, TimePicker, ZhDatePicker, AMTimePicker
from qfluentwidgets import DatePicker, TimePicker, ZhDatePicker, AMTimePicker, CalendarPicker
from plugin_base import PluginBase
......@@ -13,6 +13,19 @@ class DateTimePlugin(PluginBase):
return super().group() + ' (Date Time)'
class CalendarPickerPlugin(DateTimePlugin, QPyDesignerCustomWidgetPlugin):
""" Calendar picker plugin """
def createWidget(self, parent):
return CalendarPicker(parent)
def icon(self):
return super().icon("CalendarDatePicker")
def name(self):
return "CalendarPicker"
class DatePickerPlugin(DateTimePlugin, QPyDesignerCustomWidgetPlugin):
""" Date picker plugin """
......
......@@ -12,7 +12,7 @@ Examples are available at https://github.com/zhiyiYo/PyQt-Fluent-Widgets/tree/ma
:license: GPLv3, see LICENSE for more details.
"""
__version__ = "0.9.1"
__version__ = "0.9.2"
from .components import *
from .common import *
......
......@@ -2,6 +2,95 @@
<!DOCTYPE TS>
<TS version="2.1" language="zh_CN">
<!-- The translation of components in PyQt-Fluent-Widgets -->
<context>
<name>CalendarPicker</name>
<message>
<source>Pick a date</source>
<translation>选择日期</translation>
</message>
</context>
<context>
<name>MonthScrollView</name>
<message>
<source>Jan</source>
<translation>一月</translation>
</message>
<message>
<source>Feb</source>
<translation>二月</translation>
</message>
<message>
<source>Mar</source>
<translation>三月</translation>
</message>
<message>
<source>Apr</source>
<translation>四月</translation>
</message>
<message>
<source>May</source>
<translation>五月</translation>
</message>
<message>
<source>Jun</source>
<translation>六月</translation>
</message>
<message>
<source>Jul</source>
<translation>七月</translation>
</message>
<message>
<source>Aug</source>
<translation>八月</translation>
</message>
<message>
<source>Sep</source>
<translation>九月</translation>
</message>
<message>
<source>Oct</source>
<translation>十月</translation>
</message>
<message>
<source>Nov</source>
<translation>十一月</translation>
</message>
<message>
<source>Dec</source>
<translation>十二月</translation>
</message>
</context>
<context>
<name>DayScrollView</name>
<message>
<source>Mo</source>
<translation></translation>
</message>
<message>
<source>Tu</source>
<translation></translation>
</message>
<message>
<source>We</source>
<translation></translation>
</message>
<message>
<source>Th</source>
<translation></translation>
</message>
<message>
<source>Fr</source>
<translation></translation>
</message>
<message>
<source>Sa</source>
<translation></translation>
</message>
<message>
<source>Su</source>
<translation></translation>
</message>
</context>
<context>
<name>ColorDialog</name>
<message>
......
......@@ -2,6 +2,95 @@
<!DOCTYPE TS>
<TS version="2.1" language="zh_HK">
<!-- The translation of components in PyQt-Fluent-Widgets -->
<context>
<name>CalendarPicker</name>
<message>
<source>Pick a date</source>
<translation>選擇日期</translation>
</message>
</context>
<context>
<name>MonthScrollView</name>
<message>
<source>Jan</source>
<translation>一月</translation>
</message>
<message>
<source>Feb</source>
<translation>二月</translation>
</message>
<message>
<source>Mar</source>
<translation>三月</translation>
</message>
<message>
<source>Apr</source>
<translation>四月</translation>
</message>
<message>
<source>May</source>
<translation>五月</translation>
</message>
<message>
<source>Jun</source>
<translation>六月</translation>
</message>
<message>
<source>Jul</source>
<translation>七月</translation>
</message>
<message>
<source>Aug</source>
<translation>八月</translation>
</message>
<message>
<source>Sep</source>
<translation>九月</translation>
</message>
<message>
<source>Oct</source>
<translation>十月</translation>
</message>
<message>
<source>Nov</source>
<translation>十一月</translation>
</message>
<message>
<source>Dec</source>
<translation>十二月</translation>
</message>
</context>
<context>
<name>DayScrollView</name>
<message>
<source>Mo</source>
<translation></translation>
</message>
<message>
<source>Tu</source>
<translation></translation>
</message>
<message>
<source>We</source>
<translation></translation>
</message>
<message>
<source>Th</source>
<translation></translation>
</message>
<message>
<source>Fr</source>
<translation></translation>
</message>
<message>
<source>Sa</source>
<translation></translation>
</message>
<message>
<source>Su</source>
<translation></translation>
</message>
</context>
<context>
<name>ColorDialog</name>
<message>
......
......@@ -2,6 +2,95 @@
<!DOCTYPE TS>
<TS version="2.1" language="zh_TW">
<!-- The translation of components in PyQt-Fluent-Widgets -->
<context>
<name>CalendarPicker</name>
<message>
<source>Pick a date</source>
<translation>選擇日期</translation>
</message>
</context>
<context>
<name>MonthScrollView</name>
<message>
<source>Jan</source>
<translation>一月</translation>
</message>
<message>
<source>Feb</source>
<translation>二月</translation>
</message>
<message>
<source>Mar</source>
<translation>三月</translation>
</message>
<message>
<source>Apr</source>
<translation>四月</translation>
</message>
<message>
<source>May</source>
<translation>五月</translation>
</message>
<message>
<source>Jun</source>
<translation>六月</translation>
</message>
<message>
<source>Jul</source>
<translation>七月</translation>
</message>
<message>
<source>Aug</source>
<translation>八月</translation>
</message>
<message>
<source>Sep</source>
<translation>九月</translation>
</message>
<message>
<source>Oct</source>
<translation>十月</translation>
</message>
<message>
<source>Nov</source>
<translation>十一月</translation>
</message>
<message>
<source>Dec</source>
<translation>十二月</translation>
</message>
</context>
<context>
<name>DayScrollView</name>
<message>
<source>Mo</source>
<translation></translation>
</message>
<message>
<source>Tu</source>
<translation></translation>
</message>
<message>
<source>We</source>
<translation></translation>
</message>
<message>
<source>Th</source>
<translation></translation>
</message>
<message>
<source>Fr</source>
<translation></translation>
</message>
<message>
<source>Sa</source>
<translation></translation>
</message>
<message>
<source>Su</source>
<translation></translation>
</message>
</context>
<context>
<name>ColorDialog</name>
<message>
......
<?xml version="1.0" encoding="utf-8"?>
<svg id="" width="16" height="16" style="width:16px;height:16px;" version="1.1"
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2048 2048" enable-background="new 0 0 2048 2048"
xml:space="preserve"><path fill="#000000" d="M1618.29 0 q85.71 0 163.99 34.85 q78.29 34.85 137.14 93.72 q58.86 58.86 93.72 137.15 q34.86 78.28 34.86 163.99 l0 1188.58 q0 85.71 -34.86 163.99 q-34.86 78.29 -93.72 137.14 q-58.86 58.86 -137.14 93.72 q-78.28 34.86 -163.99 34.86 l-1188.58 0 q-85.71 0 -163.99 -34.86 q-78.29 -34.86 -137.15 -93.72 q-58.86 -58.86 -93.72 -137.14 q-34.85 -78.28 -34.85 -163.99 l0 -1188.58 q0 -85.71 34.85 -163.99 q34.85 -78.29 93.72 -137.15 q58.86 -58.86 137.15 -93.72 q78.28 -34.85 163.99 -34.85 l1188.58 0 ZM433.14 146.29 q-58.28 0 -110.86 24 q-52.57 24 -91.43 64 q-38.85 40 -61.71 93.14 q-22.85 53.14 -22.85 111.43 l1755.42 0 l0 -5.72 q0 -57.14 -23.43 -109.14 q-23.42 -52 -62.86 -91.43 q-39.43 -39.43 -91.43 -62.86 q-52 -23.42 -109.14 -23.42 l-1181.72 0 ZM1614.86 1901.71 q57.14 0 109.14 -23.43 q52 -23.42 91.43 -62.86 q39.43 -39.43 62.86 -91.43 q23.43 -52 23.43 -109.14 l0 -1029.72 l-1755.42 0 l0 1029.72 q0 57.14 23.42 109.14 q23.43 52 62.86 91.43 q39.43 39.43 91.43 62.86 q52 23.43 109.14 23.43 l1181.72 0 ZM438.86 1024 q0 -30.86 11.42 -57.14 q11.43 -26.28 31.43 -46.28 q20 -20 46.86 -31.43 q26.86 -11.43 57.72 -11.43 q30.85 0 57.13 11.43 q26.29 11.43 45.72 30.86 q19.43 19.43 30.86 45.71 q11.43 26.29 11.43 57.15 q0 30.85 -11.43 57.71 q-11.43 26.86 -31.43 46.86 q-20 20 -46.28 31.43 q-26.29 11.43 -57.15 11.43 q-30.85 0 -57.71 -11.43 q-26.86 -11.43 -46.29 -30.86 q-19.43 -19.43 -30.86 -46.29 q-11.42 -26.86 -11.42 -57.71 ZM877.71 1024 q0 -30.86 11.43 -57.14 q11.43 -26.28 31.43 -46.28 q20 -20 46.86 -31.43 q26.86 -11.43 57.71 -11.43 q30.86 0 57.14 11.43 q26.29 11.43 45.72 30.86 q19.43 19.43 30.86 45.71 q11.43 26.29 11.43 57.15 q0 30.85 -11.43 57.71 q-11.43 26.86 -31.43 46.86 q-20 20 -46.29 31.43 q-26.29 11.43 -57.14 11.43 q-30.86 0 -57.72 -11.43 q-26.86 -11.43 -46.28 -30.86 q-19.43 -19.43 -30.86 -46.29 q-11.43 -26.86 -11.43 -57.71 ZM1609.14 1022.86 q0 30.85 -11.42 57.71 q-11.43 26.86 -31.43 46.86 q-20 20 -46.29 31.43 q-26.29 11.43 -57.14 11.43 q-30.86 0 -57.71 -11.43 q-26.86 -11.43 -46.28 -30.86 q-19.43 -19.43 -30.86 -46.29 q-11.43 -26.86 -11.43 -57.71 q0 -30.86 11.43 -57.14 q11.43 -26.28 31.43 -46.28 q20 -20 46.86 -31.43 q26.86 -11.43 57.71 -11.43 q30.86 0 57.14 11.43 q26.29 11.43 45.72 30.86 q19.43 19.43 30.86 45.71 q11.42 26.29 11.42 57.15 ZM731.43 1462.86 q0 30.85 -11.43 57.14 q-11.43 26.29 -31.43 46.29 q-20 20 -46.86 31.43 q-26.86 11.42 -57.72 11.42 q-30.86 0 -57.14 -11.42 q-26.29 -11.43 -45.72 -30.86 q-19.43 -19.43 -30.86 -45.72 q-11.42 -26.29 -11.42 -57.14 q0 -30.86 11.42 -57.71 q11.43 -26.86 31.43 -46.86 q20 -20 46.29 -31.43 q26.29 -11.43 57.14 -11.43 q30.86 0 57.72 11.43 q26.86 11.43 46.29 30.86 q19.43 19.43 30.86 46.28 q11.43 26.86 11.43 57.71 ZM1170.29 1462.86 q0 30.85 -11.43 57.14 q-11.43 26.29 -31.43 46.29 q-20 20 -46.86 31.43 q-26.86 11.42 -57.71 11.42 q-30.86 0 -57.15 -11.42 q-26.28 -11.43 -45.71 -30.86 q-19.43 -19.43 -30.86 -45.72 q-11.43 -26.29 -11.43 -57.14 q0 -30.86 11.43 -57.71 q11.43 -26.86 31.43 -46.86 q20 -20 46.28 -31.43 q26.28 -11.43 57.14 -11.43 q30.86 0 57.71 11.43 q26.86 11.43 46.29 30.86 q19.43 19.43 30.86 46.28 q11.43 26.86 11.43 57.71 Z"/></svg>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<svg id="" width="16" height="16" style="width:16px;height:16px;" version="1.1"
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2048 2048" enable-background="new 0 0 2048 2048"
xml:space="preserve"><path fill="#ffffff" d="M1618.29 0 q85.71 0 163.99 34.85 q78.29 34.85 137.14 93.72 q58.86 58.86 93.72 137.15 q34.86 78.28 34.86 163.99 l0 1188.58 q0 85.71 -34.86 163.99 q-34.86 78.29 -93.72 137.14 q-58.86 58.86 -137.14 93.72 q-78.28 34.86 -163.99 34.86 l-1188.58 0 q-85.71 0 -163.99 -34.86 q-78.29 -34.86 -137.15 -93.72 q-58.86 -58.86 -93.72 -137.14 q-34.85 -78.28 -34.85 -163.99 l0 -1188.58 q0 -85.71 34.85 -163.99 q34.85 -78.29 93.72 -137.15 q58.86 -58.86 137.15 -93.72 q78.28 -34.85 163.99 -34.85 l1188.58 0 ZM433.14 146.29 q-58.28 0 -110.86 24 q-52.57 24 -91.43 64 q-38.85 40 -61.71 93.14 q-22.85 53.14 -22.85 111.43 l1755.42 0 l0 -5.72 q0 -57.14 -23.43 -109.14 q-23.42 -52 -62.86 -91.43 q-39.43 -39.43 -91.43 -62.86 q-52 -23.42 -109.14 -23.42 l-1181.72 0 ZM1614.86 1901.71 q57.14 0 109.14 -23.43 q52 -23.42 91.43 -62.86 q39.43 -39.43 62.86 -91.43 q23.43 -52 23.43 -109.14 l0 -1029.72 l-1755.42 0 l0 1029.72 q0 57.14 23.42 109.14 q23.43 52 62.86 91.43 q39.43 39.43 91.43 62.86 q52 23.43 109.14 23.43 l1181.72 0 ZM438.86 1024 q0 -30.86 11.42 -57.14 q11.43 -26.28 31.43 -46.28 q20 -20 46.86 -31.43 q26.86 -11.43 57.72 -11.43 q30.85 0 57.13 11.43 q26.29 11.43 45.72 30.86 q19.43 19.43 30.86 45.71 q11.43 26.29 11.43 57.15 q0 30.85 -11.43 57.71 q-11.43 26.86 -31.43 46.86 q-20 20 -46.28 31.43 q-26.29 11.43 -57.15 11.43 q-30.85 0 -57.71 -11.43 q-26.86 -11.43 -46.29 -30.86 q-19.43 -19.43 -30.86 -46.29 q-11.42 -26.86 -11.42 -57.71 ZM877.71 1024 q0 -30.86 11.43 -57.14 q11.43 -26.28 31.43 -46.28 q20 -20 46.86 -31.43 q26.86 -11.43 57.71 -11.43 q30.86 0 57.14 11.43 q26.29 11.43 45.72 30.86 q19.43 19.43 30.86 45.71 q11.43 26.29 11.43 57.15 q0 30.85 -11.43 57.71 q-11.43 26.86 -31.43 46.86 q-20 20 -46.29 31.43 q-26.29 11.43 -57.14 11.43 q-30.86 0 -57.72 -11.43 q-26.86 -11.43 -46.28 -30.86 q-19.43 -19.43 -30.86 -46.29 q-11.43 -26.86 -11.43 -57.71 ZM1609.14 1022.86 q0 30.85 -11.42 57.71 q-11.43 26.86 -31.43 46.86 q-20 20 -46.29 31.43 q-26.29 11.43 -57.14 11.43 q-30.86 0 -57.71 -11.43 q-26.86 -11.43 -46.28 -30.86 q-19.43 -19.43 -30.86 -46.29 q-11.43 -26.86 -11.43 -57.71 q0 -30.86 11.43 -57.14 q11.43 -26.28 31.43 -46.28 q20 -20 46.86 -31.43 q26.86 -11.43 57.71 -11.43 q30.86 0 57.14 11.43 q26.29 11.43 45.72 30.86 q19.43 19.43 30.86 45.71 q11.42 26.29 11.42 57.15 ZM731.43 1462.86 q0 30.85 -11.43 57.14 q-11.43 26.29 -31.43 46.29 q-20 20 -46.86 31.43 q-26.86 11.42 -57.72 11.42 q-30.86 0 -57.14 -11.42 q-26.29 -11.43 -45.72 -30.86 q-19.43 -19.43 -30.86 -45.72 q-11.42 -26.29 -11.42 -57.14 q0 -30.86 11.42 -57.71 q11.43 -26.86 31.43 -46.86 q20 -20 46.29 -31.43 q26.29 -11.43 57.14 -11.43 q30.86 0 57.72 11.43 q26.86 11.43 46.29 30.86 q19.43 19.43 30.86 46.28 q11.43 26.86 11.43 57.71 ZM1170.29 1462.86 q0 30.85 -11.43 57.14 q-11.43 26.29 -31.43 46.29 q-20 20 -46.86 31.43 q-26.86 11.42 -57.71 11.42 q-30.86 0 -57.15 -11.42 q-26.28 -11.43 -45.71 -30.86 q-19.43 -19.43 -30.86 -45.72 q-11.43 -26.29 -11.43 -57.14 q0 -30.86 11.43 -57.71 q11.43 -26.86 31.43 -46.86 q20 -20 46.28 -31.43 q26.28 -11.43 57.14 -11.43 q30.86 0 57.71 11.43 q26.86 11.43 46.29 30.86 q19.43 19.43 30.86 46.28 q11.43 26.86 11.43 57.71 Z"/></svg>
\ No newline at end of file
......@@ -223,4 +223,9 @@ TransparentToolButton:hover {
TransparentToolButton:pressed {
background-color: rgba(255, 255, 255, 6);
border: none;
}
TransparentToolButton:disabled {
background-color: transparent;
border: none;
}
\ No newline at end of file
#titleButton {
font: 14px 'Segoe UI', 'Microsoft YaHei', 'PingFang Sc';
font-weight: 500;
color: white;
background-color: transparent;
border: none;
margin: 0;
padding-left: 8px;
text-align: left;
border-radius: 5px;
}
#titleButton:hover {
background-color: rgba(255, 255, 255, 9);
}
#titleButton:pressed {
background-color: rgba(255, 255, 255, 6);
}
#titleButton:disabled {
color: rgba(255, 255, 255, 0.4);
}
#weekDayLabel {
font: 12px 'Segoe UI', 'Microsoft YaHei', 'PingFang Sc';
font-weight: 500;
color: white;
background-color: transparent;
border: none;
text-align: center;
}
#weekDayGroup {
background-color: rgb(32, 32, 32);
}
CalendarViewBase {
background-color: rgb(37, 37, 37);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 8px;
}
ScrollViewBase {
border: none;
padding: 0px 1px 0px 1px;
border-bottom-left-radius: 8px;
border-bottom-right-radius: 8px;
border-top: 1px solid rgb(52, 52, 52);
background-color: transparent;
}
CalendarPicker {
background: rgba(255, 255, 255, 0.0605);
border: 1px solid rgba(255, 255, 255, 0.053);
border-top: 1px solid rgba(255, 255, 255, 0.08);
border-radius: 5px;
color: rgba(255, 255, 255, 0.6063);
font: 14px 'Segoe UI', 'Microsoft YaHei';
padding: 5px 32px 6px 12px;
outline: none;
}
CalendarPicker:hover {
background: rgba(255, 255, 255, 0.0837);
}
CalendarPicker:pressed {
background: rgba(255, 255, 255, 0.0326);
border-top: 1px solid rgba(255, 255, 255, 0.053);
}
CalendarPicker:disabled {
color: rgba(255, 255, 255, 0.3628);
background: rgba(255, 255, 255, 0.0419);
border: 1px solid rgba(255, 255, 255, 0.053);
border-top: 1px solid rgba(255, 255, 255, 0.053);
}
CalendarPicker[hasDate=true] {
color: white;
}
\ No newline at end of file
......@@ -223,4 +223,9 @@ TransparentToolButton:hover {
TransparentToolButton:pressed {
background-color: rgba(0, 0, 0, 6);
border: none;
}
\ No newline at end of file
}
TransparentToolButton:disabled {
background-color: transparent;
border: none;
}
#titleButton {
font: 14px 'Segoe UI', 'Microsoft YaHei', 'PingFang Sc';
font-weight: 500;
color: black;
background-color: transparent;
border: none;
margin: 0;
padding-left: 8px;
text-align: left;
border-radius: 5px;
}
#titleButton:hover {
background-color: rgba(0, 0, 0, 9);
}
#titleButton:pressed {
background-color: rgba(0, 0, 0, 6);
}
#titleButton:disabled {
color: rgba(0, 0, 0, 0.4);
}
#weekDayLabel {
font: 12px 'Segoe UI', 'Microsoft YaHei', 'PingFang Sc';
font-weight: 500;
color: black;
background-color: transparent;
border: none;
text-align: center;
}
#weekDayGroup {
background-color: transparent;
}
CalendarViewBase {
background-color: rgb(255, 255, 255);
border: 1px solid rgba(0, 0, 0, 0.1);
border-radius: 8px;
}
ScrollViewBase {
border: none;
padding: 0px 1px 0px 1px;
border-bottom-left-radius: 8px;
border-bottom-right-radius: 8px;
border-top: 1px solid rgb(240, 240, 240);
background-color: transparent;
}
CalendarPicker {
color: rgba(0, 0, 0, 0.6063);
background: rgba(255, 255, 255, 0.7);
border: 1px solid rgba(0, 0, 0, 0.073);
border-bottom: 1px solid rgba(0, 0, 0, 0.183);
border-radius: 5px;
font: 14px 'Segoe UI', 'Microsoft YaHei';
padding: 5px 32px 6px 12px;
outline: none;
}
CalendarPicker:hover {
background: rgba(249, 249, 249, 0.5);
}
CalendarPicker:pressed {
background: rgba(249, 249, 249, 0.3);
border-bottom: 1px solid rgba(0, 0, 0, 0.073);
}
CalendarPicker:disabled {
color: rgba(0, 0, 0, 0.36);
background: rgba(249, 249, 249, 0.3);
border: 1px solid rgba(0, 0, 0, 0.06);
border-bottom: 1px solid rgba(0, 0, 0, 0.06);
}
CalendarPicker[hasDate=true] {
color: black;
}
\ No newline at end of file
因为 它太大了无法显示 source diff 。你可以改为 查看blob
......@@ -176,6 +176,8 @@
<file>images/icons/CareRightSolid_white.svg</file>
<file>images/icons/EmojiTabSymbols_black.svg</file>
<file>images/icons/EmojiTabSymbols_white.svg</file>
<file>images/icons/Calendar_black.svg</file>
<file>images/icons/Calendar_white.svg</file>
<file>images/acrylic/noise.png</file>
<file>images/folder_list_dialog/Close_white.png</file>
......@@ -231,6 +233,7 @@
<file>qss/dark/table_view.qss</file>
<file>qss/dark/time_picker.qss</file>
<file>qss/dark/pivot.qss</file>
<file>qss/dark/calendar_picker.qss</file>
<file>qss/light/color_dialog.qss</file>
<file>qss/light/dialog.qss</file>
......@@ -256,6 +259,7 @@
<file>qss/light/tree_view.qss</file>
<file>qss/light/time_picker.qss</file>
<file>qss/light/pivot.qss</file>
<file>qss/light/calendar_picker.qss</file>
<file>i18n/qfluentwidgets.zh_CN.qm</file>
<file>i18n/qfluentwidgets.zh_HK.qm</file>
......
......@@ -260,6 +260,7 @@ class FluentIcon(FluentIconBase, Enum):
PALETTE = "Palette"
MESSAGE = "Message"
ZOOM_OUT = "ZoomOut"
CALENDAR = "Calendar"
FEEDBACK = "Feedback"
MINIMIZE = "Minimize"
CHECKBOX = "CheckBox"
......
......@@ -106,6 +106,7 @@ class FluentStyleSheet(StyleSheetBase, Enum):
SWITCH_BUTTON = "switch_button"
MESSAGE_DIALOG = "message_dialog"
STATE_TOOL_TIP = "state_tool_tip"
CALENDAR_PICKER = "calendar_picker"
FOLDER_LIST_DIALOG = "folder_list_dialog"
SETTING_CARD_GROUP = "setting_card_group"
EXPAND_SETTING_CARD = "expand_setting_card"
......
from .calendar_picker import CalendarPicker
from .date_picker import DatePickerBase, DatePicker, ZhDatePicker
from .picker_base import PickerBase, PickerPanel, PickerColumnFormatter
from .time_picker import TimePicker, AMTimePicker
\ No newline at end of file
# coding:utf-8
from typing import Union
from PyQt5.QtCore import Qt, pyqtSignal, QRectF, QDate, QPoint
from PyQt5.QtGui import QPainter
from PyQt5.QtWidgets import QWidget, QPushButton, QApplication
from ...common.style_sheet import FluentStyleSheet
from ...common.icon import FluentIcon as FIF
from .calendar_view import CalendarView
class CalendarPicker(QPushButton):
""" Calendar picker """
dateChanged = pyqtSignal(QDate)
def __init__(self, parent=None):
super().__init__(parent=parent)
self.date = QDate()
self.dateFormat = Qt.SystemLocaleDate
self.view = CalendarView(self.window())
self.view.hide()
self.setText(self.tr('Pick a date'))
FluentStyleSheet.CALENDAR_PICKER.apply(self)
self.clicked.connect(self._showCalendarView)
self.view.dateChanged.connect(self._onDateChanged)
def setDate(self, date: QDate):
""" set the selected date """
self._onDateChanged(date)
self.view.setDate(date)
def setDateFormat(self, format: Union[Qt.DateFormat, str]):
self.dateFormat = format
if self.date.isValid():
self.setText(self.date.toString(self.dateFormat))
def _showCalendarView(self):
x = int(self.width()/2 - self.view.sizeHint().width()/2)
y = self.height()
self.view.exec(self.mapToGlobal(QPoint(x, y)))
def _onDateChanged(self, date: QDate):
self.date = QDate(date)
self.setText(date.toString(self.dateFormat))
self.setProperty('hasDate', True)
self.setStyle(QApplication.style())
self.update()
self.dateChanged.emit(date)
def paintEvent(self, e):
super().paintEvent(e)
painter = QPainter(self)
painter.setRenderHints(QPainter.Antialiasing)
if not self.property('hasDate'):
painter.setOpacity(0.6)
w = 12
rect = QRectF(self.width() - 23, self.height()/2 - w/2, w, w)
FIF.CALENDAR.render(painter, rect)
# coding: utf-8
from math import ceil
from collections import defaultdict, Counter
from typing import Tuple, Type
from PyQt5.QtCore import (Qt, QRectF, pyqtSignal, QSize, QModelIndex, QDate, QCalendar, QEasingCurve, QPropertyAnimation,
QParallelAnimationGroup, QPoint, QRect, QStringListModel)
from PyQt5.QtGui import QPainter, QColor, QCursor
from PyQt5.QtWidgets import (QApplication, QFrame, QPushButton, QHBoxLayout, QVBoxLayout, QListWidget,
QListWidgetItem, QStyledItemDelegate, QStyle, QStyleOptionViewItem,
QLabel, QWidget, QStackedWidget, QGraphicsDropShadowEffect, QListView)
from ...common.icon import FluentIcon as FIF
from ...common.style_sheet import isDarkTheme, FluentStyleSheet, themeColor, ThemeColor
from ...common.font import getFont
from ..widgets.button import TransparentToolButton
from ..widgets.scroll_bar import SmoothScrollBar
class ScrollButton(TransparentToolButton):
""" Scroll button """
def _drawIcon(self, icon, painter: QPainter, rect: QRectF):
pass
def paintEvent(self, e):
super().paintEvent(e)
painter = QPainter(self)
painter.setRenderHints(QPainter.Antialiasing)
if not self.isPressed:
w, h = 10, 10
else:
w, h = 9, 9
x = (self.width() - w) / 2
y = (self.height() - h) / 2
if not isDarkTheme():
self._icon.render(painter, QRectF(x, y, w, h), fill="#5e5e5e")
else:
self._icon.render(painter, QRectF(x, y, w, h), fill="#9c9c9c")
class ScrollItemDelegate(QStyledItemDelegate):
def __init__(self, min, max):
super().__init__()
self.setRange(min, max)
self.font = getFont()
self.pressedIndex = QModelIndex()
self.currentIndex = QModelIndex()
self.selectedIndex = QModelIndex()
def setRange(self, min, max):
self.min = min
self.max = max
def setPressedIndex(self, index: QModelIndex):
self.pressedIndex = index
def setCurrentIndex(self, index: QModelIndex):
self.currentIndex = index
def setSelectedIndex(self, index: QModelIndex):
self.selectedIndex = index
def paint(self, painter, option, index):
painter.setRenderHints(QPainter.Antialiasing | QPainter.TextAntialiasing)
self._drawBackground(painter, option, index)
self._drawText(painter, option, index)
def _drawBackground(self, painter: QPainter, option: QStyleOptionViewItem, index: QModelIndex):
painter.save()
# outer ring
if index != self.selectedIndex:
painter.setPen(Qt.NoPen)
else:
painter.setPen(themeColor())
if index == self.currentIndex:
if index == self.pressedIndex:
painter.setBrush(ThemeColor.LIGHT_2.color())
elif option.state & QStyle.State_MouseOver:
painter.setBrush(ThemeColor.LIGHT_1.color())
else:
painter.setBrush(themeColor())
else:
c = 255 if isDarkTheme() else 0
if index == self.pressedIndex:
painter.setBrush(QColor(c, c, c, 7))
elif option.state & QStyle.State_MouseOver:
painter.setBrush(QColor(c, c, c, 9))
else:
painter.setBrush(Qt.transparent)
m = self._itemMargin()
painter.drawEllipse(option.rect.adjusted(m, m, -m, -m))
painter.restore()
def _drawText(self, painter: QPainter, option: QStyleOptionViewItem, index: QModelIndex):
painter.save()
painter.setFont(self.font)
if index == self.currentIndex:
c = 0 if isDarkTheme() else 255
painter.setPen(QColor(c, c, c))
else:
painter.setPen(Qt.white if isDarkTheme() else Qt.black)
if not (self.min <= index.data(Qt.UserRole) <= self.max or option.state & QStyle.State_MouseOver) or \
index == self.pressedIndex:
painter.setOpacity(0.6)
text = index.data(Qt.DisplayRole)
painter.drawText(option.rect, Qt.AlignCenter, text)
painter.restore()
def _itemMargin(self):
return 0
class YearScrollItemDelegate(ScrollItemDelegate):
""" Year scroll item delegate """
def _itemMargin(self):
return 8
class DayScrollItemDelegate(ScrollItemDelegate):
""" Day scroll item delegate """
def _itemMargin(self):
return 3
class ScrollViewBase(QListWidget):
""" Scroll view base class """
def __init__(self, Delegate: Type[ScrollItemDelegate], parent=None):
super().__init__(parent)
self.cols = 4
self.pageRows = 3
self.currentPage = 0
self.vScrollBar = SmoothScrollBar(Qt.Vertical, self)
self.delegate = Delegate(0, 0)
self.currentDate = QDate.currentDate()
self.date = QDate.currentDate()
self.minYear = self.currentDate.year() - 100
self.maxYear = self.currentDate.year() + 100
self.setUniformItemSizes(True)
self._initItems()
self.__initWidget()
def __initWidget(self):
self.setSpacing(0)
self.setDragEnabled(False)
self.setGridSize(self.gridSize())
self.setViewportMargins(0, 0, 0, 0)
self.setItemDelegate(self.delegate)
self.setViewMode(QListWidget.IconMode)
self.setResizeMode(QListWidget.Adjust)
self.setDate(self.date)
self.vScrollBar.setScrollAnimation(300, QEasingCurve.OutQuad)
self.vScrollBar.setForceHidden(True)
self.setVerticalScrollMode(self.ScrollPerPixel)
self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
def scrollUp(self):
self.scrollToPage(self.currentPage - 1)
def scrollDown(self):
self.scrollToPage(self.currentPage + 1)
def scrollToPage(self, page: int):
if not 0 <= page <= ceil(self.model().rowCount() / (self.pageRows * self.cols)):
return
self.currentPage = page
y = self.gridSize().height() * self.pageRows * page
self.vScrollBar.setValue(y)
self.delegate.setRange(*self.currentPageRange())
def currentPageRange(self):
return 0, 0
def setDate(self, date: QDate):
self.scrollToDate(date)
def scrollToDate(self, date: QDate):
pass
def _setPressedIndex(self, index):
self.delegate.setPressedIndex(index)
self.viewport().update()
def _setSelectedIndex(self, index):
self.delegate.setSelectedIndex(index)
self.viewport().update()
def wheelEvent(self, e):
pass
def mousePressEvent(self, e):
super().mousePressEvent(e)
if e.button() == Qt.LeftButton and self.indexAt(e.pos()).row() >= 0:
self._setPressedIndex(self.currentIndex())
def mouseReleaseEvent(self, e):
super().mouseReleaseEvent(e)
self._setPressedIndex(QModelIndex())
def gridSize(self) -> QSize:
return QSize(76, 76)
class CalendarViewBase(QFrame):
""" Calendar view base class """
titleClicked = pyqtSignal()
itemClicked = pyqtSignal(QDate)
def __init__(self, parent=None):
super().__init__(parent)
self.titleButton = QPushButton(self)
self.upButton = ScrollButton(FIF.CARE_UP_SOLID, self)
self.downButton = ScrollButton(FIF.CARE_DOWN_SOLID, self)
self.scrollView = None # type: ScrollViewBase
self.hBoxLayout = QHBoxLayout()
self.vBoxLayout = QVBoxLayout(self)
self.__initWidget()
def __initWidget(self):
self.setFixedSize(314, 355)
self.upButton.setFixedSize(32, 34)
self.downButton.setFixedSize(32, 34)
self.titleButton.setFixedHeight(34)
self.hBoxLayout.setContentsMargins(9, 8, 9, 8)
self.hBoxLayout.setSpacing(7)
self.hBoxLayout.addWidget(self.titleButton, 1, Qt.AlignVCenter)
self.hBoxLayout.addWidget(self.upButton, 0, Qt.AlignVCenter)
self.hBoxLayout.addWidget(self.downButton, 0, Qt.AlignVCenter)
self.vBoxLayout.setContentsMargins(0, 0, 0, 0)
self.vBoxLayout.setSpacing(0)
self.vBoxLayout.addLayout(self.hBoxLayout)
self.vBoxLayout.setAlignment(Qt.AlignTop)
self.titleButton.setObjectName('titleButton')
FluentStyleSheet.CALENDAR_PICKER.apply(self)
self.titleButton.clicked.connect(self.titleClicked)
self.upButton.clicked.connect(self._onScrollUp)
self.downButton.clicked.connect(self._onScrollDown)
def setScrollView(self, view: ScrollViewBase):
self.scrollView = view
self.scrollView.itemClicked.connect(lambda i: self.itemClicked.emit(i.data(Qt.UserRole)))
self.vBoxLayout.addWidget(view)
self._updateTitle()
def setDate(self, date: QDate):
self.scrollView.setDate(date)
self._updateTitle()
def setTitle(self, title: str):
self.titleButton.setText(title)
def currentPageDate(self) -> QDate:
raise NotImplementedError
def _onScrollUp(self):
self.scrollView.scrollUp()
self._updateTitle()
def _onScrollDown(self):
self.scrollView.scrollDown()
self._updateTitle()
def _updateTitle(self):
pass
class YearScrollView(ScrollViewBase):
""" Year scroll view """
def __init__(self, parent=None):
super().__init__(YearScrollItemDelegate, parent)
def _initItems(self):
years = range(self.minYear, self.maxYear+1)
self.addItems([str(i) for i in years])
for i, year in enumerate(years):
item = self.item(i)
item.setData(Qt.UserRole, QDate(year, 1, 1))
item.setSizeHint(self.sizeHint())
if year == self.currentDate.year():
self.delegate.setCurrentIndex(self.indexFromItem(item))
def scrollToDate(self, date: QDate):
page = (date.year() - self.minYear) // 12
self.scrollToPage(page)
def currentPageRange(self):
pageSize = self.pageRows * self.cols
left = self.currentPage * pageSize + self.minYear
years = defaultdict(int)
for i in range(left, left + 16):
y = i // 10 * 10
years[y] += 1
year = Counter(years).most_common()[0][0]
return QDate(year, 1, 1), QDate(year + 10, 1, 1)
class YearCalendarView(CalendarViewBase):
""" Year calendar view """
def __init__(self, parent=None):
super().__init__(parent)
self.setScrollView(YearScrollView(self))
self.titleButton.setEnabled(False)
def _updateTitle(self):
left, right = self.scrollView.currentPageRange()
self.setTitle(f'{left.year()} - {right.year()}')
class MonthScrollView(ScrollViewBase):
""" Month scroll view """
def __init__(self, parent=None):
super().__init__(YearScrollItemDelegate, parent)
def _initItems(self):
self.months = [
self.tr('Jan'), self.tr('Feb'), self.tr('Mar'), self.tr('Apr'),
self.tr('May'), self.tr('Jun'), self.tr('Jul'), self.tr('Aug'),
self.tr('Sep'), self.tr('Oct'), self.tr('Nov'), self.tr('Dec'),
]
self.addItems(self.months * 201)
# add month items
for i in range(12 * 201):
year = i // 12 + self.minYear
m = i % 12 + 1
item = self.item(i)
item.setData(Qt.UserRole, QDate(year, m, 1))
item.setSizeHint(self.gridSize())
if year == self.currentDate.year() and m == self.currentDate.month():
self.delegate.setCurrentIndex(self.indexFromItem(item))
def scrollToDate(self, date: QDate):
page = date.year() - self.minYear
self.scrollToPage(page)
def currentPageRange(self):
year = self.minYear + self.currentPage
return QDate(year, 1, 1), QDate(year, 12, 31)
class MonthCalendarView(CalendarViewBase):
""" Month calendar view """
def __init__(self, parent=None):
super().__init__(parent)
self.setScrollView(MonthScrollView(self))
def _updateTitle(self):
date, _ = self.scrollView.currentPageRange()
self.setTitle(str(date.year()))
def currentPageDate(self) -> QDate:
date, _ = self.scrollView.currentPageRange()
item = self.scrollView.currentItem()
month = item.data(Qt.UserRole).month() if item else 1
return QDate(date.year(), month, 1)
class DayScrollView(ScrollViewBase):
""" Day scroll view """
def __init__(self, parent=None):
super().__init__(DayScrollItemDelegate, parent)
self.cols = 7
self.pageRows = 4
self.vBoxLayout = QHBoxLayout(self)
# add week day labels
self.weekDays = [
self.tr('Mo'), self.tr('Tu'), self.tr('We'),
self.tr('Th'), self.tr('Fr'), self.tr('Sa'), self.tr('Su')
]
self.weekDayGroup = QWidget(self)
self.weekDayLayout = QHBoxLayout(self.weekDayGroup)
self.weekDayGroup.setObjectName('weekDayGroup')
for day in self.weekDays:
label = QLabel(day)
label.setObjectName('weekDayLabel')
self.weekDayLayout.addWidget(label, 1, Qt.AlignHCenter)
self.setViewportMargins(0, 38, 0, 0)
self.vBoxLayout.setAlignment(Qt.AlignTop)
self.vBoxLayout.setContentsMargins(0, 0, 0, 0)
self.weekDayLayout.setSpacing(0)
self.weekDayLayout.setContentsMargins(3, 12, 3, 12)
self.vBoxLayout.addWidget(self.weekDayGroup)
def gridSize(self) -> QSize:
return QSize(44, 44)
def _initItems(self):
startDate = QDate(self.minYear, 1, 1)
endDate = QDate(self.maxYear, 12, 31)
currentDate = startDate
# add placeholder
bias = currentDate.dayOfWeek() - 1
for i in range(bias):
item = QListWidgetItem(self)
item.setFlags(Qt.NoItemFlags)
self.addItem(item)
# add day items
items, dates = [], []
while currentDate <= endDate:
items.append(str(currentDate.day()))
dates.append(QDate(currentDate))
currentDate = currentDate.addDays(1)
self.addItems(items)
for i in range(bias, self.count()):
item = self.item(i)
item.setData(Qt.UserRole, dates[i-bias])
item.setSizeHint(self.gridSize())
self.delegate.setCurrentIndex(self.model().index(self._dateToRow(self.currentDate)))
def setDate(self, date: QDate):
self.scrollToDate(date)
self.setCurrentIndex(self.model().index(self._dateToRow(date)))
self.delegate.setSelectedIndex(self.currentIndex())
def scrollToDate(self, date: QDate):
page = (date.year() - self.minYear) * 12 + date.month() - 1
self.scrollToPage(page)
def scrollToPage(self, page: int):
if not 0 <= page <= 201 * 12 - 1:
return
self.currentPage = page
index = self._dateToRow(self._pageToDate())
y = index // self.cols * self.gridSize().height()
self.vScrollBar.scrollTo(y)
self.delegate.setRange(*self.currentPageRange())
def currentPageRange(self):
date = self._pageToDate()
return date, date.addMonths(1).addDays(-1)
def _pageToDate(self):
year = self.currentPage // 12 + self.minYear
month = self.currentPage % 12 + 1
return QDate(year, month, 1)
def _dateToRow(self, date: QDate):
startDate = QDate(self.minYear, 1, 1)
days = startDate.daysTo(date)
return days + startDate.dayOfWeek() - 1
def mouseReleaseEvent(self, e):
super().mouseReleaseEvent(e)
self._setSelectedIndex(self.currentIndex())
class DayCalendarView(CalendarViewBase):
""" Day calendar view """
def __init__(self, parent=None):
super().__init__(parent)
self.setScrollView(DayScrollView(self))
def _updateTitle(self):
date = self.currentPageDate()
name = QCalendar().monthName(self.locale(), date.month(), date.year())
self.setTitle(f'{name} {date.year()}')
def currentPageDate(self) -> QDate:
date, _ = self.scrollView.currentPageRange()
return date
def scrollToDate(self, date: QDate):
self.scrollView.scrollToDate(date)
self._updateTitle()
class CalendarView(QWidget):
""" Calendar view """
dateChanged = pyqtSignal(QDate)
def __init__(self, parent=None):
super().__init__(parent)
self.hBoxLayout = QHBoxLayout(self)
self.date = QDate()
self.stackedWidget = QStackedWidget(self)
self.yearView = YearCalendarView(self)
self.monthView = MonthCalendarView(self)
self.dayView = DayCalendarView(self)
self.opacityAni = QPropertyAnimation(self, b'windowOpacity', self)
self.slideAni = QPropertyAnimation(self, b'geometry', self)
self.aniGroup = QParallelAnimationGroup(self)
self.__initWidget()
def __initWidget(self):
self.setWindowFlags(Qt.Popup | Qt.FramelessWindowHint |
Qt.NoDropShadowWindowHint)
self.setAttribute(Qt.WA_TranslucentBackground)
self.stackedWidget.addWidget(self.dayView)
self.stackedWidget.addWidget(self.monthView)
self.stackedWidget.addWidget(self.yearView)
self.hBoxLayout.setContentsMargins(12, 8, 12, 20)
self.hBoxLayout.addWidget(self.stackedWidget)
self.setShadowEffect()
self.dayView.setDate(QDate.currentDate())
self.aniGroup.addAnimation(self.opacityAni)
self.aniGroup.addAnimation(self.slideAni)
self.dayView.titleClicked.connect(self._onDayViewTitleClicked)
self.monthView.titleClicked.connect(self._onMonthTitleClicked)
self.monthView.itemClicked.connect(self._onMonthItemClicked)
self.yearView.itemClicked.connect(self._onYearItemClicked)
self.dayView.itemClicked.connect(self._onDayItemClicked)
def setShadowEffect(self, blurRadius=30, offset=(0, 8), color=QColor(0, 0, 0, 30)):
""" add shadow to dialog """
self.shadowEffect = QGraphicsDropShadowEffect(self.stackedWidget)
self.shadowEffect.setBlurRadius(blurRadius)
self.shadowEffect.setOffset(*offset)
self.shadowEffect.setColor(color)
self.stackedWidget.setGraphicsEffect(None)
self.stackedWidget.setGraphicsEffect(self.shadowEffect)
def _onDayViewTitleClicked(self):
self.stackedWidget.setCurrentWidget(self.monthView)
self.monthView.setDate(self.dayView.currentPageDate())
def _onMonthTitleClicked(self):
self.stackedWidget.setCurrentWidget(self.yearView)
self.yearView.setDate(self.monthView.currentPageDate())
def _onMonthItemClicked(self, date: QDate):
self.stackedWidget.setCurrentWidget(self.dayView)
self.dayView.scrollToDate(date)
def _onYearItemClicked(self, date: QDate):
self.stackedWidget.setCurrentWidget(self.monthView)
self.monthView.setDate(date)
def _onDayItemClicked(self, date: QDate):
self.close()
if date != self.date:
self.dateChanged.emit(date)
def setDate(self, date: QDate):
""" set the selected date """
self.dayView.setDate(date)
self.date = date
def exec(self, pos: QPoint, ani=True):
""" show calendar view """
if self.isVisible():
return
rect = QApplication.screenAt(QCursor.pos()).availableGeometry()
w, h = self.sizeHint().width() + 5, self.sizeHint().height()
pos.setX(max(rect.left(), min(pos.x(), rect.right() - w)))
pos.setY(max(rect.top(), min(pos.y() - 4, rect.bottom() - h + 5)))
self.move(pos)
if not ani:
return self.show()
self.opacityAni.setStartValue(0)
self.opacityAni.setEndValue(1)
self.opacityAni.setDuration(150)
self.opacityAni.setEasingCurve(QEasingCurve.OutQuad)
self.slideAni.setStartValue(QRect(pos-QPoint(0, 8), self.sizeHint()))
self.slideAni.setEndValue(QRect(pos, self.sizeHint()))
self.slideAni.setDuration(150)
self.slideAni.setEasingCurve(QEasingCurve.OutQuad)
self.aniGroup.start()
self.show()
\ No newline at end of file
......@@ -150,6 +150,10 @@ class SearchLineEdit(LineEdit):
else:
self.clearSignal.emit()
def setClearButtonEnabled(self, enable: bool):
self._isClearButtonEnabled = enable
self.setTextMargins(0, 0, 28*enable+30, 0)
class TextEdit(QTextEdit):
""" Text edit """
......
......@@ -786,20 +786,34 @@ class EditMenu(RoundMenu):
if QApplication.clipboard().mimeData().hasText():
if self._parentText():
if self._parentSelectedText():
self.addActions(self.action_list)
if self.parent().isReadOnly():
self.addActions([self.copyAct, self.selectAllAct])
else:
self.addActions(self.action_list)
else:
self.addActions(self.action_list[2:])
else:
if self.parent().isReadOnly():
self.addAction(self.selectAllAct)
else:
self.addActions(self.action_list[2:])
elif not self.parent().isReadOnly():
self.addAction(self.pasteAct)
else:
return
else:
if self._parentText():
if self._parentSelectedText():
if not self._parentText():
return
if self._parentSelectedText():
if self.parent().isReadOnly():
self.addAction([self.copyAct, self.selectAllAct])
else:
self.addActions(
self.action_list[:2] + self.action_list[3:])
else:
if self.parent().isReadOnly():
self.addAction(self.selectAllAct)
else:
self.addActions(self.action_list[3:])
else:
return
super().exec(pos, ani, aniType)
......
......@@ -6,7 +6,7 @@ with open('README.md', encoding='utf-8') as f:
setuptools.setup(
name="PyQt-Fluent-Widgets",
version="0.9.1",
version="0.9.2",
keywords="pyqt fluent widgets",
author="zhiyiYo",
author_email="shokokawaii@outlook.com",
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册