tkfluent 0.0.2__py3-none-any.whl → 0.0.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
@@ -12,15 +12,23 @@ from .button import FluButton
12
12
  from .entry import FluEntry
13
13
  from .frame import FluFrame
14
14
  from .label import FluLabel
15
+ from .menu import FluMenu
16
+ from .menubar import FluMenuBar
17
+ from .popupmenu import FluPopupMenu
15
18
  from .text import FluText
16
19
  from .thememanager import FluThemeManager
17
20
  from .togglebutton import FluToggleButton
21
+ from .toplevel import FluToplevel
18
22
  from .window import FluWindow
23
+ #from .winico import FluWinico
24
+
19
25
 
20
26
  FluChip = FluBadge
21
27
  FluPushButton = FluButton
22
28
  FluTextInput = FluEntry
23
29
  FluTextBox = FluText
24
30
  FluPanel = FluFrame
31
+ FluMainWindow = FluWindow
32
+ FluSubWindow = FluToplevel
25
33
 
26
34
  # 
tkflu/__main__.py CHANGED
@@ -3,13 +3,40 @@ from tkinter import *
3
3
  from tkinter.font import *
4
4
 
5
5
  root = FluWindow()
6
- root.iconify
7
- root.wincustom(way=0)
8
- root.wm_geometry("180x360")
6
+ #root.wincustom(way=0)
7
+ root.wm_geometry("360x500")
8
+
9
+ popupmenu = FluPopupMenu()
9
10
 
10
11
  thememanager = FluThemeManager()
11
12
 
12
- frame = FluFrame()
13
+ menubar = FluMenuBar(root)
14
+ menubar.add_command(
15
+ label="FluMenu1", width=80, command=lambda: print("FluMenu1 -> Clicked")
16
+ )
17
+
18
+ menu1 = FluMenu()
19
+ menu1.add_command(
20
+ label="FluMenu2-1", width=80, command=lambda: print("FluMenu2-1 -> Clicked")
21
+ )
22
+ menubar.add_cascade(
23
+ label="FluMenu2", width=80, menu=menu1
24
+ )
25
+
26
+ menu2 = FluMenu(height=93)
27
+ menu2.add_command(
28
+ label="FluMenu3-1", width=80, command=lambda: print("FluMenu3-1 -> Clicked")
29
+ )
30
+ menu2.add_command(
31
+ label="FluMenu3-2", width=80, command=lambda: print("FluMenu3-2 -> Clicked")
32
+ )
33
+ menubar.add_cascade(
34
+ label="FluMenu3", width=80, menu=menu2
35
+ )
36
+
37
+ menubar.pack(fill="x",)
38
+
39
+ frame = FluFrame(root)
13
40
 
14
41
  badge1 = FluBadge(frame, text="FluBadge", width=60)
15
42
  badge1.pack(padx=5, pady=5)
tkflu/badge.py CHANGED
@@ -121,11 +121,12 @@ class FluBadge(FluBadgeCanvas, DDrawWidget):
121
121
  fill=_text_color, text=self.attributes.text, font=self.attributes.font
122
122
  )
123
123
 
124
- def theme(self, mode, style=None):
125
- self.mode = mode
124
+ def theme(self, mode=None, style=None):
125
+ if mode:
126
+ self.mode = mode
126
127
  if style:
127
128
  self.style = style
128
- if mode.lower() == "dark":
129
+ if self.mode.lower() == "dark":
129
130
  if self.style.lower() == "accent":
130
131
  self._dark_accent()
131
132
  else:
@@ -138,7 +139,7 @@ class FluBadge(FluBadgeCanvas, DDrawWidget):
138
139
 
139
140
  def _light(self):
140
141
  self.dconfigure(
141
- back_color="#f0f0f0",
142
+ back_color="#f9f9f9",
142
143
  border_color="#f0f0f0",
143
144
  border_width=1,
144
145
  text_color="#191919",
tkflu/button.py CHANGED
@@ -155,18 +155,23 @@ class FluButton(FluButtonCanvas, DDrawWidget):
155
155
  fill=_text_color, text=self.attributes.text, font=self.attributes.font
156
156
  )
157
157
 
158
- def theme(self, mode, style=None):
159
- self.mode = mode
158
+ def theme(self, mode=None, style=None):
159
+ if mode:
160
+ self.mode = mode
160
161
  if style:
161
162
  self.style = style
162
- if mode.lower() == "dark":
163
+ if self.mode.lower() == "dark":
163
164
  if self.style.lower() == "accent":
164
165
  self._dark_accent()
166
+ elif self.style.lower() == "menu":
167
+ self._dark_menu()
165
168
  else:
166
169
  self._dark()
167
170
  else:
168
171
  if self.style.lower() == "accent":
169
172
  self._light_accent()
173
+ elif self.style.lower() == "menu":
174
+ self._light_menu()
170
175
  else:
171
176
  self._light()
172
177
 
