tkfluent 0.1.1__py3-none-any.whl → 0.1.3__py3-none-any.whl

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.
tkflu/__init__.py CHANGED
@@ -1,9 +1,11 @@
1
- """
1
+ """
2
2
 
3
3
  Fluent设计的tkinter组件库(模板)
4
4
 
5
5
  -------------
6
6
  作者:XiangQinxi
7
+
8
+ 贡献者:totowang-hhh
7
9
  -------------
8
10
  """
9
11
 
tkflu/__main__.py CHANGED
@@ -2,7 +2,9 @@ from tkflu import *
2
2
  from tkinter import *
3
3
  from tkinter.font import *
4
4
 
5
- blue_primary_color()
5
+ purple_primary_color()
6
+ set_animation_steps(10)
7
+ set_animation_step_time(10)
6
8
 
7
9
  def togglestate():
8
10
  if button1.dcget("state") == NORMAL:
tkflu/button.py CHANGED
@@ -4,13 +4,39 @@ from tkdeft.windows.drawwidget import DDrawWidget
4
4
 
5
5
  from .designs.button import button
6
6
 
7
+ from typing import Union
8
+
7
9
 
8
10
  class FluButtonDraw(DSvgDraw):
9
11
  def create_roundrect(self,
10
- x1, y1, x2, y2, radius, radiusy=None, temppath=None,
11
- fill="transparent", fill_opacity=1,
12
- outline="black", outline2=None, outline_opacity=1, outline2_opacity=1, width=1,
13
- ):
12
+ x1: Union[int, float], y1: Union[int, float], x2: Union[int, float], y2: Union[int, float],
13
+ radius: Union[int, float], radiusy: Union[int, float] = None, temppath: Union[str, None] = None,
14
+ fill: Union[str, tuple]="transparent", fill_opacity: Union[int, float]=1,
15
+ outline: Union[str, tuple] = "black", outline2: Union[str, tuple] = None,
16
+ outline_opacity: Union[int, float] = 1, outline2_opacity: Union[int, float] = 1, width: Union[int, float] = 1,
17
+ ) -> str:
18
+ """
19
+ 用于生成svg圆角矩形图片,图片默认将会保存至临时文件夹。
20
+
21
+ Parameters:
22
+ x1: 第一个x轴的坐标
23
+ y1: 第一个y轴的坐标
24
+ x2: 第二个x轴的坐标,与x1连起来
25
+ y2: 第二个y轴的坐标,与y1连起来
26
+ radius: 圆角大小
27
+ radiusy: 圆角大小(y轴方向),如果不设置,将默认为参数radius的值
28
+ temppath: 临时文件地址,如果你不知道,就别设置
29
+ fill: 背景颜色
30
+ fill_opacity: 背景透明度
31
+ outline: 边框颜色
32
+ outline2: 边框颜色2(渐变),如果取了这个值,边框将会变为渐变,从左到右,outline为第一个渐变色,outline2为第二个渐变色
33
+ outline_opacity: 边框透明度
34
+ outline2_opacity: 第二个边框渐变颜色的透明度,如果outline没有设置,则这个值不会被用到
35
+ width: 边框宽度
36
+
37
+ Returns:
38
+ svg图片保存地址
39
+ """
14
40
  if radiusy:
15
41
  _rx = radius
16
42
  _ry = radiusy
@@ -19,9 +45,9 @@ class FluButtonDraw(DSvgDraw):
19
45
  drawing = self.create_drawing(x2 - x1, y2 - y1, temppath=temppath)
20
46
  if outline2:
21
47
  border = drawing[1].linearGradient(start=(x1, y1), end=(x1, y2), id="DButton.Border",
22
- gradientUnits="userSpaceOnUse")
23
- border.add_stop_color("0.9", outline, outline_opacity)
24
- border.add_stop_color("1", outline2, outline2_opacity)
48
+ gradientUnits="userSpaceOnUse") # 渐变色配置
49
+ border.add_stop_color("0.9", outline, outline_opacity) # 第一个渐变色的位置、第一个渐变色、第一个渐变色的透明度
50
+ border.add_stop_color("1", outline2, outline2_opacity) # 第二个渐变色的位置、第二个渐变色、第二个渐变色的透明度
25
51
  drawing[1].defs.add(border)
26
52
  stroke = f"url(#{border.get_id()})"
27
53
  stroke_opacity = 1
@@ -41,41 +67,80 @@ class FluButtonDraw(DSvgDraw):
41
67
 
42
68
 
43
69
  class FluButtonCanvas(DCanvas):
44
- draw = FluButtonDraw
70
+
71
+ draw = FluButtonDraw # 设置svg绘图引擎
45
72
 
46
73
  def create_round_rectangle(self,
47
- x1, y1, x2, y2, r1, r2=None, temppath=None,
48
- fill="transparent", fill_opacity=1,
49
- outline="black", outline2="black", outline_opacity=1, outline2_opacity=1,
50
- width=1,
51
- ):
74
+ x1: Union[int, float], y1: Union[int, float], x2: Union[int, float], y2: Union[int, float],
75
+ r1: Union[int, float], r2: Union[int, float] = None, temppath: Union[str, None] = None,
76
+ fill: Union[str, tuple]="transparent", fill_opacity: Union[int, float] = 1,
77
+ outline: Union[str, tuple] = "black", outline2: Union[str, tuple] = "black",
78
+ outline_opacity: Union[int, float] = 1, outline2_opacity: Union[int, float] = 1,
79
+ width: Union[int, float] = 1, *args, **kwargs
80
+ ) -> int:
81
+ """
82
+ 在画布上创建个圆角矩形
83
+
84
+ Parameters:
85
+ x1: 第一个x轴的坐标
86
+ y1: 第一个y轴的坐标
87
+ x2: 第二个x轴的坐标,与x1连起来
88
+ y2: 第二个y轴的坐标,与y1连起来
89
+ r1: 圆角大小
90
+ r2: 圆角大小(y轴方向),如果不设置,将默认为参数r1的值
91
+ temppath: 临时文件地址,如果你不知道,就别设置
92
+ fill: 背景颜色
93
+ fill_opacity: 背景透明度
94
+ outline: 边框颜色
95
+ outline2: 边框颜色2(渐变),如果取了这个值,边框将会变为渐变,从左到右,outline为第一个渐变色,outline2为第二个渐变色
96
+ outline_opacity: 边框透明度
97
+ outline2_opacity: 第二个边框渐变颜色的透明度,如果outline没有设置,则这个值不会被用到
98
+ width: 边框宽度
99
+
100
+ Returns: svg图片保存地址
101
+ """
52
102
  self._img = self.svgdraw.create_roundrect(
53
103
  x1, y1, x2, y2, r1, r2, temppath=temppath,
54
104
  fill=fill, fill_opacity=fill_opacity,
55
105
  outline=outline, outline2=outline2, outline_opacity=outline_opacity, outline2_opacity=outline2_opacity,
56
106
  width=width,
57
- )
58
- self._tkimg = self.svgdraw.create_tksvg_image(self._img)
59
- return self.create_image(x1, y1, anchor="nw", image=self._tkimg)
107
+ ) # 创建个svg圆角矩形图片
108
+ self._tkimg = self.svgdraw.create_tksvg_image(self._img) # 用tksvg读取svg图片
109
+ return self.create_image(x1, y1, anchor="nw", image=self._tkimg, *args, **kwargs) # 在画布上创建个以svg图片为图片的元件
60
110
 
61
- create_roundrect = create_round_rectangle
111
+ create_roundrect = create_round_rectangle # 缩写
62
112
 
63
113
 
64
114
  from .constants import MODE, STATE, BUTTONSTYLE
65
115
  from .tooltip import FluToolTipBase
66
116
  from .designs.gradient import FluGradient
117
+ from tkinter import Event
118
+ from tkinter.font import Font
67
119
 
68
120
  class FluButton(FluButtonCanvas, DDrawWidget, FluToolTipBase, FluGradient):
69
121
  def __init__(self, *args,
70
- text="",
71
- width=120,
72
- height=32,
73
- command=None,
74
- font=None,
122
+ text: Union[str, int, float]= "",
123
+ width: Union[int, float] = 120,
124
+ height: Union[int, float] = 32,
125
+ command: callable = None,
126
+ font: Union[Font, tuple] = None,
75
127
  mode: MODE = "light",
76
128
  style: BUTTONSTYLE = "standard",
77
129
  state: STATE = "normal",
78
- **kwargs):
130
+ **kwargs) -> None:
131
+ """
132
+ 按钮组件
133
+
134
+ Parameters:
135
+ text: 按钮的标签文本
136
+ width: 默认宽带
137
+ height: 默认高度
138
+ command: 点击时出发的事件
139
+ font: 自定义标签字体
140
+ mode: 按钮深浅主题,参考tkflu.constants.MODE
141
+ style: 按钮样式,参考tkflu.constants.BUTTONSTYLE
142
+ state: 按钮的状态,参考tkflu.constants.STATE
143
+ """
79
144
  self._init(mode, style)
80
145
 
81
146
  super().__init__(*args, width=width, height=height, **kwargs)
@@ -101,6 +166,14 @@ class FluButton(FluButtonCanvas, DDrawWidget, FluToolTipBase, FluGradient):
101
166
 
102
167
  def _init(self, mode: MODE, style: BUTTONSTYLE):
103
168
 
169
+ """
170
+ 初始化按钮,正常情况下无需在程序中调用
171
+
172
+ Parameters:
173
+ mode: 按钮深浅主题,参考tkflu.constants.MODE
174
+ style: 按钮样式,参考tkflu.constants.BUTTONSTYLE
175
+ """
176
+
104
177
  from easydict import EasyDict
105
178
 
106
179
  self.enter = False
@@ -122,13 +195,17 @@ class FluButton(FluButtonCanvas, DDrawWidget, FluToolTipBase, FluGradient):
122
195
 
123
196
  self.theme(mode=mode, style=style)
124
197
 
125
- def _draw(self, event=None, tempcolor: dict = None):
198
+ def _draw(self, event: Union[Event, None] = None, tempcolor: Union[dict, None] = None):
199
+ """
200
+
201
+ Parameters:
202
+ 绘制按钮
203
+ """
126
204
  super()._draw(event)
127
205
 
128
206
  width = self.winfo_width()
129
207
  height = self.winfo_height()
130
-
131
- self.delete("all")
208
+ # 提前定义,反正多次调用浪费资源
132
209
 
133
210
  state = self.dcget("state")
134
211
 
@@ -166,6 +243,9 @@ class FluButton(FluButtonCanvas, DDrawWidget, FluToolTipBase, FluGradient):
166
243
  _radius = tempcolor.radius
167
244
  _text_color = tempcolor.text_color
168
245
 
246
+ if hasattr(self, "element_border"):
247
+ self.delete(self.element_border)
248
+
169
249
  self.element_border = self.create_round_rectangle(
170
250
  0, 0, width, height, _radius, temppath=self.temppath,
171
251
  fill=_back_color, fill_opacity=_back_opacity,
@@ -174,10 +254,15 @@ class FluButton(FluButtonCanvas, DDrawWidget, FluToolTipBase, FluGradient):
174
254
  width=_border_width,
175
255
  )
176
256
 
177
- self.element_text = self.create_text(
178
- self.winfo_width() / 2, self.winfo_height() / 2, anchor="center",
179
- fill=_text_color, text=self.attributes.text, font=self.attributes.font
180
- )
257
+ if hasattr(self, "element_text"):
258
+ self.itemconfigure(self.element_text, fill=_text_color, text=self.attributes.text, font=self.attributes.font)
259
+ self.coords(self.element_text, width / 2, height / 2)
260
+ else:
261
+ self.element_text = self.create_text(
262
+ width / 2, height / 2, anchor="center",
263
+ fill=_text_color, text=self.attributes.text, font=self.attributes.font
264
+ )
265
+ self.tag_raise(self.element_text, self.element_border)
181
266
 
182
267
  self.update()
183
268
 
@@ -186,7 +271,17 @@ class FluButton(FluButtonCanvas, DDrawWidget, FluToolTipBase, FluGradient):
186
271
  self.mode = mode
187
272
  if style:
188
273
  self.style = style
189
- if self.mode.lower() == "dark":
274
+ theme_handlers = {
275
+ ("light", "accent"): self._light_accent,
276
+ ("light", "menu"): self._light_menu,
277
+ ("light", "standard"): self._light,
278
+ ("dark", "accent"): self._dark_accent,
279
+ ("dark", "menu"): self._dark_menu,
280
+ ("dark", "standard"): self._dark,
281
+ }
282
+ handler = theme_handlers.get((self.mode.lower(), self.style.lower()))
283
+ handler()
284
+ """if self.mode.lower() == "dark":
190
285
  if self.style.lower() == "accent":
