tkfluent 0.1.3__tar.gz → 0.1.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {tkfluent-0.1.3 → tkfluent-0.1.4}/PKG-INFO +2 -2
- {tkfluent-0.1.3 → tkfluent-0.1.4}/pyproject.toml +2 -2
- {tkfluent-0.1.3 → tkfluent-0.1.4}/tkflu/__main__.py +7 -4
- tkfluent-0.1.4/tkflu/designs/scrollbar.py +56 -0
- {tkfluent-0.1.3 → tkfluent-0.1.4}/tkflu/designs/slider.py +16 -0
- tkfluent-0.1.4/tkflu/popupwindow.py +66 -0
- {tkfluent-0.1.3 → tkfluent-0.1.4}/tkflu/slider.py +156 -87
- {tkfluent-0.1.3 → tkfluent-0.1.4}/tkflu/thememanager.py +11 -11
- {tkfluent-0.1.3 → tkfluent-0.1.4}/tkflu/tooltip.py +1 -6
- tkfluent-0.1.3/tkflu/popupwindow.py +0 -33
- {tkfluent-0.1.3 → tkfluent-0.1.4}/README.md +0 -0
- {tkfluent-0.1.3 → tkfluent-0.1.4}/tkflu/__init__.py +0 -0
- {tkfluent-0.1.3 → tkfluent-0.1.4}/tkflu/badge.py +0 -0
- {tkfluent-0.1.3 → tkfluent-0.1.4}/tkflu/button.py +0 -0
- {tkfluent-0.1.3 → tkfluent-0.1.4}/tkflu/bwm.py +0 -0
- {tkfluent-0.1.3 → tkfluent-0.1.4}/tkflu/checkbox.py +0 -0
- {tkfluent-0.1.3 → tkfluent-0.1.4}/tkflu/constants.py +0 -0
- {tkfluent-0.1.3 → tkfluent-0.1.4}/tkflu/customwindow.py +0 -0
- {tkfluent-0.1.3 → tkfluent-0.1.4}/tkflu/customwindow2.py +0 -0
- {tkfluent-0.1.3 → tkfluent-0.1.4}/tkflu/defs.py +0 -0
- {tkfluent-0.1.3 → tkfluent-0.1.4}/tkflu/demos/__init__.py +0 -0
- {tkfluent-0.1.3 → tkfluent-0.1.4}/tkflu/demos/acrylic1.py +0 -0
- {tkfluent-0.1.3 → tkfluent-0.1.4}/tkflu/demos/demo1.py +0 -0
- {tkfluent-0.1.3 → tkfluent-0.1.4}/tkflu/demos/designer.py +0 -0
- {tkfluent-0.1.3 → tkfluent-0.1.4}/tkflu/demos/grad.py +0 -0
- {tkfluent-0.1.3 → tkfluent-0.1.4}/tkflu/demos/grad2.py +0 -0
- {tkfluent-0.1.3 → tkfluent-0.1.4}/tkflu/demos/grad3.py +0 -0
- {tkfluent-0.1.3 → tkfluent-0.1.4}/tkflu/demos/test.py +0 -0
- {tkfluent-0.1.3 → tkfluent-0.1.4}/tkflu/demos/tooltip.py +0 -0
- {tkfluent-0.1.3 → tkfluent-0.1.4}/tkflu/designs/__init__.py +0 -0
- {tkfluent-0.1.3 → tkfluent-0.1.4}/tkflu/designs/animation.py +0 -0
- {tkfluent-0.1.3 → tkfluent-0.1.4}/tkflu/designs/badge.py +0 -0
- {tkfluent-0.1.3 → tkfluent-0.1.4}/tkflu/designs/button.py +0 -0
- {tkfluent-0.1.3 → tkfluent-0.1.4}/tkflu/designs/design.py +0 -0
- {tkfluent-0.1.3 → tkfluent-0.1.4}/tkflu/designs/entry.py +0 -0
- {tkfluent-0.1.3 → tkfluent-0.1.4}/tkflu/designs/fonts/__init__.py +0 -0
- {tkfluent-0.1.3 → tkfluent-0.1.4}/tkflu/designs/fonts/segoeui.ttf +0 -0
- {tkfluent-0.1.3 → tkfluent-0.1.4}/tkflu/designs/frame.py +0 -0
- {tkfluent-0.1.3 → tkfluent-0.1.4}/tkflu/designs/gradient.py +0 -0
- {tkfluent-0.1.3 → tkfluent-0.1.4}/tkflu/designs/label.py +0 -0
- {tkfluent-0.1.3 → tkfluent-0.1.4}/tkflu/designs/menubar.py +0 -0
- {tkfluent-0.1.3 → tkfluent-0.1.4}/tkflu/designs/primary_color.py +0 -0
- {tkfluent-0.1.3 → tkfluent-0.1.4}/tkflu/designs/text.py +0 -0
- {tkfluent-0.1.3 → tkfluent-0.1.4}/tkflu/designs/tooltip.py +0 -0
- {tkfluent-0.1.3 → tkfluent-0.1.4}/tkflu/designs/window.py +0 -0
- {tkfluent-0.1.3 → tkfluent-0.1.4}/tkflu/entry.py +0 -0
- {tkfluent-0.1.3 → tkfluent-0.1.4}/tkflu/frame.py +0 -0
- {tkfluent-0.1.3 → tkfluent-0.1.4}/tkflu/icons.py +0 -0
- {tkfluent-0.1.3 → tkfluent-0.1.4}/tkflu/image.py +0 -0
- {tkfluent-0.1.3 → tkfluent-0.1.4}/tkflu/label.py +0 -0
- {tkfluent-0.1.3 → tkfluent-0.1.4}/tkflu/listbox.py +0 -0
- {tkfluent-0.1.3 → tkfluent-0.1.4}/tkflu/litenav.py +0 -0
- {tkfluent-0.1.3 → tkfluent-0.1.4}/tkflu/menu.py +0 -0
- {tkfluent-0.1.3 → tkfluent-0.1.4}/tkflu/menubar.py +0 -0
- {tkfluent-0.1.3 → tkfluent-0.1.4}/tkflu/popupmenu.py +0 -0
- {tkfluent-0.1.3 → tkfluent-0.1.4}/tkflu/scrollbar.py +0 -0
- {tkfluent-0.1.3 → tkfluent-0.1.4}/tkflu/text.py +0 -0
- {tkfluent-0.1.3 → tkfluent-0.1.4}/tkflu/togglebutton.py +0 -0
- {tkfluent-0.1.3 → tkfluent-0.1.4}/tkflu/toplevel.py +0 -0
- {tkfluent-0.1.3 → tkfluent-0.1.4}/tkflu/window.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: tkfluent
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.4
|
4
4
|
Summary: Fluent(SunValley) Design for Tkinter. Modern GUI
|
5
5
|
License: GPL-3.0
|
6
6
|
Keywords: tkfluent,tksvg,tkinter,fluent,modern,GUI,interface
|
@@ -30,7 +30,7 @@ Requires-Dist: easydict (>=1.13,<2.0)
|
|
30
30
|
Requires-Dist: numpy
|
31
31
|
Requires-Dist: pillow (>=10.2.0,<11.0.0)
|
32
32
|
Requires-Dist: svgwrite (>=1.4.3,<2.0.0)
|
33
|
-
Requires-Dist: tkdeft (==0.0
|
33
|
+
Requires-Dist: tkdeft (==0.1.0)
|
34
34
|
Requires-Dist: tkextrafont (>=0.6.3,<0.7.0)
|
35
35
|
Requires-Dist: tksvg (>=0.7.4,<0.8.0)
|
36
36
|
Project-URL: Documentation, https://tkfluent.netlify.app
|
@@ -1,6 +1,6 @@
|
|
1
1
|
[tool.poetry]
|
2
2
|
name = "tkfluent"
|
3
|
-
version = "0.1.
|
3
|
+
version = "0.1.4"
|
4
4
|
description = "Fluent(SunValley) Design for Tkinter. Modern GUI"
|
5
5
|
authors = ["XiangQinxi <xiangqinxi@outlook.com>"]
|
6
6
|
readme = "README.md"
|
@@ -36,7 +36,7 @@ tksvg = "^0.7.4"
|
|
36
36
|
tkextrafont = "^0.6.3"
|
37
37
|
svgwrite = "^1.4.3"
|
38
38
|
pillow = "^10.2.0"
|
39
|
-
tkdeft = "0.0
|
39
|
+
tkdeft = "0.1.0"
|
40
40
|
easydict = "^1.13"
|
41
41
|
numpy = "*"
|
42
42
|
|
@@ -4,7 +4,7 @@ from tkinter.font import *
|
|
4
4
|
|
5
5
|
purple_primary_color()
|
6
6
|
set_animation_steps(10)
|
7
|
-
set_animation_step_time(
|
7
|
+
set_animation_step_time(12)
|
8
8
|
|
9
9
|
def togglestate():
|
10
10
|
if button1.dcget("state") == NORMAL:
|
@@ -23,7 +23,7 @@ def togglestate():
|
|
23
23
|
entry1._draw()
|
24
24
|
root = FluWindow()
|
25
25
|
#root.wincustom(way=0)
|
26
|
-
root.geometry("
|
26
|
+
root.geometry("360x650")
|
27
27
|
|
28
28
|
popupmenu = FluPopupMenu()
|
29
29
|
|
@@ -108,7 +108,7 @@ entry1.pack(fill="x", padx=5, pady=5)
|
|
108
108
|
text1 = FluText(frame)
|
109
109
|
text1.pack(fill="x", padx=5, pady=5)
|
110
110
|
|
111
|
-
slider1 = FluSlider(frame, value=0)
|
111
|
+
slider1 = FluSlider(frame, value=0, max=200)
|
112
112
|
slider1.pack(fill="x", padx=5, pady=5)
|
113
113
|
|
114
114
|
"""listbox1 = FluListBox(frame)
|
@@ -116,5 +116,8 @@ listbox1.dconfigure()
|
|
116
116
|
listbox1.pack(fill="x", padx=5, pady=5)"""
|
117
117
|
|
118
118
|
frame.pack(fill="both", expand="yes", side="right", padx=15, pady=15)
|
119
|
-
frame.update_idletasks()
|
119
|
+
#frame.update_idletasks()
|
120
|
+
|
121
|
+
#thememanager.mode("light")
|
122
|
+
|
120
123
|
root.mainloop()
|
@@ -0,0 +1,56 @@
|
|
1
|
+
def scrollbar(mode, state=None):
|
2
|
+
"""滚动栏设计配置"""
|
3
|
+
if mode.lower() == "dark":
|
4
|
+
return {
|
5
|
+
"rest": {
|
6
|
+
"track_color": "#202020",
|
7
|
+
"track_opacity": 0.5,
|
8
|
+
"thumb_color": "#606060",
|
9
|
+
"thumb_opacity": 0.8
|
10
|
+
},
|
11
|
+
"hover": {
|
12
|
+
"track_color": "#202020",
|
13
|
+
"track_opacity": 0.7,
|
14
|
+
"thumb_color": "#808080",
|
15
|
+
"thumb_opacity": 1.0
|
16
|
+
},
|
17
|
+
"pressed": {
|
18
|
+
"track_color": "#202020",
|
19
|
+
"track_opacity": 0.9,
|
20
|
+
"thumb_color": "#A0A0A0",
|
21
|
+
"thumb_opacity": 1.0
|
22
|
+
},
|
23
|
+
"disabled": {
|
24
|
+
"track_color": "#202020",
|
25
|
+
"track_opacity": 0.3,
|
26
|
+
"thumb_color": "#404040",
|
27
|
+
"thumb_opacity": 0.5
|
28
|
+
}
|
29
|
+
}
|
30
|
+
else: # light mode
|
31
|
+
return {
|
32
|
+
"rest": {
|
33
|
+
"track_color": "#F0F0F0",
|
34
|
+
"track_opacity": 0.5,
|
35
|
+
"thumb_color": "#C0C0C0",
|
36
|
+
"thumb_opacity": 0.8
|
37
|
+
},
|
38
|
+
"hover": {
|
39
|
+
"track_color": "#F0F0F0",
|
40
|
+
"track_opacity": 0.7,
|
41
|
+
"thumb_color": "#A0A0A0",
|
42
|
+
"thumb_opacity": 1.0
|
43
|
+
},
|
44
|
+
"pressed": {
|
45
|
+
"track_color": "#F0F0F0",
|
46
|
+
"track_opacity": 0.9,
|
47
|
+
"thumb_color": "#808080",
|
48
|
+
"thumb_opacity": 1.0
|
49
|
+
},
|
50
|
+
"disabled": {
|
51
|
+
"track_color": "#F0F0F0",
|
52
|
+
"track_opacity": 0.3,
|
53
|
+
"thumb_color": "#E0E0E0",
|
54
|
+
"thumb_opacity": 0.5
|
55
|
+
}
|
56
|
+
}
|
@@ -13,6 +13,8 @@ def slider(mode: str, state: str):
|
|
13
13
|
"radius": 12,
|
14
14
|
"inner_radius": 6,
|
15
15
|
|
16
|
+
"width": 28,
|
17
|
+
|
16
18
|
"back_color": "#FFFFFF",
|
17
19
|
"back_opacity": 1,
|
18
20
|
|
@@ -43,6 +45,8 @@ def slider(mode: str, state: str):
|
|
43
45
|
"radius": 12,
|
44
46
|
"inner_radius": 8,
|
45
47
|
|
48
|
+
"width": 28,
|
49
|
+
|
46
50
|
"back_color": "#FFFFFF",
|
47
51
|
"back_opacity": 1,
|
48
52
|
|
@@ -73,6 +77,8 @@ def slider(mode: str, state: str):
|
|
73
77
|
"radius": 12,
|
74
78
|
"inner_radius": 5,
|
75
79
|
|
80
|
+
"width": 28,
|
81
|
+
|
76
82
|
"back_color": "#FFFFFF",
|
77
83
|
"back_opacity": 1,
|
78
84
|
|
@@ -103,6 +109,8 @@ def slider(mode: str, state: str):
|
|
103
109
|
"radius": 12,
|
104
110
|
"inner_radius": 6,
|
105
111
|
|
112
|
+
"width": 28,
|
113
|
+
|
106
114
|
"back_color": "#FFFFFF",
|
107
115
|
"back_opacity": 1,
|
108
116
|
|
@@ -133,6 +141,8 @@ def slider(mode: str, state: str):
|
|
133
141
|
"thumb": {
|
134
142
|
"radius": 12,
|
135
143
|
|
144
|
+
"width": 28,
|
145
|
+
|
136
146
|
"inner_radius": 6,
|
137
147
|
"inner_back_color": get_primary_color()[1],
|
138
148
|
"inner_back_opacity": 1,
|
@@ -164,6 +174,8 @@ def slider(mode: str, state: str):
|
|
164
174
|
"thumb": {
|
165
175
|
"radius": 12,
|
166
176
|
|
177
|
+
"width": 28,
|
178
|
+
|
167
179
|
"inner_radius": 8,
|
168
180
|
"inner_back_color": get_primary_color()[1],
|
169
181
|
"inner_back_opacity": 1,
|
@@ -195,6 +207,8 @@ def slider(mode: str, state: str):
|
|
195
207
|
"thumb": {
|
196
208
|
"radius": 12,
|
197
209
|
|
210
|
+
"width": 28,
|
211
|
+
|
198
212
|
"inner_radius": 5,
|
199
213
|
"inner_back_color": get_primary_color()[1],
|
200
214
|
"inner_back_opacity": 0.8,
|
@@ -226,6 +240,8 @@ def slider(mode: str, state: str):
|
|
226
240
|
"thumb": {
|
227
241
|
"radius": 12,
|
228
242
|
|
243
|
+
"width": 28,
|
244
|
+
|
229
245
|
"inner_radius": 6,
|
230
246
|
"inner_back_color": "#FFFFFF",
|
231
247
|
"inner_back_opacity": 0.158100,
|
@@ -0,0 +1,66 @@
|
|
1
|
+
from tkinter import Toplevel
|
2
|
+
|
3
|
+
|
4
|
+
class FluPopupWindow(Toplevel):
|
5
|
+
def __init__(self, *args, transparent_color="#ebebeb", mode="light", width=100, height=46, custom=True, **kwargs):
|
6
|
+
super().__init__(*args, background=transparent_color, **kwargs)
|
7
|
+
|
8
|
+
self.theme(mode=mode)
|
9
|
+
|
10
|
+
if width > 0 and height > 0:
|
11
|
+
self.geometry(f"{width}x{height}")
|
12
|
+
|
13
|
+
if custom:
|
14
|
+
self.transient_color = transparent_color
|
15
|
+
self.overrideredirect(True)
|
16
|
+
self.wm_attributes("-transparentcolor", transparent_color)
|
17
|
+
|
18
|
+
self.withdraw()
|
19
|
+
|
20
|
+
self.bind("<FocusOut>", self._event_focusout, add="+")
|
21
|
+
|
22
|
+
def _event_focusout(self, event=None):
|
23
|
+
"""self.wm_attributes("-alpha", 1)
|
24
|
+
self.deiconify()
|
25
|
+
|
26
|
+
from .designs.animation import get_animation_steps, get_animation_step_time
|
27
|
+
|
28
|
+
FRAMES_COUNT = get_animation_steps()
|
29
|
+
FRAME_DELAY = get_animation_step_time()
|
30
|
+
|
31
|
+
def fade_out(step=1):
|
32
|
+
alpha = step / FRAMES_COUNT # 按帧数变化,从0到1
|
33
|
+
self.wm_attributes("-alpha", alpha)
|
34
|
+
if step < FRAMES_COUNT:
|
35
|
+
# 每执行一次,增加一次透明度,间隔由帧数决定
|
36
|
+
self.after(int(round(FRAME_DELAY * FRAMES_COUNT / FRAMES_COUNT)), lambda: fade_out(step - 1))
|
37
|
+
|
38
|
+
fade_out() # 启动动画"""
|
39
|
+
self.withdraw()
|
40
|
+
|
41
|
+
def popup(self, x, y):
|
42
|
+
self.geometry(f"+{x}+{y}")
|
43
|
+
#self.focus_set()
|
44
|
+
self.wm_attributes("-alpha", 0.0)
|
45
|
+
self.deiconify()
|
46
|
+
|
47
|
+
from .designs.animation import get_animation_steps, get_animation_step_time
|
48
|
+
|
49
|
+
FRAMES_COUNT = get_animation_steps()
|
50
|
+
FRAME_DELAY = get_animation_step_time()
|
51
|
+
|
52
|
+
def fade_in(step=0):
|
53
|
+
alpha = step / FRAMES_COUNT # 按帧数变化,从0到1
|
54
|
+
self.wm_attributes("-alpha", alpha)
|
55
|
+
if step < FRAMES_COUNT:
|
56
|
+
# 每执行一次,增加一次透明度,间隔由帧数决定
|
57
|
+
self.after(int(round(FRAME_DELAY*FRAMES_COUNT / FRAMES_COUNT)), lambda: fade_in(step + 1))
|
58
|
+
|
59
|
+
fade_in() # 启动动画
|
60
|
+
|
61
|
+
def theme(self, mode=None):
|
62
|
+
if mode:
|
63
|
+
self.mode = mode
|
64
|
+
for widget in self.winfo_children():
|
65
|
+
if hasattr(widget, "theme"):
|
66
|
+
widget.theme(mode=self.mode.lower())
|
@@ -1,85 +1,75 @@
|
|
1
|
-
from tkdeft.windows.draw import DSvgDraw
|
2
1
|
from tkdeft.windows.canvas import DCanvas
|
2
|
+
from tkdeft.windows.draw import DSvgDraw
|
3
3
|
from tkdeft.windows.drawwidget import DDrawWidget
|
4
4
|
|
5
5
|
from .designs.slider import slider
|
6
6
|
|
7
7
|
|
8
8
|
class FluSliderDraw(DSvgDraw):
|
9
|
-
def
|
9
|
+
def create_track(
|
10
10
|
self,
|
11
|
-
|
12
|
-
x3, # 滑块的x坐标
|
13
|
-
r1, # 滑块外圆半径
|
14
|
-
r2, # 滑块内圆半径
|
11
|
+
width, height, width2,
|
15
12
|
temppath=None,
|
16
|
-
fill="transparent", fill_opacity=1, # 滑块外圆的背景颜色、透明度
|
17
13
|
radius=3, # 滑块进度条圆角大小
|
18
|
-
|
19
|
-
outline2="transparent", outline2_opacity=1, # 滑块伪阴影的渐变色中的第二个渐变颜色、透明度
|
20
|
-
inner_fill="transparent", inner_fill_opacity=1, # 滑块内圆的背景颜色、透明度
|
21
|
-
track_fill="transparent", track_height=4, track_opacity=1, # 滑块进度条的选中部分矩形的背景颜色、高度、透明度
|
14
|
+
track_fill="transparent", track_opacity=1, # 滑块进度条的选中部分矩形的背景颜色、高度、透明度
|
22
15
|
rail_fill="transparent", rail_opacity=1 #
|
23
16
|
):
|
24
|
-
drawing = self.create_drawing(
|
25
|
-
|
26
|
-
border = drawing[1].linearGradient(start=(r1, 1), end=(r1, r1 * 2 - 1), id="DButton.Border",
|
27
|
-
gradientUnits="userSpaceOnUse")
|
28
|
-
border.add_stop_color(0.500208, outline, outline_opacity)
|
29
|
-
border.add_stop_color(0.954545, outline2, outline2_opacity)
|
30
|
-
drawing[1].defs.add(border)
|
31
|
-
stroke = f"url(#{border.get_id()})"
|
32
|
-
#print("x1:", x1, "\n", "y1:", y1, "\n", "x2:", x2, "\n", "y2:", y2, "\n", "r1:", r1, "\n", sep="")
|
33
|
-
|
34
|
-
x = x1 + r1 - 4
|
35
|
-
xx = x2 - r1 + 4
|
36
|
-
|
37
|
-
#print("track_x1:", x, "\n", "track_x2:", xx, sep="")
|
38
|
-
|
39
|
-
#print("")
|
17
|
+
drawing = self.create_drawing(width, height, temppath=temppath, fill_opacity=0)
|
40
18
|
|
41
19
|
drawing[1].add(
|
42
20
|
drawing[1].rect(
|
43
|
-
(
|
44
|
-
# 矩形x位置:画布最左的x坐标 + 滑块外半径 - 滑块内半径
|
45
|
-
# 矩形y位置:画布高度(画布最上的y坐标 - 画布最上的y坐标)一半 - 进度条的高度的一半
|
46
|
-
(xx - x, track_height),
|
47
|
-
# 矩形宽度:画布最右的x坐标 - 滑块外半径 + 滑块内半径 | 矩形高度:进度条的高度
|
21
|
+
(0, 0), (width2, height),
|
48
22
|
rx=radius,
|
49
|
-
fill=
|
23
|
+
fill=track_fill, fill_opacity=track_opacity, fill_rule="evenodd"
|
50
24
|
)
|
51
|
-
) #
|
25
|
+
) # 滑块进度左边的选中区域 (只左部分)
|
52
26
|
|
53
27
|
drawing[1].add(
|
54
28
|
drawing[1].rect(
|
55
|
-
(
|
56
|
-
# 矩形x位置:画布最左的x坐标 + 滑块外半径 - 滑块内半径
|
57
|
-
# 矩形y位置:画布高度(画布最上的y坐标 - 画布最上的y坐标)一半 - 进度条的高度的一半
|
58
|
-
(x3 - x, track_height),
|
59
|
-
# 矩形宽度:(滑块的x坐标 - 矩形x位置) | 矩形高度:进度条的高度
|
29
|
+
(width2, 0), (width-width2, height),
|
60
30
|
rx=radius,
|
61
|
-
fill=
|
31
|
+
fill=rail_fill, fill_opacity=rail_opacity
|
62
32
|
)
|
63
|
-
) #
|
33
|
+
) # 滑块进度未选中区域 (占全部)
|
34
|
+
|
35
|
+
drawing[1].save()
|
36
|
+
return drawing[0]
|
37
|
+
|
38
|
+
def create_thumb(
|
39
|
+
self,
|
40
|
+
width, height,
|
41
|
+
r1, # 滑块外圆半径
|
42
|
+
r2, # 滑块内圆半径
|
43
|
+
temppath=None,
|
44
|
+
fill="transparent", fill_opacity=1, # 滑块外圆的背景颜色、透明度
|
45
|
+
outline="transparent", outline_opacity=1, # 滑块伪阴影的渐变色中的第一个渐变颜色、透明度
|
46
|
+
outline2="transparent", outline2_opacity=1, # 滑块伪阴影的渐变色中的第二个渐变颜色、透明度
|
47
|
+
inner_fill="transparent", inner_fill_opacity=1, # 滑块内圆的背景颜色、透明度
|
48
|
+
):
|
49
|
+
drawing = self.create_drawing(width, height, temppath=temppath, fill_opacity=0)
|
64
50
|
|
65
|
-
|
66
|
-
|
51
|
+
border = drawing[1].linearGradient(start=(r1, 1), end=(r1, r1 * 2 - 1), id="DButton.Border",
|
52
|
+
gradientUnits="userSpaceOnUse")
|
53
|
+
border.add_stop_color(0.500208, outline, outline_opacity)
|
54
|
+
border.add_stop_color(0.954545, outline2, outline2_opacity)
|
55
|
+
drawing[1].defs.add(border)
|
56
|
+
stroke = f"url(#{border.get_id()})"
|
67
57
|
|
68
58
|
drawing[1].add(
|
69
59
|
drawing[1].circle(
|
70
|
-
(
|
60
|
+
(width / 2, height / 2), r1,
|
71
61
|
fill=stroke, fill_opacity=1, fill_rule="evenodd"
|
72
62
|
)
|
73
63
|
) # 圆形滑块的伪阴影边框
|
74
64
|
drawing[1].add(
|
75
65
|
drawing[1].circle(
|
76
|
-
(
|
66
|
+
(width / 2, height / 2), r1 - 1,
|
77
67
|
fill=fill, fill_opacity=fill_opacity, fill_rule="nonzero"
|
78
68
|
)
|
79
69
|
) # 圆形滑块的外填充
|
80
70
|
drawing[1].add(
|
81
71
|
drawing[1].circle(
|
82
|
-
(
|
72
|
+
(width / 2, height / 2), r2,
|
83
73
|
fill=inner_fill, fill_opacity=inner_fill_opacity, fill_rule="nonzero"
|
84
74
|
)
|
85
75
|
) # 圆形滑块的内填充
|
@@ -90,23 +80,35 @@ class FluSliderDraw(DSvgDraw):
|
|
90
80
|
class FluSliderCanvas(DCanvas):
|
91
81
|
draw = FluSliderDraw
|
92
82
|
|
93
|
-
def
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
83
|
+
def create_track(
|
84
|
+
self,
|
85
|
+
x1, y1, width, height, width2, temppath=None, radius=3,
|
86
|
+
track_fill="transparent", track_opacity=1,
|
87
|
+
rail_fill="transparent", rail_opacity=1
|
88
|
+
):
|
89
|
+
self._img2 = self.svgdraw.create_track(
|
90
|
+
width, height, width2, temppath=temppath, radius=radius,
|
91
|
+
track_fill=track_fill, track_opacity=track_opacity,
|
92
|
+
rail_fill=rail_fill, rail_opacity=rail_opacity
|
93
|
+
)
|
94
|
+
self._tkimg2 = self.svgdraw.create_tksvg_image(self._img2)
|
95
|
+
#print(self._img2)
|
96
|
+
return self.create_image(x1, y1, anchor="nw", image=self._tkimg2)
|
97
|
+
|
98
|
+
def create_thumb(
|
99
|
+
self,
|
100
|
+
x1, y1, width, height, r1, r2, temppath=None,
|
101
|
+
fill="transparent", fill_opacity=1,
|
102
|
+
outline="transparent", outline_opacity=1,
|
103
|
+
outline2="transparent", outline2_opacity=1,
|
104
|
+
inner_fill="transparent", inner_fill_opacity=1,
|
105
|
+
):
|
106
|
+
self._img = self.svgdraw.create_thumb(
|
107
|
+
width, height, r1, r2, temppath=temppath,
|
108
|
+
fill=fill, fill_opacity=fill_opacity,
|
105
109
|
outline=outline, outline_opacity=outline_opacity,
|
106
110
|
outline2=outline2, outline2_opacity=outline2_opacity,
|
107
111
|
inner_fill=inner_fill, inner_fill_opacity=inner_fill_opacity,
|
108
|
-
track_fill=track_fill, track_height=track_height, track_opacity=track_opacity,
|
109
|
-
rail_fill=rail_fill, rail_opacity=rail_opacity
|
110
112
|
)
|
111
113
|
self._tkimg = self.svgdraw.create_tksvg_image(self._img)
|
112
114
|
return self.create_image(x1, y1, anchor="nw", image=self._tkimg)
|
@@ -152,7 +154,9 @@ class FluSlider(FluSliderCanvas, DDrawWidget):
|
|
152
154
|
|
153
155
|
self.bind("<<Clicked>>", lambda event=None: self.focus_set(), add="+")
|
154
156
|
|
155
|
-
self.bind("<Motion>", self._event_button1_motion)
|
157
|
+
self.bind("<B1-Motion>", self._event_button1_motion)
|
158
|
+
|
159
|
+
self.enter_thumb = False
|
156
160
|
|
157
161
|
from .defs import set_default_font
|
158
162
|
set_default_font(font, self.attributes)
|
@@ -192,6 +196,11 @@ class FluSlider(FluSliderCanvas, DDrawWidget):
|
|
192
196
|
|
193
197
|
#print("")
|
194
198
|
|
199
|
+
if hasattr(self, "_e1"):
|
200
|
+
self.tag_unbind(self.element_track, "<Enter>", self._e1)
|
201
|
+
if hasattr(self, "_e2"):
|
202
|
+
self.tag_unbind(self.element_track, "<Leave>", self._e2)
|
203
|
+
|
195
204
|
self.delete("all")
|
196
205
|
|
197
206
|
state = self.dcget("state")
|
@@ -200,13 +209,16 @@ class FluSlider(FluSliderCanvas, DDrawWidget):
|
|
200
209
|
|
201
210
|
if state == "normal":
|
202
211
|
if event:
|
203
|
-
if self.enter:
|
204
|
-
if self.
|
205
|
-
|
212
|
+
if self.enter: # 先检查是否在组件内
|
213
|
+
if self.enter_thumb: # 再检查是否在滑块上
|
214
|
+
if self.button1:
|
215
|
+
_dict = self.attributes.pressed
|
216
|
+
else:
|
217
|
+
_dict = self.attributes.hover
|
206
218
|
else:
|
207
|
-
_dict = self.attributes.hover
|
219
|
+
_dict = self.attributes.hover # 在组件内但不在滑块上
|
208
220
|
else:
|
209
|
-
_dict = self.attributes.rest
|
221
|
+
_dict = self.attributes.rest # 不在组件内
|
210
222
|
else:
|
211
223
|
_dict = self.attributes.rest
|
212
224
|
else:
|
@@ -224,6 +236,8 @@ class FluSlider(FluSliderCanvas, DDrawWidget):
|
|
224
236
|
_thumb_radius = _dict.thumb.radius
|
225
237
|
_thumb_inner_radius = _dict.thumb.inner_radius
|
226
238
|
|
239
|
+
_thumb_width = _dict.thumb.width
|
240
|
+
|
227
241
|
_thumb_back_color = _dict.thumb.back_color
|
228
242
|
_thumb_back_opacity = _dict.thumb.back_opacity
|
229
243
|
|
@@ -237,34 +251,81 @@ class FluSlider(FluSliderCanvas, DDrawWidget):
|
|
237
251
|
_thumb_inner_back_opacity = _dict.thumb.inner_back_opacity
|
238
252
|
|
239
253
|
thumb_xp = self.attributes.value / (self.attributes.max - self.attributes.min) # 滑块对应数值的比例
|
240
|
-
thumb_x =
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
254
|
+
thumb_x = self.winfo_width() * thumb_xp # 滑块对应数值的x左边
|
255
|
+
|
256
|
+
width = self.winfo_width()
|
257
|
+
height = self.winfo_height()
|
258
|
+
# 修改滑块位置计算
|
259
|
+
thumb_width = _thumb_width
|
260
|
+
min_x = thumb_width / 2
|
261
|
+
max_x = self.winfo_width() - thumb_width / 2
|
262
|
+
track_length = max_x - min_x
|
263
|
+
|
264
|
+
# 计算轨道实际可用宽度(减去滑块宽度)
|
265
|
+
effective_track_width = self.winfo_width() - thumb_width
|
266
|
+
|
267
|
+
thumb_xp = (self.attributes.value - self.attributes.min) / (self.attributes.max - self.attributes.min)
|
268
|
+
thumb_center = thumb_width / 2 + thumb_xp * effective_track_width
|
269
|
+
|
270
|
+
thumb_width = _thumb_width
|
271
|
+
effective_width = self.winfo_width() - thumb_width
|
272
|
+
ratio = (self.attributes.value - self.attributes.min) / (self.attributes.max - self.attributes.min)
|
273
|
+
thumb_left = thumb_width / 2 + ratio * effective_width - thumb_width / 2
|
274
|
+
|
275
|
+
# 确保不会超出右边界
|
276
|
+
thumb_left = min(thumb_left, self.winfo_width() - thumb_width)
|
277
|
+
|
278
|
+
# 创建轨道时,width2 参数应为选中部分的宽度(滑块中心位置)
|
279
|
+
self.element_track = self.create_track(
|
280
|
+
_thumb_width / 4,
|
281
|
+
height / 2 - _track_height,
|
282
|
+
self.winfo_width() - _thumb_width / 2,
|
283
|
+
_track_height,
|
284
|
+
thumb_center - _thumb_width / 4, # 关键修正:使用滑块中心相对于轨道起点的距离
|
285
|
+
temppath=self.temppath, radius=_radius,
|
286
|
+
track_fill=_track_back_color, track_opacity=_track_back_opacity,
|
287
|
+
rail_fill=_rail_back_color, rail_opacity=_rail_back_opacity
|
288
|
+
)
|
245
289
|
|
246
|
-
self.element_thumb = self.
|
247
|
-
|
248
|
-
|
249
|
-
|
290
|
+
self.element_thumb = self.create_thumb(
|
291
|
+
thumb_left, 0, # 直接使用计算出的左上角位置
|
292
|
+
thumb_width, thumb_width,
|
293
|
+
_thumb_radius, _thumb_inner_radius,
|
294
|
+
temppath=self.temppath2, fill=_thumb_back_color, fill_opacity=_thumb_back_opacity,
|
250
295
|
outline=_thumb_border_color, outline_opacity=_thumb_border_color_opacity,
|
251
296
|
outline2=_thumb_border_color2, outline2_opacity=_thumb_border_color2_opacity,
|
252
297
|
inner_fill=_thumb_inner_back_color, inner_fill_opacity=_thumb_inner_back_opacity,
|
253
|
-
track_height=_track_height, track_fill=_track_back_color, track_opacity=_track_back_opacity,
|
254
|
-
rail_fill=_rail_back_color, rail_opacity=_rail_back_opacity
|
255
298
|
)
|
256
299
|
|
300
|
+
self._e1 = self.tag_bind(self.element_thumb, "<Enter>", self._event_enter_thumb, add="+")
|
301
|
+
self._e2 = self.tag_bind(self.element_thumb, "<Leave>", self._event_leave_thumb, add="+")
|
302
|
+
|
257
303
|
def pos(self, event):
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
304
|
+
#print(event.x, event.y)
|
305
|
+
#if self.enter and self.button1:
|
306
|
+
# 获取滑块宽度
|
307
|
+
thumb_width = self.attributes.pressed.thumb.width
|
308
|
+
|
309
|
+
# 计算有效轨道长度
|
310
|
+
effective_width = self.winfo_width() - thumb_width
|
311
|
+
|
312
|
+
# 计算滑块位置比例(考虑滑块宽度边界)
|
313
|
+
ratio = (event.x - thumb_width/2) / effective_width
|
314
|
+
ratio = max(0, min(1, ratio)) # 限制在0-1范围内
|
315
|
+
|
316
|
+
# 计算实际值
|
317
|
+
value = self.attributes.min + ratio * (self.attributes.max - self.attributes.min)
|
318
|
+
self.dconfigure(value=value)
|
319
|
+
self._draw()
|
320
|
+
#print(self.focus_get())
|
321
|
+
|
322
|
+
|
323
|
+
def _event_enter_thumb(self, event=None):
|
324
|
+
self.enter_thumb = True
|
325
|
+
self.update()
|
326
|
+
|
327
|
+
def _event_leave_thumb(self, event=None):
|
328
|
+
self.enter_thumb = False
|
268
329
|
|
269
330
|
def _event_button1_motion(self, event):
|
270
331
|
self.pos(event)
|
@@ -293,6 +354,8 @@ class FluSlider(FluSliderCanvas, DDrawWidget):
|
|
293
354
|
"radius": r["thumb"]["radius"],
|
294
355
|
"inner_radius": r["thumb"]["inner_radius"],
|
295
356
|
|
357
|
+
"width": r["thumb"]["width"],
|
358
|
+
|
296
359
|
"back_color": r["thumb"]["back_color"],
|
297
360
|
"back_opacity": r["thumb"]["back_opacity"],
|
298
361
|
|
@@ -320,6 +383,8 @@ class FluSlider(FluSliderCanvas, DDrawWidget):
|
|
320
383
|
"radius": h["thumb"]["radius"],
|
321
384
|
"inner_radius": h["thumb"]["inner_radius"],
|
322
385
|
|
386
|
+
"width": r["thumb"]["width"],
|
387
|
+
|
323
388
|
"back_color": h["thumb"]["back_color"],
|
324
389
|
"back_opacity": h["thumb"]["back_opacity"],
|
325
390
|
|
@@ -347,6 +412,8 @@ class FluSlider(FluSliderCanvas, DDrawWidget):
|
|
347
412
|
"radius": p["thumb"]["radius"],
|
348
413
|
"inner_radius": p["thumb"]["inner_radius"],
|
349
414
|
|
415
|
+
"width": r["thumb"]["width"],
|
416
|
+
|
350
417
|
"back_color": p["thumb"]["back_color"],
|
351
418
|
"back_opacity": p["thumb"]["back_opacity"],
|
352
419
|
|
@@ -374,6 +441,8 @@ class FluSlider(FluSliderCanvas, DDrawWidget):
|
|
374
441
|
"radius": d["thumb"]["radius"],
|
375
442
|
"inner_radius": d["thumb"]["inner_radius"],
|
376
443
|
|
444
|
+
"width": r["thumb"]["width"],
|
445
|
+
|
377
446
|
"back_color": d["thumb"]["back_color"],
|
378
447
|
"back_opacity": d["thumb"]["back_opacity"],
|
379
448
|
|
@@ -11,17 +11,18 @@ class FluThemeManager(object):
|
|
11
11
|
from tkinter import _default_root
|
12
12
|
self._window = _default_root
|
13
13
|
self._mode = mode
|
14
|
-
self.mode(self._mode)
|
15
|
-
self._window.after(delay, lambda: self.mode(self._mode))
|
14
|
+
#self.mode(self._mode)
|
15
|
+
#self._window.after(delay, lambda: self.mode(self._mode))
|
16
16
|
|
17
|
-
def mode(self, mode: str, delay: Union[int, None] =
|
18
|
-
def
|
17
|
+
def mode(self, mode: str, delay: Union[int, None] = None):
|
18
|
+
def update_window():
|
19
19
|
self._mode = mode
|
20
20
|
if hasattr(self._window, "theme"):
|
21
21
|
self._window.theme(mode=mode)
|
22
22
|
if hasattr(self._window, "_draw"):
|
23
23
|
self._window._draw()
|
24
24
|
self._window.update()
|
25
|
+
def update_children():
|
25
26
|
for widget in self._window.winfo_children():
|
26
27
|
if hasattr(widget, "theme"):
|
27
28
|
widget.theme(mode=mode)
|
@@ -30,19 +31,18 @@ class FluThemeManager(object):
|
|
30
31
|
if hasattr(widget, "update_children"):
|
31
32
|
widget.update_children()
|
32
33
|
#widget.update()
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
def __():
|
34
|
+
update_window()
|
35
|
+
update_children()
|
36
|
+
|
37
|
+
def update_children2():
|
38
38
|
for widget in self._window.winfo_children():
|
39
39
|
if hasattr(widget, "_draw"):
|
40
40
|
widget._draw()
|
41
41
|
if hasattr(widget, "update_children"):
|
42
42
|
widget.update_children()
|
43
43
|
widget.update()
|
44
|
-
|
45
|
-
self._window.after(
|
44
|
+
|
45
|
+
#self._window.after(len(self._window.winfo_children())*50, update_children2)
|
46
46
|
|
47
47
|
def toggle(self, delay: Union[int, None] = None):
|
48
48
|
if self._mode == "light":
|
@@ -40,10 +40,6 @@ class FluToolTip(FluPopupWindow):
|
|
40
40
|
self.wm_attributes("-alpha", 0.0)
|
41
41
|
self.deiconify()
|
42
42
|
|
43
|
-
# 设置初始透明度为0
|
44
|
-
|
45
|
-
|
46
|
-
# 渐显动画
|
47
43
|
def fade_in(step=0):
|
48
44
|
FRAMES_COUNT = 20
|
49
45
|
alpha = step / FRAMES_COUNT # 按帧数变化,从0到1
|
@@ -131,8 +127,7 @@ class FluToolTip2(FluPopupWindow):
|
|
131
127
|
background=n["back_color"]
|
132
128
|
)
|
133
129
|
|
134
|
-
|
135
|
-
self.wm_attributes("-transparentcolor", n["back_color"])
|
130
|
+
self.wm_attributes("-transparentcolor", n["back_color"])
|
136
131
|
#print(n["back_color"])
|
137
132
|
if hasattr(self, "_frame"):
|
138
133
|
self._frame.dconfigure(
|
@@ -1,33 +0,0 @@
|
|
1
|
-
from tkinter import Toplevel
|
2
|
-
|
3
|
-
|
4
|
-
class FluPopupWindow(Toplevel):
|
5
|
-
def __init__(self, *args, transparent_color="#ebebeb", mode="light", width=100, height=46, custom=True, **kwargs):
|
6
|
-
super().__init__(*args, background=transparent_color, **kwargs)
|
7
|
-
|
8
|
-
self.theme(mode=mode)
|
9
|
-
|
10
|
-
self.geometry(f"{width}x{height}")
|
11
|
-
|
12
|
-
if custom:
|
13
|
-
self.transient_color = transparent_color
|
14
|
-
self.overrideredirect(True)
|
15
|
-
self.wm_attributes("-transparentcolor", transparent_color)
|
16
|
-
|
17
|
-
self.withdraw()
|
18
|
-
|
19
|
-
self.bind("<FocusOut>", self._event_focusout, add="+")
|
20
|
-
|
21
|
-
def _event_focusout(self, event=None):
|
22
|
-
self.withdraw()
|
23
|
-
|
24
|
-
def popup(self, x, y):
|
25
|
-
self.geometry(f"+{x}+{y}")
|
26
|
-
#self.focus_set()
|
27
|
-
|
28
|
-
def theme(self, mode=None):
|
29
|
-
if mode:
|
30
|
-
self.mode = mode
|
31
|
-
for widget in self.winfo_children():
|
32
|
-
if hasattr(widget, "theme"):
|
33
|
-
widget.theme(mode=self.mode.lower())
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|