@@ -174,25 +179,53 @@ class FluButton(FluButtonCanvas, DDrawWidget):
174
179
  self.dconfigure(
175
180
  rest={
176
181
  "back_color": "#ffffff",
177
- "border_color": "#f0f0f0",
178
- "border_color2": "#d6d6d6",
182
+ "border_color": "#e5e5e5",
183
+ "border_color2": "#cccccc",
179
184
  "border_width": 1,
180
185
  "radius": 6,
181
186
  "text_color": "#1b1b1b",
182
187
  },
183
188
  hover={
184
189
  "back_color": "#fcfcfc",
185
- "border_color": "#f0f0f0",
186
- "border_color2": "#d6d6d6",
190
+ "border_color": "#e5e5e5",
191
+ "border_color2": "#cccccc",
187
192
  "border_width": 1,
188
193
  "radius": 6,
189
194
  "text_color": "#1b1b1b",
190
195
  },
191
196
  pressed={
192
197
  "back_color": "#fdfdfd",
198
+ "border_color": "#e5e5e5",
199
+ "border_color2": "#e5e5e5",
200
+ "border_width": 1,
201
+ "radius": 6,
202
+ "text_color": "#636363",
203
+ }
204
+ )
205
+
206
+ def _light_menu(self):
207
+ self.dconfigure(
208
+ rest={
209
+ "back_color": "#ffffff",
210
+ "border_color": "white",
211
+ "border_color2": "white",
212
+ "border_width": 0,
213
+ "radius": 6,
214
+ "text_color": "#1b1b1b",
215
+ },
216
+ hover={
217
+ "back_color": "#eaeaea",
218
+ "border_color": "#f0f0f0",
219
+ "border_color2": "#d6d6d6",
220
+ "border_width": 0,
221
+ "radius": 6,
222
+ "text_color": "#1b1b1b",
223
+ },
224
+ pressed={
225
+ "back_color": "#ededed",
193
226
  "border_color": "#f0f0f0",
194
227
  "border_color2": "#f0f0f0",
195
- "border_width": 1,
228
+ "border_width": 0,
196
229
  "radius": 6,
197
230
  "text_color": "#636363",
198
231
  }
@@ -254,6 +287,34 @@ class FluButton(FluButtonCanvas, DDrawWidget):
254
287
  }
255
288
  )
256
289
 
290
+ def _dark_menu(self):
291
+ self.dconfigure(
292
+ rest={
293
+ "back_color": "#202020",
294
+ "border_color": "black",
295
+ "border_color2": "black",
296
+ "border_width": 0,
297
+ "radius": 6,
298
+ "text_color": "#ffffff",
299
+ },
300
+ hover={
301
+ "back_color": "#2d2d2d",
302
+ "border_color": "#303030",
303
+ "border_color2": "#262626",
304
+ "border_width": 0,
305
+ "radius": 6,
306
+ "text_color": "#ffffff",
307
+ },
308
+ pressed={
309
+ "back_color": "#292929",
310
+ "border_color": "#2a2a2a",
311
+ "border_color2": "#262626",
312
+ "border_width": 0,
313
+ "radius": 6,
314
+ "text_color": "#cfcfcf",
315
+ }
316
+ )
317
+
257
318
  def _dark_accent(self):