191
286
  self._dark_accent()
192
287
  elif self.style.lower() == "menu":
@@ -199,72 +294,80 @@ class FluButton(FluButtonCanvas, DDrawWidget, FluToolTipBase, FluGradient):
199
294
  elif self.style.lower() == "menu":
200
295
  self._light_menu()
201
296
  else:
202
- self._light()
203
-
204
- def _theme(self, mode, style, animate_steps: int = 10):
297
+ self._light()"""
298
+
299
+ def _theme(self, mode: MODE, style: BUTTONSTYLE, animation_steps: int = None, animation_step_time: int = None):
300
+ if animation_steps is None:
301
+ from .designs.animation import get_animation_steps
302
+ animation_steps = get_animation_steps()
303
+ if animation_step_time is None:
304
+ from .designs.animation import get_animation_step_time
305
+ animation_step_time = get_animation_step_time()
205
306
  r = button(mode, style, "rest")
206
307
  h = button(mode, style, "hover")
207
308
  p = button(mode, style, "pressed")
208
309
  d = button(mode, style, "disabled")
209
- steps = animate_steps
210
- if self.dcget("state") == "normal":
211
- if self.enter:
212
- if self.button1:
213
- now = p
310
+ if not animation_steps == 0 or not animation_step_time == 0:
311
+ if self.dcget("state") == "normal":
312
+ if self.enter:
313
+ if self.button1:
314
+ now = p
315
+ else:
316
+ now = h
214
317
  else:
215
- now = h
318
+ now = r
216
319
  else:
217
- now = r
218
- else:
219
- now = d
220
- if hasattr(self.attributes.rest, "back_color"):
221
- back_colors = self.generate_hex2hex(
222
- self.attributes.rest.back_color, now["back_color"], steps
223
- )
224
- border_colors = self.generate_hex2hex(
225
- self.attributes.rest.border_color, now["border_color"], steps
226
- )
227
- if self.attributes.rest.border_color2 is None:
228
- self.attributes.rest.border_color2 = self.attributes.rest.border_color
229
- if now["border_color2"] is None:
230
- now["border_color2"] = now["border_color"]
231
- border_colors2 = self.generate_hex2hex(
232
- self.attributes.rest.border_color2, now["border_color2"], steps
233
- )
234
- text_colors = self.generate_hex2hex(
235
- self.attributes.rest.text_color, now["text_color"], steps
236
- )
237
- import numpy as np
238
- back_opacitys = np.linspace(
239
- float(self.attributes.rest.back_opacity), float(now["back_opacity"]), steps).tolist()
240
- border_color_opacitys = np.linspace(
241
- float(self.attributes.rest.border_color_opacity), float(now["border_color_opacity"]), steps).tolist()
242
- if self.attributes.rest.border_color2_opacity is None:
243
- self.attributes.rest.border_color2_opacity = self.attributes.rest.border_color_opacity
244
- if now["border_color2_opacity"] is None:
245
- now["border_color2_opacity"] = now["border_color_opacity"]
246
- border_color2_opacitys = np.linspace(
247
- float(self.attributes.rest.border_color2_opacity), float(now["border_color2_opacity"]), steps).tolist()
248
- for i in range(steps):
249
- def update(ii=i):
250
- from easydict import EasyDict
251
- tempcolor = EasyDict(
252
- {
253
- "back_color": back_colors[ii],
254
- "back_opacity": back_opacitys[ii],
255
- "border_color": border_colors[ii],
256
- "border_color_opacity": str(border_color_opacitys[ii]),
257
- "border_color2": border_colors2[ii],
258
- "border_color2_opacity": str(border_color2_opacitys[ii]),
259
- "border_width": 1,
260
- "text_color": text_colors[ii],
261
- "radius": 6,
262
- }
263
- )
264
- self._draw(None, tempcolor)
265
-
266
- self.after(i * 10, update)
267
- self.after(steps * 10 + 10, lambda: self._draw(None, None))
320
+ now = d
321
+ #print(animation_step_time)
322
+ #print(type(animation_step_time))
323
+ if hasattr(self.attributes.rest, "back_color"):
324
+ back_colors = self.generate_hex2hex(
325
+ self.attributes.rest.back_color, now["back_color"], animation_steps
326
+ )
327
+ border_colors = self.generate_hex2hex(
328
+ self.attributes.rest.border_color, now["border_color"], animation_steps
329
+ )
330
+ if self.attributes.rest.border_color2 is None:
331
+ self.attributes.rest.border_color2 = self.attributes.rest.border_color
332
+ if now["border_color2"] is None:
333
+ now["border_color2"] = now["border_color"]
334
+ border_colors2 = self.generate_hex2hex(
335
+ self.attributes.rest.border_color2, now["border_color2"], animation_steps
336
+ )
337
+ text_colors = self.generate_hex2hex(
338
+ self.attributes.rest.text_color, now["text_color"], animation_steps
339
+ )
340
+ import numpy as np
341
+ back_opacitys = np.linspace(
342
+ float(self.attributes.rest.back_opacity), float(now["back_opacity"]), animation_steps).tolist()
343
+ border_color_opacitys = np.linspace(
344
+ float(self.attributes.rest.border_color_opacity), float(now["border_color_opacity"]), animation_steps).tolist()
345
+ if self.attributes.rest.border_color2_opacity is None:
346
+ self.attributes.rest.border_color2_opacity = self.attributes.rest.border_color_opacity
347
+ if now["border_color2_opacity"] is None:
348
+ now["border_color2_opacity"] = now["border_color_opacity"]
349
+ border_color2_opacitys = np.linspace(
350
+ float(self.attributes.rest.border_color2_opacity), float(now["border_color2_opacity"]), animation_steps).tolist()
351
+ for i in range(animation_steps):
352
+ def update(ii=i):
353
+ from easydict import EasyDict
354
+ tempcolor = EasyDict(
355
+ {
356
+ "back_color": back_colors[ii],
357
+ "back_opacity": back_opacitys[ii],
358
+ "border_color": border_colors[ii],
359
+ "border_color_opacity": str(border_color_opacitys[ii]),
360
+ "border_color2": border_colors2[ii],
361
+ "border_color2_opacity": str(border_color2_opacitys[ii]),
362
+ "border_width": 1,
363
+ "text_color": text_colors[ii],
364
+ "radius": 6,
365
+ }
366
+ )
367
+ self._draw(None, tempcolor)
368
+
369
+ self.after(i * animation_step_time, update)
370
+ #self.after(animation_steps * animation_step_time + 10, lambda: self._draw(None, None))
268
371
 
269
372
  self.dconfigure(
270
373
  rest={
@@ -334,7 +437,7 @@ class FluButton(FluButtonCanvas, DDrawWidget, FluToolTipBase, FluGradient):
334
437
  def invoke(self):
335
438
  self.attributes.command()
336
439
 
337
- def _event_off_button1(self, event=None):
440
+ def _event_off_button1(self, event: Event = None):
338
441
  self.button1 = False
339
442
 
340
443
  self._draw(event)
tkflu/bwm.py CHANGED
@@ -126,20 +126,26 @@ class BWm(FluGradient):
126
126
  else:
127
127
  self._light()
128
128
 
129
- def _theme(self, mode):
129
+ def _theme(self, mode, animation_steps: int = None, animation_step_time: int = None):
130
130
  from .designs.window import window
131
131
  n = window(mode)
132
132
  """if self.attributes.back_color is not None:
133
133
  n["back_color"] = self.attributes.back_color"""
134
-
135
- if self.dcget("back_color"):
136
- back_colors = self.generate_hex2hex(self.dcget("back_color"), n["back_color"], steps=10)
137
- for i in range(10):
138
- def update(ii=i): # 使用默认参数立即捕获i的值
139
- self.dconfigure(back_color=back_colors[ii])
140
- self._draw()
141
-
142
- self.after(i * 10, update) # 直接传递函数,不需要lambda
134
+ if animation_steps is None:
135
+ from .designs.animation import get_animation_steps
136
+ animation_steps = get_animation_steps()
137
+ if animation_step_time is None:
138
+ from .designs.animation import get_animation_step_time
139
+ animation_step_time = get_animation_step_time()
140
+ if not animation_steps == 0 or not animation_step_time == 0:
141
+ if self.dcget("back_color"):
142
+ back_colors = self.generate_hex2hex(self.dcget("back_color"), n["back_color"], steps=animation_steps)
143
+ for i in range(animation_steps):
144
+ def update(ii=i): # 使用默认参数立即捕获i的值
145
+ self.dconfigure(back_color=back_colors[ii])
146
+ self._draw()
147
+
148
+ self.after(i * animation_step_time, update) # 直接传递函数,不需要lambda
143
149
 
144
150
  self.dconfigure(
145
151
  back_color=n["back_color"],
@@ -181,6 +187,8 @@ class BWm(FluGradient):
181
187
  if platform == "win32":
182
188
  if way == 0:
183
189
  from .customwindow import CustomWindow
190
+ import warnings
191
+ warnings.warn("This is EXPERIMENTAL! Please consider way=1 in production.")
184
192
  self.customwindow = CustomWindow(self, wait=wait)
185
193
  self.customwindow.bind_drag(self.titlebar)
186
194
  self.customwindow.bind_drag(self.titlelabel)
@@ -0,0 +1,33 @@
1
+ from tkflu import *
2
+
3
+ set_animation_steps(10)
4
+ set_animation_step_time(10)
5
+
6
+ root = FluWindow()
7
+ root.title("tkfluent designer")
8
+ root.geometry("500x300")
9
+
10
+ theme_manager = FluThemeManager(root)
11
+
12
+ menubar = FluMenuBar(root)
13
+
14
+ menu1 = FluMenu()
15
+ menu1.geometry("90x90")
16
+ menu1.add_command(label="Light", command=lambda: theme_manager.mode("light"))
17
+ menu1.add_command(label="Dark", command=lambda: theme_manager.mode("dark"))
18
+
19
+ def func1():
20
+ messagebox = FluToplevel()
21
+ messagebox.geometry("300x200")
22
+
23
+ label = FluLabel(messagebox, text="This is a example for tkfluent!", width=160, height=32)
24
+ label.pack(anchor="center")
25
+
26
+ menubar.add_command(label="File", style="standard", width=40, command=lambda: print("File -> Clicked"))
27
+ menubar.add_cascade(label="Theme Mode", style="standard", width=100, menu=menu1)
28
+ menubar.add_command(label="About", style="standard", width=40, command=lambda: func1())
29
+
30
+ menubar.show()
31
+
32
+
33
+ root.mainloop()
tkflu/demos/grad2.py CHANGED
@@ -1,140 +1,17 @@
1
- import tkinter as tk
2
- from tkinter import ttk
3
- import numpy as np
1
+ from tkflu import *
4
2
 
3
+ set_animation_steps(20)
4
+ set_animation_step_time(20)
5
5
 
6
- class GradientLabelApp:
7
- def __init__(self, root):
8
- self.root = root
9
- self.root.title("Tkinter渐变标签演示")
10
- self.root.geometry("400x200")
6
+ root = FluWindow()
11
7
 
12
- # 渐变控制变量
13
- self.is_animating = False
14
- self.current_step = 0
15
- self.gradient_steps = 20 # 渐变步数
8
+ theme_manager = FluThemeManager(root)
16
9
 
17
- # 创建UI组件
18
- self.create_widgets()
10
+ frame = FluFrame(root, mode="light", style="standard")
19
11
 
20
- # 预生成渐变序列 (从蓝色到红色)
21
- self.gradient = self.generate_gradient_hex(
22
- "#ffffff",
23
- "#005fb8",
24
- self.gradient_steps
25
- )
12
+ btn = FluButton(frame, text="Button", mode="light", style="standard", command=lambda: theme_manager.toggle())
13
+ btn.pack(padx=20, pady=20, fill="both", expand="yes")
26
14
 
27
- def create_widgets(self):
28
- """创建界面组件"""
29
- # 渐变显示标签
30
- self.label = tk.Label(
31
- self.root,
32
- text="渐变背景标签",
33
- font=('Arial', 20),
34
- relief='raised',
35
- borderwidth=2
36
- )
37
- self.label.pack(pady=20, ipadx=50, ipady=30, fill='x', padx=20)
15
+ frame.pack(padx=20, pady=20, fill="both", expand="yes")
38
16
 
39
- # 控制按钮框架
40
- button_frame = ttk.Frame(self.root)
41
- button_frame.pack(pady=10)
42
-
43
- # 开始按钮
44
- self.start_button = ttk.Button(
45
- button_frame,
46
- text="开始渐变",
47
- command=self.toggle_animation
48
- )
49
- self.start_button.pack(side='left', padx=5)
50
-
51
- # 重置按钮
52
- ttk.Button(
53
- button_frame,
54
- text="重置",
55
- command=self.reset_animation
56
- ).pack(side='left', padx=5)
57
-
58
- def generate_gradient(self, start_color, end_color, steps):
59
- """生成颜色渐变序列"""
60
- gradient = []
61
- for t in np.linspace(0, 1, steps):
62
- r = int(start_color[0] + (end_color[0] - start_color[0]) * t)
63
- g = int(start_color[1] + (end_color[1] - start_color[1]) * t)
64
- b = int(start_color[2] + (end_color[2] - start_color[2]) * t)
65
- gradient.append(f"#{r:02x}{g:02x}{b:02x}")
66
- return gradient
67
-
68
- def generate_gradient_hex(self, start_hex, end_hex, steps):
69
- """
70
- 专为HEX颜色设计的渐变生成器
71
- :param start_hex: 起始颜色 HEX格式 (如 "#FF0000")
72
- :param end_hex: 结束颜色 HEX格式 (如 "#0000FF")
73
- :param steps: 渐变步数
74
- :return: HEX格式的颜色列表
75
- """
76
-
77
- # 去除#号并转换为RGB元组
78
- def hex_to_rgb(h):
79
- h = h.lstrip('#')
80
- return tuple(int(h[i:i + 2], 16) for i in (0, 2, 4))
81
-
82
- # RGB转HEX
83
- def rgb_to_hex(rgb):
84
- return f"#{rgb[0]:02x}{rgb[1]:02x}{rgb[2]:02x}"
85
-
86
- rgb_start = hex_to_rgb(start_hex)
87
- rgb_end = hex_to_rgb(end_hex)
88
-
89
- gradient = []
90
- for t in np.linspace(0, 1, steps):
91
- # 计算每个通道的中间值
92
- r = int(rgb_start[0] + (rgb_end[0] - rgb_start[0]) * t)
93
- g = int(rgb_start[1] + (rgb_end[1] - rgb_start[1]) * t)
94
- b = int(rgb_start[2] + (rgb_end[2] - rgb_start[2]) * t)
95
-
96
- # 确保值在0-255范围内并转换为HEX
97
- gradient.append(rgb_to_hex((
98
- max(0, min(255, r)),
99
- max(0, min(255, g)),
100
- max(0, min(255, b))
101
- )))
102
-
103
- return gradient
104
-
105
- def toggle_animation(self):
106
- """切换动画状态"""
107
- self.is_animating = not self.is_animating
108
- self.start_button.config(
109
- text="停止渐变" if self.is_animating else "开始渐变"
110
- )
111
- if self.is_animating:
112
- self.animate_gradient()
113
-
114
- def animate_gradient(self):
115
- """执行渐变动画"""
116
- if not self.is_animating:
117
- return
118
-
119
- # 更新标签背景色
120
- color = self.gradient[self.current_step]
121
- self.label.config(background=color)
122
-
123
- # 更新步进
124
- self.current_step = (self.current_step + 1) % len(self.gradient)
125
-
126
- # 50ms后继续下一帧 (约20FPS)
127
- self.root.after(50, self.animate_gradient)
128
-
129
- def reset_animation(self):
130
- """重置动画状态"""
131
- self.is_animating = False
132
- self.current_step = 0
133
- self.start_button.config(text="开始渐变")
134
- self.label.config(background='SystemButtonFace') # 恢复默认背景色
135
-
136
-
137
- if __name__ == "__main__":
138
- root = tk.Tk()
139
- app = GradientLabelApp(root)
140
- root.mainloop()
17
+ root.mainloop()
tkflu/demos/grad3.py CHANGED
@@ -1,11 +1,16 @@
1
1
  from tkflu import *
2
2
 
3
+ set_animation_steps(20)
4
+ set_animation_step_time(20)
3
5
 
4
6
  root = FluWindow()
5
7
 
6
8
  theme_manager = FluThemeManager(root)
7
9
 
8
- btn = FluButton(root, text="Button", mode="light", style="standard", command=lambda: theme_manager.toggle())
9
- btn.pack()
10
+ button = FluButton(root, text="Button", mode="light", style="standard", command=lambda: theme_manager.toggle())
11
+ button.pack(padx=20, pady=20, fill="both", expand="yes")
12
+
13
+ label = FluLabel(root, text="Label", mode="light")
14
+ label.pack(padx=20, pady=20, fill="both", expand="yes")
10
15
 
11
16
  root.mainloop()