258
319
  self.dconfigure(
259
320
  rest={
tkflu/bwm.py ADDED
@@ -0,0 +1,174 @@
1
+ class BWm(object):
2
+ def _draw(self, event=None):
3
+
4
+ """
5
+ 重新绘制窗口及自定义的窗口组件
6
+
7
+ :param event:
8
+ """
9
+
10
+ self.configure(background=self.attributes.back_color)
11
+ if self.custom:
12
+ if hasattr(self, "titlebar"):
13
+ self.titlebar.configure(background=self.attributes.back_color)
14
+ self.titlebar.update()
15
+ if hasattr(self, "titlelabel"):
16
+ self.titlelabel.dconfigure(text_color=self.attributes.text_color)
17
+ self.titlelabel._draw()
18
+ if hasattr(self, "closebutton"):
19
+ self.closebutton.dconfigure(
20
+ rest={
21
+ "back_color": self.titlebar.cget("background"),
22
+ "border_color": "#f0f0f0",
23
+ "border_color2": "#d6d6d6",
24
+ "border_width": 0,
25
+ "radius": 0,
26
+ "text_color": self.attributes.closebutton.text_color,
27
+ },
28
+ hover={
29
+ "back_color": self.attributes.closebutton.back_color,
30
+ "border_color": "#f0f0f0",
31
+ "border_color2": "#d6d6d6",
32
+ "border_width": 0,
33
+ "radius": 0,
34
+ "text_color": self.attributes.closebutton.text_hover_color,
35
+ },
36
+ pressed={
37
+ "back_color": self.attributes.closebutton.back_color,
38
+ "border_color": "#f0f0f0",
39
+ "border_color2": "#f0f0f0",
40
+ "border_width": 0,
41
+ "radius": 0,
42
+ "text_color": self.attributes.closebutton.text_hover_color,
43
+ }
44
+ )
45
+ self.closebutton._draw()
46
+
47
+ def _event_configure(self, event=None):
48
+
49
+ """
50
+ 触发 `<Configure>` 事件
51
+
52
+ :param event:
53
+ :return:
54
+ """
55
+
56
+ self._draw()
57
+
58
+ def _init(self, mode):
59
+ from easydict import EasyDict
60
+ self.attributes = EasyDict(
61
+ {
62
+ "back_color": None,
63
+ "text_color": None,
64
+ "closebutton": {
65
+ "back_color": None,
66
+ "text_color": None,
67
+ "text_hover_color": None
68
+ }
69
+ }
70
+ )
71
+
72
+ self.theme(mode)
73
+
74
+ def _exit(self):
75
+ self.quit()
76
+
77
+ def theme(self, mode: str):
78
+
79
+ """
80
+ 同 `theme_myself`
81
+
82
+ :param mode:
83
+ :return:
84
+ """
85
+
86
+ self.theme_myself(mode=mode)
87
+
88
+ def theme_myself(self, mode: str):
89
+
90
+ """
91
+ 修改该窗口的Fluent主题
92
+
93
+ :param mode:
94
+ :return:
95
+ """
96
+
97
+ self.mode = mode
98
+ if mode.lower() == "dark":
99
+ self._dark()
100
+ else:
101
+ self._light()
102
+
103
+ def _light(self):
104
+ self.dconfigure(
105
+ back_color="#ffffff",
106
+ text_color="#000000",
107
+ closebutton={
108
+ "back_color": "red",
109
+ "text_color": "#000000",
110
+ "text_hover_color": "#ffffff"
111
+ }
112
+ )
113
+
114
+ def _dark(self):
115
+ self.dconfigure(
116
+ back_color="#202020",
117
+ text_color="#ffffff",
118
+ closebutton={
119
+ "back_color": "red",
120
+ "text_color": "#ffffff",
121
+ "text_hover_color": "#000000"
122
+ }
123
+ )
124
+
125
+ def wincustom(self, wait=200, way=1):
126
+
127
+ """
128
+ 自定义窗口 仅限`Windows系统`
129
+
130
+ :param wait: 直接执行自定义窗口容易出错误 需要一点时间等待才能执行 同`after()`中的`ms`
131
+ :param way: 取0时保留原版边框,但稳定性很差,容易崩溃。取1时不保留原版边框,但稳定性较好。
132
+ :return:
133
+ """
134
+
135
+ from sys import platform
136
+ from .button import FluButton
137
+ from .label import FluLabel
138
+ from tkinter import Frame
139
+ self.titlebar = Frame(self, width=180, height=35, background=self.attributes.back_color)
140
+ self.titlelabel = FluLabel(self.titlebar, text=self.title(), width=50)
141
+ self.titlelabel.pack(fill="y", side="left")
142
+ self.closebutton = FluButton(self.titlebar, text="", width=32, height=32, command=lambda: self._exit())
143
+ self.closebutton.pack(fill="y", side="right")
144
+ self.titlebar.pack(fill="x", side="top")
145
+
146
+ if platform == "win32":
147
+ if way == 0:
148
+ from .customwindow import CustomWindow
149
+ self.customwindow = CustomWindow(self, wait=wait)
150
+ self.customwindow.bind_drag(self.titlebar)
151
+ self.customwindow.bind_drag(self.titlelabel)
152
+ else:
153
+ self.overrideredirect(True)
154
+ try:
155
+ from win32gui import GetParent, GetWindowLong, SetWindowLong
156
+ from win32con import GWL_EXSTYLE, WS_EX_APPWINDOW, WS_EX_TOOLWINDOW
157
+ hwnd = GetParent(self.winfo_id())
158
+ style = GetWindowLong(hwnd, GWL_EXSTYLE)
159
+ style = style & ~WS_EX_TOOLWINDOW
160
+ style = style | WS_EX_APPWINDOW
161
+ SetWindowLong(hwnd, GWL_EXSTYLE, style)
162
+ self.after(30, lambda: self.withdraw())
163
+ self.after(60, lambda: self.deiconify())
164
+ except:
165
+ pass
166
+
167
+ self.wm_attributes("-topmost", True)
168
+
169
+ from .customwindow2 import WindowDragArea
170
+ self.dragarea = WindowDragArea(self)
171
+ self.dragarea.bind(self.titlebar)
172
+ self.dragarea.bind(self.titlelabel)
173
+
174
+ self.custom = True
tkflu/entry.py CHANGED
@@ -71,6 +71,8 @@ class FluEntry(FluEntryCanvas, DDrawWidget):
71
71
 
72
72
  super().__init__(*args, width=width, height=height, cursor=cursor, **kwargs)
73
73
 
74
+ self.bind("<FocusIn>", self._event_focus_in, add="+")
75
+
74
76
  if font is None:
75
77
  from tkdeft.utility.fonts import SegoeFont
76
78
  self.attributes.font = SegoeFont()
@@ -148,7 +150,7 @@ class FluEntry(FluEntryCanvas, DDrawWidget):
148
150
  self.dconfigure(
149
151
  rest={
150
152
  "back_color": "#ffffff",
151
- "border_color": "#f0f0f0",
153
+ "border_color": "#e5e5e5",
152
154
  "border_color2": "#8d8d8d",
153
155
  "border_width": 1,
154
156
  "radius": 6,
@@ -156,7 +158,7 @@ class FluEntry(FluEntryCanvas, DDrawWidget):
156
158
  },
157
159
  focus={
158
160
  "back_color": "#ffffff",
159
- "border_color": "#f0f0f0",
161
+ "border_color": "#e5e5e5",
160
162
  "border_color2": "#005fb8",
161
163
  "border_width": 2,
162
164
  "radius": 6,
tkflu/frame.py CHANGED
@@ -74,6 +74,7 @@ class FluFrame(Frame, DObject):
74
74
  width=300,
75
75
  height=150,
76
76
  mode="light",
77
+ style="standard",
77
78
  **kwargs,
78
79
  ):
79
80
  from tempfile import mkstemp
@@ -84,7 +85,7 @@ class FluFrame(Frame, DObject):
84
85
 
85
86
  super().__init__(master=self.canvas)
86
87
 
87
- self._init(mode)
88
+ self._init(mode, style)
88
89
 
89
90
  self.enter = False
90
91
  self.button1 = False
@@ -93,7 +94,7 @@ class FluFrame(Frame, DObject):
93
94
 
94
95
  self.canvas.bind("<Configure>", self._event_configure, add="+")
95
96
 
96
- def _init(self, mode):
97
+ def _init(self, mode, style):
97
98
  from easydict import EasyDict
98
99
 
99
100
  self.attributes = EasyDict(
@@ -106,33 +107,60 @@ class FluFrame(Frame, DObject):
106
107
  }
107
108
  )
108
109
 
109
- self.theme(mode)
110
-
111
- def theme(self, mode="light"):
112
- self.mode = mode
113
- if mode.lower() == "dark":
114
- self._dark()
110
+ self.theme(mode=mode, style=style)
111
+
112
+ def theme(self, mode=None, style=None):
113
+ if mode:
114
+ self.mode = mode
115
+ if style:
116
+ self.style = style
117
+ if self.mode.lower() == "dark":
118
+ if self.style.lower() == "popupmenu":
119
+ self._dark_popupmenu()
120
+ else:
121
+ self._dark()
115
122
  else:
116
- self._light()
123
+ if self.style.lower() == "popupmenu":
124
+ self._light_popupmenu()
125
+ else:
126
+ self._light()
117
127
 
118
128
  def _light(self):
119
129
  self.dconfigure(
120
- back_color="#ffffff",
130
+ back_color="#f9f9f9",
121
131
  border_color="#ebebeb",
122
132
  border_color2="#e4e4e4",
123
- border_width=1,
133
+ border_width=1.5,
124
134
  radius=6,
125
135
  )
126
136
 
137
+ def _light_popupmenu(self):
138
+ self.dconfigure(
139
+ back_color="#f9f9f9",
140
+ border_color="#4d5056",
141
+ border_color2="#4d5056",
142
+ border_width=1.5,
143
+ radius=8,
144
+ )
145
+
127
146
  def _dark(self):
128
147
  self.dconfigure(
129
148
  back_color="#242424",
130
149
  border_color="#303030",
131
150
  border_color2="#282828",
132
- border_width=1,
151
+ border_width=1.5,
133
152
  radius=6,
134
153
  )
135
154
 
155
+ def _dark_popupmenu(self):
156
+ self.dconfigure(
157
+ back_color="#242424",
158
+ border_color="#4d5056",
159
+ border_color2="#4d5056",
160
+ border_width=1.5,
161
+ radius=8,
162
+ )
163
+
136
164
  def pack_info(self):
137
165
  return self.canvas.pack_info()
138
166
 
tkflu/menu.py ADDED
@@ -0,0 +1,65 @@
1
+ from .popupmenu import FluPopupMenu
2
+ from tkdeft.object import DObject
3
+
4
+
5
+ class FluMenu(FluPopupMenu):
6
+ def __init__(self, *args, **kwargs):
7
+ super().__init__(*args, **kwargs)
8
+
9
+ def _init(self, mode, style):
10
+ from easydict import EasyDict
11
+
12
+ self.attributes = EasyDict(
13
+ {
14
+ "back_color": None,
15
+ "border_color": None,
16
+ "border_color2": None,
17
+ "border_width": None,
18
+ "radius": None,
19
+
20
+ "actions": {}
21
+ }
22
+ )
23
+
24
+ self.theme(mode=mode, style=style)
25
+
26
+ def add_command(self, custom_widget=None, width=40, **kwargs):
27
+ if custom_widget:
28
+ widget = custom_widget(self)
29
+ else:
30
+ from .button import FluButton
31
+ widget = FluButton(self, width=width)
32
+ if "label" in kwargs:
33
+ label = kwargs.pop("label")
34
+ else:
35
+ label = ""
36
+ if "style" in kwargs:
37
+ style = kwargs.pop("style")
38
+ else:
39
+ style = "menu"
40
+ if "command" in kwargs:
41
+ c = kwargs.pop("command")
42
+
43
+ def command():
44
+ c()
45
+ self.window.wm_withdraw()
46
+
47
+ else:
48
+ def empty():
49
+ pass
50
+
51
+ command = empty
52
+ if "id" in kwargs:
53
+ id = kwargs.pop("id")
54
+ else:
55
+ id = widget._w
56
+ if hasattr(widget, "dconfigure"):
57
+ widget.dconfigure(text=label, command=command)
58
+ else:
59
+ if hasattr(widget, "configure"):
60
+ widget.configure(text=label, command=command)
61
+ if hasattr(widget, "theme"):
62
+ widget.theme(style=style)
63
+
64
+ widget.pack(side="top", fill="x", padx=1, pady=(1, 0))
65
+ self.dcget("actions")[id] = widget
tkflu/menubar.py ADDED
@@ -0,0 +1,140 @@
1
+ from tkinter import Frame, Menu
2
+ from tkdeft.object import DObject
3
+
4
+
5
+ class FluMenuBar(Frame, DObject):
6
+ def __init__(self, *args, mode="light", height=40, **kwargs):
7
+ self._init(mode)
8
+
9
+ super().__init__(*args, height=height, **kwargs)
10
+
11
+ self._draw(None)
12
+
13
+ self.bind("<Configure>", self._event_configure, add="+")
14
+
15
+ def _init(self, mode):
16
+
17
+ from easydict import EasyDict
18
+
19
+ self.attributes = EasyDict(
20
+ {
21
+ "back_color": "#f3f3f3",
22
+
23
+ "actions": {}
24
+ }
25
+ )
26
+
27
+ self.theme(mode=mode)
28
+
29
+ def add_command(self, custom_widget=None, width=40, **kwargs):
30
+ if custom_widget:
31
+ widget = custom_widget(self)
32
+ else:
33
+ from .button import FluButton
34
+ widget = FluButton(self, width=width)
35
+ if "label" in kwargs:
36
+ label = kwargs.pop("label")
37
+ else:
38
+ label = ""
39
+ if "style" in kwargs:
40
+ style = kwargs.pop("style")
41
+ else:
42
+ style = "menu"
43
+ if "command" in kwargs:
44
+ command = kwargs.pop("command")
45
+ else:
46
+ def empty():
47
+ pass
48
+
49
+ command = empty
50
+ if "id" in kwargs:
51
+ id = kwargs.pop("id")
52
+ else:
53
+ id = widget._w
54
+ if hasattr(widget, "dconfigure"):
55
+ widget.dconfigure(text=label, command=command)
56
+ else:
57
+ if hasattr(widget, "configure"):
58
+ widget.configure(text=label, command=command)
59
+ if hasattr(widget, "theme"):
60
+ widget.theme(style=style)
61
+
62
+ widget.pack(side="left", padx=5, pady=5)
63
+ self.dcget("actions")[id] = widget
64
+
65
+ from .menu import FluMenu
66
+
67
+ def add_cascade(self, custom_widget=None, width=40, menu: FluMenu = None, **kwargs):
68
+ if custom_widget:
69
+ widget = custom_widget(self)
70
+ else:
71
+ from .button import FluButton
72
+ widget = FluButton(self, width=width)
73
+ if "label" in kwargs:
74
+ label = kwargs.pop("label")
75
+ else:
76
+ label = ""
77
+ if "style" in kwargs:
78
+ style = kwargs.pop("style")
79
+ else:
80
+ style = "menu"
81
+ if "id" in kwargs:
82
+ id = kwargs.pop("id")
83
+ else:
84
+ id = widget._w
85
+
86
+ def command():
87
+ menu.focus_set()
88
+ menu.popup(widget.winfo_rootx(), widget.winfo_rooty() + widget.winfo_height())
89
+ menu.window.deiconify()
90
+ menu.window.attributes("-topmost")
91
+
92
+ if hasattr(widget, "dconfigure"):
93
+ widget.dconfigure(text=label, command=command)
94
+ else:
95
+ if hasattr(widget, "configure"):
96
+ widget.configure(text=label, command=command)
97
+ if hasattr(widget, "theme"):
98
+ widget.theme(style=style)
99
+
100
+ widget.pack(side="left", padx=5, pady=5)
101
+ self.dcget("actions")[id] = widget
102
+
103
+ def action(self, id):
104
+ return self.dcget("actions")[id]
105
+
106
+ def theme(self, mode="light"):
107
+ self.theme_myself(mode=mode)
108
+
109
+ actions = self.dcget("actions")
110
+
111
+ for key in actions:
112
+ widget = actions[key]
113
+ if hasattr(widget, "theme"):
114
+ widget.theme(mode=mode)
115
+ if hasattr(widget, "_draw"):
116
+ widget._draw()
117
+ widget.update()
118
+
119
+ def theme_myself(self, mode="light"):
120
+ self.mode = mode
121
+ if mode.lower() == "dark":
122
+ self._dark()
123
+ else:
124
+ self._light()
125
+
126
+ def _light(self):
127
+ self.dconfigure(
128
+ back_color="#f3f3f3"
129
+ )
130
+
131
+ def _dark(self):
132
+ self.dconfigure(
133
+ back_color="#202020"
134
+ )
135
+
136
+ def _draw(self, event=None):
137
+ self.config(background=self.attributes.back_color)
138
+
139
+ def _event_configure(self, event=None):
140
+ self._draw(event)
tkflu/popupmenu.py ADDED
@@ -0,0 +1,81 @@
1
+ from tkinter import Toplevel
2
+ from .frame import FluFrame
3
+
4
+
5
+ class FluPopupMenuWindow(Toplevel):
6
+ def __init__(self, *args, transparent_color="#ffefa2", mode="light", width=100, height=46, **kwargs):
7
+ super().__init__(*args, background=transparent_color, **kwargs)
8
+
9
+ self.theme(mode=mode)
10
+
11
+ self.geometry(f"{width}x{height}")
12
+
13
+ self.transient_color = transparent_color
14
+ self.overrideredirect(True)
15
+ self.attributes("-transparentcolor", transparent_color)
16
+
17
+ self.withdraw()
18
+
19
+ self.bind("<FocusOut>", self._event_focusout)
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
+
27
+ def theme(self, mode=None):
28
+ if mode:
29
+ self.mode = mode
30
+ for widget in self.winfo_children():
31
+ if hasattr(widget, "theme"):
32
+ widget.theme(mode=self.mode.lower())
33
+
34
+
35
+ class FluPopupMenu(FluFrame):
36
+ def __init__(self, *args, width=100, height=46, transparent_color="#ffefa2", style="popupmenu", **kwargs):
37
+ self.window = FluPopupMenuWindow(transparent_color=transparent_color, width=width, height=height)
38
+
39
+ super().__init__(self.window, *args, style=style, **kwargs)
40
+
41
+ self.pack(fill="both", expand="yes", padx=5, pady=5)
42
+
43
+ def wm_attributes(self, *args, **kwargs):
44
+ self.window.wm_attributes(*args, **kwargs)
45
+
46
+ attributes = wm_attributes
47
+
48
+ def wm_protocol(self, *args, **kwargs):
49
+ self.window.wm_protocol(*args, **kwargs)
50
+
51
+ protocol = wm_protocol
52
+
53
+ def wm_deiconify(self, *args, **kwargs):
54
+ self.window.wm_deiconify(*args, **kwargs)
55
+
56
+ deiconify = wm_deiconify
57
+
58
+ def wm_withdraw(self, *args, **kwargs):
59
+ self.window.wm_withdraw(*args, **kwargs)
60
+
61
+ withdraw = wm_withdraw
62
+
63
+ def wm_iconify(self, *args, **kwargs):
64
+ self.window.wm_iconify(*args, **kwargs)
65
+
66
+ iconify = wm_iconify
67
+
68
+ def wm_resizable(self, *args, **kwargs):
69
+ self.window.wm_resizable(*args, **kwargs)
70
+
71
+ resizable = wm_resizable
72
+
73
+ def wm_geometry(self, *args, **kwargs):
74
+ self.window.wm_geometry(*args, **kwargs)
75
+
76
+ geometry = wm_geometry
77
+
78
+ def wm_popup(self, x, y):
79
+ self.window.popup(x=x, y=y)
80
+
81
+ popup = wm_popup
tkflu/text.py CHANGED
@@ -70,6 +70,8 @@ class FluText(FluTextCanvas, DDrawWidget):
70
70
 
71
71
  super().__init__(*args, width=width, height=height, cursor=cursor, **kwargs)
72
72
 
73
+ self.bind("<FocusIn>", self._event_focus_in, add="+")
74
+
73
75
  if font is None:
74
76
  from tkdeft.utility.fonts import SegoeFont
75
77
  self.attributes.font = SegoeFont()
@@ -151,7 +153,7 @@ class FluText(FluTextCanvas, DDrawWidget):
151
153
  self.dconfigure(
152
154
  rest={
153
155
  "back_color": "#ffffff",
154
- "border_color": "#f0f0f0",
156
+ "border_color": "#e5e5e5",
155
157
  "border_color2": "#8d8d8d",
156
158
  "border_width": 1,
157
159
  "radius": 6,
@@ -159,7 +161,7 @@ class FluText(FluTextCanvas, DDrawWidget):
159
161
  },
160
162
  focus={
161
163
  "back_color": "#ffffff",
162
- "border_color": "#f0f0f0",
164
+ "border_color": "#e5e5e5",
163
165
  "border_color2": "#005fb8",
164
166
  "border_width": 2,
165
167
  "radius": 6,
tkflu/thememanager.py CHANGED
@@ -1,8 +1,9 @@
1
1
  from .window import FluWindow
2
+ from .toplevel import FluToplevel
2
3
 
3
4
 
4
5
  class FluThemeManager(object):
5
- def __init__(self, window: FluWindow = None, mode: str = "light"):
6
+ def __init__(self, window=None, mode: str = "light"):
6
7
  if window:
7
8
  self._window = window
8
9
  else:
tkflu/toplevel.py ADDED
@@ -0,0 +1,30 @@
1
+ from tkinter import Toplevel
2
+ from tkdeft.object import DObject
3
+ from .bwm import BWm
4
+
5
+
6
+ class FluToplevel(Toplevel, BWm, DObject):
7
+
8
+ """Fluent设计的子窗口"""
9
+
10
+ def __init__(self, *args, mode="light", **kwargs):
11
+
12
+ """
13
+ 初始化类
14
+
15
+ :param args: 参照tkinter.TK.__init__
16
+ :param className: 参照tkinter.TK.__init__
17
+ :param mode: Fluent主题模式 分为 “light” “dark”
18
+ :param kwargs: 参照tkinter.TK.__init__
19
+ """
20
+
21
+ self._init(mode)
22
+
23
+ self.custom = False
24
+
25
+ Toplevel.__init__(self, *args, **kwargs)
26
+
27
+ self.bind("<Configure>", self._event_configure)
28
+
29
+ def _exit(self):
30
+ self.destroy()
tkflu/window.py CHANGED
@@ -1,8 +1,9 @@
1
- from tkinter import Tk
1
+ from tkinter import Tk, Toplevel
2
2
  from tkdeft.object import DObject
3
+ from .bwm import BWm
3
4
 
4
5
 
5
- class FluWindow(Tk, DObject):
6
+ class FluWindow(Tk, BWm, DObject):
6
7
 
7
8
  """Fluent设计的主窗口"""
8
9
 
@@ -25,173 +26,6 @@ class FluWindow(Tk, DObject):
25
26
 
26
27
  self.bind("<Configure>", self._event_configure)
27
28
 
28
- def _draw(self, event=None):
29
29
 
30
- """
31
- 重新绘制窗口及自定义的窗口组件
32
-
33
- :param event:
34
- """
35
-
36
- self.configure(background=self.attributes.back_color)
37
- if self.custom:
38
- if hasattr(self, "titlebar"):
39
- self.titlebar.configure(background=self.attributes.back_color)
40
- self.titlebar.update()
41
- if hasattr(self, "titlelabel"):
42
- self.titlelabel.dconfigure(text_color=self.attributes.text_color)
43
- self.titlelabel._draw()
44
- if hasattr(self, "closebutton"):
45
- self.closebutton.dconfigure(
46
- rest={
47
- "back_color": self.titlebar.cget("background"),
48
- "border_color": "#f0f0f0",
49
- "border_color2": "#d6d6d6",
50
- "border_width": 0,
51
- "radius": 0,
52
- "text_color": self.attributes.closebutton.text_color,
53
- },
54
- hover={
55
- "back_color": self.attributes.closebutton.back_color,
56
- "border_color": "#f0f0f0",
57
- "border_color2": "#d6d6d6",
58
- "border_width": 0,
59
- "radius": 0,
60
- "text_color": self.attributes.closebutton.text_hover_color,
61
- },
62
- pressed={
63
- "back_color": self.attributes.closebutton.back_color,
64
- "border_color": "#f0f0f0",
65
- "border_color2": "#f0f0f0",
66
- "border_width": 0,
67
- "radius": 0,
68
- "text_color": self.attributes.closebutton.text_hover_color,
69
- }
70
- )
71
- self.closebutton._draw()
72
-
73
- def _event_configure(self, event=None):
74
-
75
- """
76
- 触发 `<Configure>` 事件
77
-
78
- :param event:
79
- :return:
80
- """
81
-
82
- self._draw()
83
-
84
- def _init(self, mode):
85
- from easydict import EasyDict
86
- self.attributes = EasyDict(
87
- {
88
- "back_color": None,
89
- "text_color": None,
90
- "closebutton": {
91
- "back_color": None,
92
- "text_color": None,
93
- "text_hover_color": None
94
- }
95
- }
96
- )
97
-
98
- self.theme(mode)
99
-
100
- def theme(self, mode: str):
101
-
102
- """
103
- 同 `theme_myself`
104
-
105
- :param mode:
106
- :return:
107
- """
108
-
109
- self.theme_myself(mode=mode)
110
-
111
- def theme_myself(self, mode: str):
112
-
113
- """
114
- 修改该窗口的Fluent主题
115
-
116
- :param mode:
117
- :return:
118
- """
119
-
120
- self.mode = mode
121
- if mode.lower() == "dark":
122
- self._dark()
123
- else:
124
- self._light()
125
-
126
- def _light(self):
127
- self.dconfigure(
128
- back_color="#ffffff",
129
- text_color="#000000",
130
- closebutton={
131
- "back_color": "red",
132
- "text_color": "#000000",
133
- "text_hover_color": "#ffffff"
134
- }
135
- )
136
-
137
- def _dark(self):
138
- self.dconfigure(
139
- back_color="#202020",
140
- text_color="#ffffff",
141
- closebutton={
142
- "back_color": "red",
143
- "text_color": "#ffffff",
144
- "text_hover_color": "#000000"
145
- }
146
- )
147
-
148
- def wincustom(self, wait=200, way=1):
149
-
150
- """
151
- 自定义窗口 仅限`Windows系统`
152
-
153
- :param wait: 直接执行自定义窗口容易出错误 需要一点时间等待才能执行 同`after()`中的`ms`
154
- :param way: 取0时保留原版边框,但稳定性很差,容易崩溃。取1时不保留原版边框,但稳定性较好。
155
- :return:
156
- """
157
-
158
- from sys import platform
159
- from .button import FluButton
160
- from .label import FluLabel
161
- from tkinter import Frame
162
- self.titlebar = Frame(self, width=180, height=35, background=self.attributes.back_color)
163
- self.titlelabel = FluLabel(self.titlebar, text=self.title(), width=50)
164
- self.titlelabel.pack(fill="y", side="left")
165
- self.closebutton = FluButton(self.titlebar, text="", width=32, height=32, command=lambda: self.quit())
166
- self.closebutton.pack(fill="y", side="right")
167
- self.titlebar.pack(fill="x", side="top")
168
-
169
- if platform == "win32":
170
- if way == 0:
171
- from .customwindow import CustomWindow
172
- self.customwindow = CustomWindow(self, wait=wait)
173
- self.customwindow.bind_drag(self.titlebar)
174
- self.customwindow.bind_drag(self.titlelabel)
175
- else:
176
- self.overrideredirect(True)
177
- try:
178
- from win32gui import GetParent, GetWindowLong, SetWindowLong
179
- from win32con import GWL_EXSTYLE, WS_EX_APPWINDOW, WS_EX_TOOLWINDOW
180
- hwnd = GetParent(self.winfo_id())
181
- style = GetWindowLong(hwnd, GWL_EXSTYLE)
182
- style = style & ~WS_EX_TOOLWINDOW
183
- style = style | WS_EX_APPWINDOW
184
- SetWindowLong(hwnd, GWL_EXSTYLE, style)
185
- self.after(30, lambda: self.withdraw())
186
- self.after(60, lambda: self.deiconify())
187
- except:
188
- pass
189
-
190
- self.wm_attributes("-topmost", True)
191
30
 
192
- from .customwindow2 import WindowDragArea
193
- self.dragarea = WindowDragArea(self)
194
- self.dragarea.bind(self.titlebar)
195
- self.dragarea.bind(self.titlelabel)
196
31
 
197
- self.custom = True
tkflu/winico.py ADDED
@@ -0,0 +1,25 @@
1
+ from tkdeft.object import DObject
2
+
3
+ try:
4
+ from tkwinico import *
5
+ except:
6
+ class FluWinico(DObject):
7
+ pass
8
+ else:
9
+ class FluWinico(Winico, DObject):
10
+ def __init__(self, *args, icon_name=None, icon_file=None, **kwargs):
11
+ super().__init__(*args, **kwargs)
12
+
13
+ self.tray_add(self.icon(icon_name=icon_name, icon_file=icon_file), callback=self.callback, callback_args=[MESSAGE, X, Y])
14
+
15
+ from .popupmenu import FluPopupMenu
16
+
17
+ self.menu = FluPopupMenu()
18
+ self.menu.window.geometry("100x40")
19
+
20
+ def callback(self, message, x, y):
21
+ if message == "WM_RBUTTONDOWNessage":
22
+ self.menu.window.attributes("-topmost", True)
23
+ self.menu.window.deiconify()
24
+ self.menu.popup(x, y)
25
+ self.menu.focus_set()
@@ -1,22 +1,23 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: tkfluent
3
- Version: 0.0.2
3
+ Version: 0.0.3
4
4
  Summary: Fluent Design for Tkinter
5
5
  Author: XiangQinxi
6
6
  Author-email: xiangqinxi@outlook.com
7
- Classifier: Programming Language :: Python :: 2
8
- Classifier: Programming Language :: Python :: 2.7
7
+ Requires-Python: >=3.7,<4.0
9
8
  Classifier: Programming Language :: Python :: 3
10
- Classifier: Programming Language :: Python :: 3.4
11
- Classifier: Programming Language :: Python :: 3.5
12
- Classifier: Programming Language :: Python :: 3.6
13
9
  Classifier: Programming Language :: Python :: 3.7
14
10
  Classifier: Programming Language :: Python :: 3.8
15
11
  Classifier: Programming Language :: Python :: 3.9
16
12
  Classifier: Programming Language :: Python :: 3.10
17
13
  Classifier: Programming Language :: Python :: 3.11
18
14
  Classifier: Programming Language :: Python :: 3.12
15
+ Requires-Dist: easydict (>=1.13,<2.0)
16
+ Requires-Dist: pillow (>=10.2.0,<11.0.0)
17
+ Requires-Dist: svgwrite (>=1.4.3,<2.0.0)
19
18
  Requires-Dist: tkdeft (>=0.0.7,<0.0.8)
19
+ Requires-Dist: tkextrafont (>=0.6.3,<0.7.0)
20
+ Requires-Dist: tksvg (>=0.7.4,<0.8.0)
20
21
  Project-URL: Documentation, https://tkfluent.netlify.app
21
22
  Description-Content-Type: text/markdown
22
23
 
@@ -0,0 +1,27 @@
1
+ tkflu/__init__.py,sha256=HXTCYFRrttdDS-SfE-vKHNbb6_sw4WqAUkaiv-F7IkA,751
2
+ tkflu/__main__.py,sha256=sWIY4ltJN76w7LmlGZQmE3N0X0VyYS3_zSL-76VwEeY,2002
3
+ tkflu/badge.py,sha256=SReWYzwuJpKU-OvnpMUrsYoYAJ2pA0bahChxS06lhYk,4914
4
+ tkflu/button.py,sha256=WZgwCxKIg0O_zwgsYY37FNyeZdcjIs7xewEiAUqdaK8,11967
5
+ tkflu/bwm.py,sha256=KdDbHar0wReUwJDmLqKYQkfQ_xcBLNVDkTZayTk30FY,5979
6
+ tkflu/checkbox.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
+ tkflu/customwindow.py,sha256=Fr4CF0vKwj36tYzgX9_5F7OwcD59z9LfOW20Ugm2Hxc,3761
8
+ tkflu/customwindow2.py,sha256=nyNEMoGVnOYXCPbdvxZFUH-VlpAtjjEGI8Ul9VDvgAs,2109
9
+ tkflu/entry.py,sha256=5afwWpMgGo_Lm7-ZDuipplxsI5Z1YNsLumtwmaxJIAE,6481
10
+ tkflu/frame.py,sha256=jQprJ5pXfQ17iywzbAatS12U2g43yg1Mg7O-3dnXPOQ,7934
11
+ tkflu/image.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
+ tkflu/label.py,sha256=m9HEXlM0ribh8y4B6vfp3HEVH8ElyuVPyG-2BwzdGVo,1598
13
+ tkflu/listbox.py,sha256=gD_oNNWVZtm5qXQ8bVBNRqJL6CGiIYtvhxztM9huzew,9991
14
+ tkflu/litenav.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
+ tkflu/menu.py,sha256=XUhbEmo0xgiVAv0o8HDRF4jfZ0PxGKbeyzWp3xkQwKk,1868
16
+ tkflu/menubar.py,sha256=2XdMfWy6djGU3RL1ykbaUR6bj0rwaqdUJmufOzsdOPE,4027
17
+ tkflu/popupmenu.py,sha256=rf_YWX5UzwlAhoRDRZE_tVbx_yfVxkecsdWTWvg80QA,2349
18
+ tkflu/scrollbar.py,sha256=1hbu5n1mx4KyiF_M3sohpJJPux1zu5Jlw9V6LfQQs1Y,7293
19
+ tkflu/text.py,sha256=5JwWXQ4OutnqxUWoZ-m1agULDSEg6HDoNdaU0wQMKd8,6590
20
+ tkflu/thememanager.py,sha256=oG-VWkFogVJJOmsz67hyVfvNdkWMUeP252Qcez8FQmk,963
21
+ tkflu/togglebutton.py,sha256=hcAYh8XYaireQuGLHKWxJDLm2wMYHt3GlJnE8TjjbIY,13436
22
+ tkflu/toplevel.py,sha256=e5ZhQ7W2OheWJTkqev9sp9onmSASGIp_hdBaO8EYDc0,723
23
+ tkflu/window.py,sha256=X3hhhtzwwFpKfuVsdkcUk4qX_5Y0iGEUO_N7mKU9sGw,713
24
+ tkflu/winico.py,sha256=5wB9VL6SyMLD9fH9eglWPuJjQAyd851PoNUO4j5A9gw,859
25
+ tkfluent-0.0.3.dist-info/METADATA,sha256=Kcv5NWDbTxkT7dV8NIJiuv3JEPZvQvH4wc17RwLt7KQ,872
26
+ tkfluent-0.0.3.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
27
+ tkfluent-0.0.3.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
2
  Generator: poetry-core 1.9.0
3
3
  Root-Is-Purelib: true
4
- Tag: py2.py3-none-any
4
+ Tag: py3-none-any
@@ -1,21 +0,0 @@
1
- tkflu/__init__.py,sha256=ZkeXXJhoEwjNUes12oBZHovvKFCuZiaoZj-NCeFvVYg,530
2
- tkflu/__main__.py,sha256=7qALQjQaw9-cEB_9UhWUuQYZSfh9eONftFx16PlosCE,1317
3
- tkflu/badge.py,sha256=3Yw5EwlA2UvRLVMK8jdsAv_R6RtrSbC5dQTk9gr2sv4,4882
4
- tkflu/button.py,sha256=2_XxwkauewTL_Z6YIafJRXAQg8jyrPGhLdRJMaZ1QFY,9987
5
- tkflu/checkbox.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
- tkflu/customwindow.py,sha256=Fr4CF0vKwj36tYzgX9_5F7OwcD59z9LfOW20Ugm2Hxc,3761
7
- tkflu/customwindow2.py,sha256=nyNEMoGVnOYXCPbdvxZFUH-VlpAtjjEGI8Ul9VDvgAs,2109
8
- tkflu/entry.py,sha256=5tQqhGzqwSiRIJQdZz52afDtVAWKKfWNeLgGDzeRXNk,6416
9
- tkflu/frame.py,sha256=noQhnU-4d6UnvjVMeLYTuS5F-pFBx9-iSJCFXH02B2c,7075
10
- tkflu/image.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
- tkflu/label.py,sha256=m9HEXlM0ribh8y4B6vfp3HEVH8ElyuVPyG-2BwzdGVo,1598
12
- tkflu/listbox.py,sha256=gD_oNNWVZtm5qXQ8bVBNRqJL6CGiIYtvhxztM9huzew,9991
13
- tkflu/litenav.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
- tkflu/scrollbar.py,sha256=1hbu5n1mx4KyiF_M3sohpJJPux1zu5Jlw9V6LfQQs1Y,7293
15
- tkflu/text.py,sha256=uwpW2omhd6kKQyEVMH-GSSozeMxP3zBUY_RPW5fvuao,6525
16
- tkflu/thememanager.py,sha256=10Pp4nRyEjdbX4wmh4HayIZomc_iz_vxxSrhIh2SR6s,941
17
- tkflu/togglebutton.py,sha256=hcAYh8XYaireQuGLHKWxJDLm2wMYHt3GlJnE8TjjbIY,13436
18
- tkflu/window.py,sha256=pc5M9jIgUj98cFJNR7Q4i3Sll3HxIsDKA8dHL2DxWXg,6581
19
- tkfluent-0.0.2.dist-info/METADATA,sha256=5UKzRl5OML8VJkXCB1TNd_TB1h5ofkavnxHsDQEhCVM,890
20
- tkfluent-0.0.2.dist-info/WHEEL,sha256=IrRNNNJ-uuL1ggO5qMvT1GGhQVdQU54d6ZpYqEZfEWo,92
21
- tkfluent-0.0.2.dist-info/RECORD,,