CTkScrollableDropdownPP 2.0.3__tar.gz → 2.1__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.
- {ctkscrollabledropdownpp-2.0.3 → ctkscrollabledropdownpp-2.1}/CTkScrollableDropdownPP/ctk_scrollable_dropdown.py +69 -37
- ctkscrollabledropdownpp-2.1/CTkScrollableDropdownPP.egg-info/PKG-INFO +120 -0
- ctkscrollabledropdownpp-2.1/PKG-INFO +120 -0
- ctkscrollabledropdownpp-2.1/README.md +103 -0
- {ctkscrollabledropdownpp-2.0.3 → ctkscrollabledropdownpp-2.1}/pyproject.toml +1 -1
- ctkscrollabledropdownpp-2.0.3/CTkScrollableDropdownPP.egg-info/PKG-INFO +0 -69
- ctkscrollabledropdownpp-2.0.3/PKG-INFO +0 -69
- ctkscrollabledropdownpp-2.0.3/README.md +0 -52
- {ctkscrollabledropdownpp-2.0.3 → ctkscrollabledropdownpp-2.1}/CTkScrollableDropdownPP/__init__.py +0 -0
- {ctkscrollabledropdownpp-2.0.3 → ctkscrollabledropdownpp-2.1}/CTkScrollableDropdownPP.egg-info/SOURCES.txt +0 -0
- {ctkscrollabledropdownpp-2.0.3 → ctkscrollabledropdownpp-2.1}/CTkScrollableDropdownPP.egg-info/dependency_links.txt +0 -0
- {ctkscrollabledropdownpp-2.0.3 → ctkscrollabledropdownpp-2.1}/CTkScrollableDropdownPP.egg-info/requires.txt +0 -0
- {ctkscrollabledropdownpp-2.0.3 → ctkscrollabledropdownpp-2.1}/CTkScrollableDropdownPP.egg-info/top_level.txt +0 -0
- {ctkscrollabledropdownpp-2.0.3 → ctkscrollabledropdownpp-2.1}/LICENSE +0 -0
- {ctkscrollabledropdownpp-2.0.3 → ctkscrollabledropdownpp-2.1}/setup.cfg +0 -0
|
@@ -10,7 +10,7 @@ class CTkScrollableDropdown(customtkinter.CTkToplevel):
|
|
|
10
10
|
command=None, image_values=[], alpha: float = 0.95, frame_corner_radius=20, double_click=False,
|
|
11
11
|
frame_border_color=None, text_color=None, autocomplete=False,
|
|
12
12
|
hover_color=None, pagination: bool = True, items_per_page: int = 50,
|
|
13
|
-
groups=None, **button_kwargs):
|
|
13
|
+
groups=None, font=("Segoe UI", 12), **button_kwargs):
|
|
14
14
|
super().__init__(master=attach.winfo_toplevel(), takefocus=1)
|
|
15
15
|
|
|
16
16
|
self.group_patterns = None
|
|
@@ -37,18 +37,20 @@ class CTkScrollableDropdown(customtkinter.CTkToplevel):
|
|
|
37
37
|
self.current_page = 0
|
|
38
38
|
self.filtered_values = None
|
|
39
39
|
self.current_group = 0
|
|
40
|
+
self.font = font
|
|
40
41
|
self.groups = []
|
|
42
|
+
|
|
41
43
|
if groups is not None:
|
|
42
44
|
for g in groups:
|
|
43
45
|
if isinstance(g, (list, tuple)) and len(g) >= 2:
|
|
44
46
|
self.groups.append({"name": g[0], "pattern": g[1]})
|
|
45
47
|
else:
|
|
46
48
|
raise ValueError(f"groups must be a list of [name, pattern], got {g!r}")
|
|
47
|
-
|
|
49
|
+
|
|
48
50
|
self.group_names = [g["name"] for g in self.groups]
|
|
49
51
|
self.group_patterns = []
|
|
50
52
|
included_values = set()
|
|
51
|
-
|
|
53
|
+
|
|
52
54
|
for g in self.groups:
|
|
53
55
|
pattern = g["pattern"]
|
|
54
56
|
if pattern == "__OTHERS__":
|
|
@@ -58,14 +60,14 @@ class CTkScrollableDropdown(customtkinter.CTkToplevel):
|
|
|
58
60
|
self.group_patterns.append(compiled)
|
|
59
61
|
matched = [v for v in self.all_values if compiled.search(v)]
|
|
60
62
|
included_values.update(matched)
|
|
61
|
-
|
|
63
|
+
|
|
62
64
|
self.grouped_values = {}
|
|
63
65
|
for i, pat in enumerate(self.group_patterns):
|
|
64
66
|
if pat == "__OTHERS__":
|
|
65
67
|
self.grouped_values[i] = [v for v in self.all_values if v not in included_values]
|
|
66
68
|
else:
|
|
67
69
|
self.grouped_values[i] = [v for v in self.all_values if pat.search(v)]
|
|
68
|
-
|
|
70
|
+
|
|
69
71
|
if sys.platform.startswith("win"):
|
|
70
72
|
self.after(100, lambda: self.overrideredirect(True))
|
|
71
73
|
self.transparent_color = self._apply_appearance_mode(self._fg_color) if hasattr(self, '_fg_color') else "#FFFFFF"
|
|
@@ -101,15 +103,16 @@ class CTkScrollableDropdown(customtkinter.CTkToplevel):
|
|
|
101
103
|
self.search_var = customtkinter.StringVar()
|
|
102
104
|
self.search_var.trace_add('write', lambda *args: self.live_update(self.search_var.get()))
|
|
103
105
|
self.search_entry = customtkinter.CTkEntry(self, textvariable=self.search_var)
|
|
104
|
-
self.search_entry.pack(fill="x")
|
|
106
|
+
self.search_entry.pack(fill="x", pady=(0, 5))
|
|
105
107
|
if self.groups:
|
|
106
|
-
self.group_frame = customtkinter.CTkFrame(self, fg_color=self.fg_color)
|
|
107
|
-
self.group_frame.pack(fill="x", padx=5)
|
|
108
|
+
self.group_frame = customtkinter.CTkFrame(self, fg_color=self.fg_color, bg_color=self.transparent_color)
|
|
109
|
+
self.group_frame.pack(fill="x", padx=5, pady=(0, 5))
|
|
108
110
|
self.group_buttons = []
|
|
109
111
|
for idx, name in enumerate(self.group_names):
|
|
110
112
|
btn = customtkinter.CTkButton(
|
|
111
113
|
self.group_frame,
|
|
112
114
|
text=name,
|
|
115
|
+
font=self.font,
|
|
113
116
|
height=button_height,
|
|
114
117
|
fg_color=self.button_color,
|
|
115
118
|
text_color=self.text_color,
|
|
@@ -130,7 +133,7 @@ class CTkScrollableDropdown(customtkinter.CTkToplevel):
|
|
|
130
133
|
border_color=self.frame_border_color
|
|
131
134
|
)
|
|
132
135
|
self.frame._scrollbar.grid_configure(padx=3)
|
|
133
|
-
self.frame.pack(expand=True, fill="both")
|
|
136
|
+
self.frame.pack(expand=True, fill="both", pady=(3, 0))
|
|
134
137
|
if self.pagination:
|
|
135
138
|
self.button_container = customtkinter.CTkFrame(self.frame, fg_color=self.fg_color)
|
|
136
139
|
self.button_container.pack(expand=True, fill="both")
|
|
@@ -157,7 +160,11 @@ class CTkScrollableDropdown(customtkinter.CTkToplevel):
|
|
|
157
160
|
else:
|
|
158
161
|
self.justify = "c"
|
|
159
162
|
self.button_height = button_height
|
|
160
|
-
self.image_values =
|
|
163
|
+
self.image_values = image_values
|
|
164
|
+
self.value_to_image = {}
|
|
165
|
+
if image_values and len(image_values) == len(values):
|
|
166
|
+
for val, img in zip(values, image_values):
|
|
167
|
+
self.value_to_image[val] = img
|
|
161
168
|
self.resizable(width=False, height=False)
|
|
162
169
|
self.transient(self.master)
|
|
163
170
|
if double_click or isinstance(self.attach, customtkinter.CTkEntry) or isinstance(self.attach, customtkinter.CTkComboBox):
|
|
@@ -187,19 +194,36 @@ class CTkScrollableDropdown(customtkinter.CTkToplevel):
|
|
|
187
194
|
self._init_buttons()
|
|
188
195
|
|
|
189
196
|
def _on_group_frame_configure(self, event):
|
|
197
|
+
if not self.group_buttons:
|
|
198
|
+
return
|
|
199
|
+
|
|
190
200
|
min_btn_width = 100
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
201
|
+
n = len(self.group_buttons)
|
|
202
|
+
cols = max(1, min(n, event.width // min_btn_width))
|
|
203
|
+
rows = (n + cols - 1) // cols
|
|
204
|
+
|
|
205
|
+
frame_height = rows * self.button_height
|
|
206
|
+
if self.group_frame.winfo_height() != frame_height:
|
|
207
|
+
self.group_frame.configure(height=frame_height)
|
|
208
|
+
|
|
196
209
|
for idx, btn in enumerate(self.group_buttons):
|
|
197
210
|
row = idx // cols
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
211
|
+
col_in_row = idx % cols
|
|
212
|
+
row_start = row * cols
|
|
213
|
+
num_in_row = min(cols, n - row_start)
|
|
214
|
+
|
|
215
|
+
rel_width = 1.0 / num_in_row
|
|
216
|
+
rel_x = col_in_row * rel_width
|
|
217
|
+
rel_y = row / rows
|
|
218
|
+
rel_height = 1.0 / rows
|
|
219
|
+
|
|
220
|
+
btn.place(
|
|
221
|
+
in_=self.group_frame,
|
|
222
|
+
relx=rel_x,
|
|
223
|
+
rely=rel_y,
|
|
224
|
+
relwidth=rel_width,
|
|
225
|
+
relheight=rel_height
|
|
226
|
+
)
|
|
203
227
|
|
|
204
228
|
def switch_group(self, idx):
|
|
205
229
|
if idx == self.current_group:
|
|
@@ -216,25 +240,26 @@ class CTkScrollableDropdown(customtkinter.CTkToplevel):
|
|
|
216
240
|
self.filtered_values = None
|
|
217
241
|
self.current_page = 0
|
|
218
242
|
self._init_buttons()
|
|
219
|
-
|
|
243
|
+
|
|
220
244
|
def update_buttons(self, values_list):
|
|
221
245
|
for i, value in enumerate(values_list):
|
|
222
246
|
if i in self.widgets:
|
|
223
247
|
btn, _ = self.widgets[i]
|
|
224
|
-
btn.configure(text=value, command=lambda v=value: self._attach_key_press(v))
|
|
248
|
+
btn.configure(text=value, command=lambda v=value: self._attach_key_press(v), image=self.value_to_image.get(value))
|
|
225
249
|
btn.pack(fill="x", pady=2, padx=(self.padding, 0))
|
|
226
250
|
self.widgets[i][1] = True
|
|
227
251
|
else:
|
|
228
252
|
btn = customtkinter.CTkButton(
|
|
229
253
|
self.button_container,
|
|
230
254
|
text=value,
|
|
231
|
-
font=
|
|
255
|
+
font=self.font,
|
|
232
256
|
command=lambda v=value: self._attach_key_press(v),
|
|
233
257
|
height=self.button_height,
|
|
234
258
|
fg_color=self.button_color,
|
|
235
259
|
text_color=self.text_color,
|
|
236
260
|
anchor=self.justify,
|
|
237
|
-
hover_color=self.hover_color
|
|
261
|
+
hover_color=self.hover_color,
|
|
262
|
+
image=self.value_to_image.get(value)
|
|
238
263
|
)
|
|
239
264
|
btn.pack(fill="x", pady=2, padx=(self.padding, 0))
|
|
240
265
|
self.widgets[i] = [btn, True]
|
|
@@ -330,7 +355,7 @@ class CTkScrollableDropdown(customtkinter.CTkToplevel):
|
|
|
330
355
|
self._update_pagination_buttons(filtered=bool(self.filtered_values))
|
|
331
356
|
self.frame.update_idletasks()
|
|
332
357
|
self.frame._parent_canvas.yview_moveto(len(values_to_show) / self.items_per_page)
|
|
333
|
-
|
|
358
|
+
|
|
334
359
|
def destroy_popup(self):
|
|
335
360
|
self.destroy()
|
|
336
361
|
self.disable = True
|
|
@@ -429,7 +454,7 @@ class CTkScrollableDropdown(customtkinter.CTkToplevel):
|
|
|
429
454
|
index = len(self.values)
|
|
430
455
|
if index in self.widgets:
|
|
431
456
|
btn, _ = self.widgets[index]
|
|
432
|
-
btn.configure(text=value, command=lambda v=value: self._attach_key_press(v))
|
|
457
|
+
btn.configure(text=value, command=lambda v=value: self._attach_key_press(v), image=self.value_to_image.get(value))
|
|
433
458
|
btn.pack(fill="x", pady=2, padx=(self.padding, 0))
|
|
434
459
|
self.widgets[index][1] = True
|
|
435
460
|
else:
|
|
@@ -441,8 +466,9 @@ class CTkScrollableDropdown(customtkinter.CTkToplevel):
|
|
|
441
466
|
hover_color=self.hover_color,
|
|
442
467
|
anchor=self.justify,
|
|
443
468
|
command=lambda v=value: self._attach_key_press(v),
|
|
444
|
-
|
|
445
|
-
|
|
469
|
+
image=self.value_to_image.get(value),
|
|
470
|
+
width=0,
|
|
471
|
+
*kwargs)
|
|
446
472
|
btn.pack(fill="x", pady=2, padx=(self.padding, 0))
|
|
447
473
|
self.widgets[index] = [btn, True]
|
|
448
474
|
self.values.append(value)
|
|
@@ -511,11 +537,11 @@ class CTkScrollableDropdown(customtkinter.CTkToplevel):
|
|
|
511
537
|
self.groups.append({"name": g[0], "pattern": g[1]})
|
|
512
538
|
else:
|
|
513
539
|
raise ValueError(f"groups must be list of [name, pattern], got {g!r}")
|
|
514
|
-
|
|
540
|
+
|
|
515
541
|
self.group_names = [g["name"] for g in self.groups]
|
|
516
542
|
self.group_patterns = []
|
|
517
543
|
included_values = set()
|
|
518
|
-
|
|
544
|
+
|
|
519
545
|
for g in self.groups:
|
|
520
546
|
pattern = g["pattern"]
|
|
521
547
|
if pattern == "__OTHERS__":
|
|
@@ -525,22 +551,28 @@ class CTkScrollableDropdown(customtkinter.CTkToplevel):
|
|
|
525
551
|
self.group_patterns.append(compiled)
|
|
526
552
|
matched = [v for v in self.all_values if compiled.search(v)]
|
|
527
553
|
included_values.update(matched)
|
|
528
|
-
|
|
554
|
+
|
|
529
555
|
self.grouped_values = {}
|
|
530
556
|
for i, pat in enumerate(self.group_patterns):
|
|
531
557
|
if pat == "__OTHERS__":
|
|
532
558
|
self.grouped_values[i] = [v for v in self.all_values if v not in included_values]
|
|
533
559
|
else:
|
|
534
560
|
self.grouped_values[i] = [v for v in self.all_values if pat.search(v)]
|
|
535
|
-
|
|
561
|
+
|
|
536
562
|
self.current_group = 0
|
|
537
563
|
self.switch_group(self.current_group)
|
|
538
564
|
if "image_values" in kwargs:
|
|
539
|
-
|
|
540
|
-
self.image_values =
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
565
|
+
image_values_arg = kwargs.pop("image_values")
|
|
566
|
+
self.image_values = image_values_arg
|
|
567
|
+
self.value_to_image = {}
|
|
568
|
+
|
|
569
|
+
if image_values_arg and len(image_values_arg) == len(self.values):
|
|
570
|
+
for val, img in zip(self.values, image_values_arg):
|
|
571
|
+
self.value_to_image[val] = img
|
|
572
|
+
|
|
573
|
+
for key, (btn, visible) in self.widgets.items():
|
|
574
|
+
current_value = btn.cget("text")
|
|
575
|
+
btn.configure(image=self.value_to_image.get(current_value))
|
|
544
576
|
if "button_color" in kwargs:
|
|
545
577
|
bc = kwargs.pop("button_color")
|
|
546
578
|
for key in self.widgets:
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: CTkScrollableDropdownPP
|
|
3
|
+
Version: 2.1
|
|
4
|
+
Summary: Enhanced CTkScrollableDropdown with pagination, search and groups support
|
|
5
|
+
Author: PLauncher-Team, Akash Bora
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/PLauncher-Team/CTkScrollableDropdownPP
|
|
8
|
+
Project-URL: Original, https://github.com/Akascape/CTkScrollableDropdown
|
|
9
|
+
Keywords: customtkinter,dropdown,pagination,search,groups
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Requires-Python: >=3.8
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
License-File: LICENSE
|
|
15
|
+
Requires-Dist: customtkinter>=5.2.0
|
|
16
|
+
Dynamic: license-file
|
|
17
|
+
|
|
18
|
+
# CTkScrollableDropdownPP
|
|
19
|
+
|
|
20
|
+
[](https://pepy.tech/projects/ctkscrollabledropdownpp)
|
|
21
|
+
|
|
22
|
+
**CTkScrollableDropdownPP** is an enhanced dropdown widget for CustomTkinter featuring pagination, live search, and grouping support.
|
|
23
|
+
|
|
24
|
+
> Based on the original [CTkScrollableDropdown](https://github.com/Akascape/CTkScrollableDropdown) project.
|
|
25
|
+
|
|
26
|
+
## Features
|
|
27
|
+
|
|
28
|
+
* Pagination for large lists
|
|
29
|
+
* Real-time filtering
|
|
30
|
+
* Grouped items (using regex or labels)
|
|
31
|
+
* Autocomplete on typing
|
|
32
|
+
* Fully customizable appearance
|
|
33
|
+
|
|
34
|
+
## Installation
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
pip install ctkscrollabledropdownpp
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Example
|
|
41
|
+
|
|
42
|
+
```python
|
|
43
|
+
import customtkinter
|
|
44
|
+
from PIL import Image, ImageDraw
|
|
45
|
+
from CTkScrollableDropdownPP import CTkScrollableDropdown
|
|
46
|
+
import io
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def create_color_image(color, width=20, height=20):
|
|
50
|
+
"""Create an image of the specified color"""
|
|
51
|
+
img = Image.new('RGBA', (width, height), (0, 0, 0, 0))
|
|
52
|
+
draw = ImageDraw.Draw(img)
|
|
53
|
+
draw.rectangle((0, 0, width - 1, height - 1), fill=color)
|
|
54
|
+
img_bytes = io.BytesIO()
|
|
55
|
+
img.save(img_bytes, format='PNG')
|
|
56
|
+
img_bytes.seek(0)
|
|
57
|
+
return customtkinter.CTkImage(Image.open(img_bytes), size=(width, height))
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def create_number_image(number, width=20, height=20):
|
|
61
|
+
"""Create an image with a digit"""
|
|
62
|
+
img = Image.new('RGBA', (width, height), (0, 0, 0, 0))
|
|
63
|
+
draw = ImageDraw.Draw(img)
|
|
64
|
+
draw.rectangle((0, 0, width - 1, height - 1), fill="#FFFFFF")
|
|
65
|
+
draw.text((width // 2, height // 2), str(number), fill="#000000", anchor="mm")
|
|
66
|
+
img_bytes = io.BytesIO()
|
|
67
|
+
img.save(img_bytes, format='PNG')
|
|
68
|
+
img_bytes.seek(0)
|
|
69
|
+
return customtkinter.CTkImage(Image.open(img_bytes), size=(width, height))
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
# Create main window
|
|
73
|
+
root = customtkinter.CTk()
|
|
74
|
+
root.geometry("500x400")
|
|
75
|
+
|
|
76
|
+
# Create CTkComboBox
|
|
77
|
+
combobox = customtkinter.CTkComboBox(root, width=250)
|
|
78
|
+
combobox.pack(pady=50)
|
|
79
|
+
|
|
80
|
+
# Data for dropdown list
|
|
81
|
+
colors = {
|
|
82
|
+
"Red": "#FF0000",
|
|
83
|
+
"Green": "#00FF00",
|
|
84
|
+
"Blue": "#0000FF",
|
|
85
|
+
"Yellow": "#FFFF00",
|
|
86
|
+
"Orange": "#FFA500",
|
|
87
|
+
"Purple": "#800080",
|
|
88
|
+
"Pink": "#FFC0CB",
|
|
89
|
+
"Brown": "#A52A2A",
|
|
90
|
+
"Black": "#000000",
|
|
91
|
+
"White": "#FFFFFF"
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
numbers = [str(i) for i in range(10)] # Digits from 0 to 9
|
|
95
|
+
|
|
96
|
+
# Create lists of values and images
|
|
97
|
+
color_values = list(colors.keys())
|
|
98
|
+
color_images = [create_color_image(color_code) for color_code in colors.values()]
|
|
99
|
+
|
|
100
|
+
number_values = numbers
|
|
101
|
+
number_images = [create_number_image(num) for num in numbers]
|
|
102
|
+
|
|
103
|
+
# Combine all values and images
|
|
104
|
+
all_values = color_values + number_values
|
|
105
|
+
all_images = color_images + number_images
|
|
106
|
+
|
|
107
|
+
# Groups for sorting
|
|
108
|
+
groups = [
|
|
109
|
+
["Numbers", "^[0-9]$"],
|
|
110
|
+
["Colors", "__OTHERS__"]
|
|
111
|
+
]
|
|
112
|
+
|
|
113
|
+
# Create dropdown list
|
|
114
|
+
dropdown = CTkScrollableDropdown(attach=combobox, button_color="#2b2b2b", height=200, width=300, fg_color="#333333",
|
|
115
|
+
values=all_values, command=lambda value: print(f"Selected: {value}"),
|
|
116
|
+
image_values=all_images, text_color="#ffffff", hover_color="#3a3a3a",
|
|
117
|
+
font=("Arial", 12), groups=groups, items_per_page=10)
|
|
118
|
+
|
|
119
|
+
root.mainloop()
|
|
120
|
+
```
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: CTkScrollableDropdownPP
|
|
3
|
+
Version: 2.1
|
|
4
|
+
Summary: Enhanced CTkScrollableDropdown with pagination, search and groups support
|
|
5
|
+
Author: PLauncher-Team, Akash Bora
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/PLauncher-Team/CTkScrollableDropdownPP
|
|
8
|
+
Project-URL: Original, https://github.com/Akascape/CTkScrollableDropdown
|
|
9
|
+
Keywords: customtkinter,dropdown,pagination,search,groups
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Requires-Python: >=3.8
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
License-File: LICENSE
|
|
15
|
+
Requires-Dist: customtkinter>=5.2.0
|
|
16
|
+
Dynamic: license-file
|
|
17
|
+
|
|
18
|
+
# CTkScrollableDropdownPP
|
|
19
|
+
|
|
20
|
+
[](https://pepy.tech/projects/ctkscrollabledropdownpp)
|
|
21
|
+
|
|
22
|
+
**CTkScrollableDropdownPP** is an enhanced dropdown widget for CustomTkinter featuring pagination, live search, and grouping support.
|
|
23
|
+
|
|
24
|
+
> Based on the original [CTkScrollableDropdown](https://github.com/Akascape/CTkScrollableDropdown) project.
|
|
25
|
+
|
|
26
|
+
## Features
|
|
27
|
+
|
|
28
|
+
* Pagination for large lists
|
|
29
|
+
* Real-time filtering
|
|
30
|
+
* Grouped items (using regex or labels)
|
|
31
|
+
* Autocomplete on typing
|
|
32
|
+
* Fully customizable appearance
|
|
33
|
+
|
|
34
|
+
## Installation
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
pip install ctkscrollabledropdownpp
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Example
|
|
41
|
+
|
|
42
|
+
```python
|
|
43
|
+
import customtkinter
|
|
44
|
+
from PIL import Image, ImageDraw
|
|
45
|
+
from CTkScrollableDropdownPP import CTkScrollableDropdown
|
|
46
|
+
import io
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def create_color_image(color, width=20, height=20):
|
|
50
|
+
"""Create an image of the specified color"""
|
|
51
|
+
img = Image.new('RGBA', (width, height), (0, 0, 0, 0))
|
|
52
|
+
draw = ImageDraw.Draw(img)
|
|
53
|
+
draw.rectangle((0, 0, width - 1, height - 1), fill=color)
|
|
54
|
+
img_bytes = io.BytesIO()
|
|
55
|
+
img.save(img_bytes, format='PNG')
|
|
56
|
+
img_bytes.seek(0)
|
|
57
|
+
return customtkinter.CTkImage(Image.open(img_bytes), size=(width, height))
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def create_number_image(number, width=20, height=20):
|
|
61
|
+
"""Create an image with a digit"""
|
|
62
|
+
img = Image.new('RGBA', (width, height), (0, 0, 0, 0))
|
|
63
|
+
draw = ImageDraw.Draw(img)
|
|
64
|
+
draw.rectangle((0, 0, width - 1, height - 1), fill="#FFFFFF")
|
|
65
|
+
draw.text((width // 2, height // 2), str(number), fill="#000000", anchor="mm")
|
|
66
|
+
img_bytes = io.BytesIO()
|
|
67
|
+
img.save(img_bytes, format='PNG')
|
|
68
|
+
img_bytes.seek(0)
|
|
69
|
+
return customtkinter.CTkImage(Image.open(img_bytes), size=(width, height))
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
# Create main window
|
|
73
|
+
root = customtkinter.CTk()
|
|
74
|
+
root.geometry("500x400")
|
|
75
|
+
|
|
76
|
+
# Create CTkComboBox
|
|
77
|
+
combobox = customtkinter.CTkComboBox(root, width=250)
|
|
78
|
+
combobox.pack(pady=50)
|
|
79
|
+
|
|
80
|
+
# Data for dropdown list
|
|
81
|
+
colors = {
|
|
82
|
+
"Red": "#FF0000",
|
|
83
|
+
"Green": "#00FF00",
|
|
84
|
+
"Blue": "#0000FF",
|
|
85
|
+
"Yellow": "#FFFF00",
|
|
86
|
+
"Orange": "#FFA500",
|
|
87
|
+
"Purple": "#800080",
|
|
88
|
+
"Pink": "#FFC0CB",
|
|
89
|
+
"Brown": "#A52A2A",
|
|
90
|
+
"Black": "#000000",
|
|
91
|
+
"White": "#FFFFFF"
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
numbers = [str(i) for i in range(10)] # Digits from 0 to 9
|
|
95
|
+
|
|
96
|
+
# Create lists of values and images
|
|
97
|
+
color_values = list(colors.keys())
|
|
98
|
+
color_images = [create_color_image(color_code) for color_code in colors.values()]
|
|
99
|
+
|
|
100
|
+
number_values = numbers
|
|
101
|
+
number_images = [create_number_image(num) for num in numbers]
|
|
102
|
+
|
|
103
|
+
# Combine all values and images
|
|
104
|
+
all_values = color_values + number_values
|
|
105
|
+
all_images = color_images + number_images
|
|
106
|
+
|
|
107
|
+
# Groups for sorting
|
|
108
|
+
groups = [
|
|
109
|
+
["Numbers", "^[0-9]$"],
|
|
110
|
+
["Colors", "__OTHERS__"]
|
|
111
|
+
]
|
|
112
|
+
|
|
113
|
+
# Create dropdown list
|
|
114
|
+
dropdown = CTkScrollableDropdown(attach=combobox, button_color="#2b2b2b", height=200, width=300, fg_color="#333333",
|
|
115
|
+
values=all_values, command=lambda value: print(f"Selected: {value}"),
|
|
116
|
+
image_values=all_images, text_color="#ffffff", hover_color="#3a3a3a",
|
|
117
|
+
font=("Arial", 12), groups=groups, items_per_page=10)
|
|
118
|
+
|
|
119
|
+
root.mainloop()
|
|
120
|
+
```
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# CTkScrollableDropdownPP
|
|
2
|
+
|
|
3
|
+
[](https://pepy.tech/projects/ctkscrollabledropdownpp)
|
|
4
|
+
|
|
5
|
+
**CTkScrollableDropdownPP** is an enhanced dropdown widget for CustomTkinter featuring pagination, live search, and grouping support.
|
|
6
|
+
|
|
7
|
+
> Based on the original [CTkScrollableDropdown](https://github.com/Akascape/CTkScrollableDropdown) project.
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
* Pagination for large lists
|
|
12
|
+
* Real-time filtering
|
|
13
|
+
* Grouped items (using regex or labels)
|
|
14
|
+
* Autocomplete on typing
|
|
15
|
+
* Fully customizable appearance
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
pip install ctkscrollabledropdownpp
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Example
|
|
24
|
+
|
|
25
|
+
```python
|
|
26
|
+
import customtkinter
|
|
27
|
+
from PIL import Image, ImageDraw
|
|
28
|
+
from CTkScrollableDropdownPP import CTkScrollableDropdown
|
|
29
|
+
import io
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def create_color_image(color, width=20, height=20):
|
|
33
|
+
"""Create an image of the specified color"""
|
|
34
|
+
img = Image.new('RGBA', (width, height), (0, 0, 0, 0))
|
|
35
|
+
draw = ImageDraw.Draw(img)
|
|
36
|
+
draw.rectangle((0, 0, width - 1, height - 1), fill=color)
|
|
37
|
+
img_bytes = io.BytesIO()
|
|
38
|
+
img.save(img_bytes, format='PNG')
|
|
39
|
+
img_bytes.seek(0)
|
|
40
|
+
return customtkinter.CTkImage(Image.open(img_bytes), size=(width, height))
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def create_number_image(number, width=20, height=20):
|
|
44
|
+
"""Create an image with a digit"""
|
|
45
|
+
img = Image.new('RGBA', (width, height), (0, 0, 0, 0))
|
|
46
|
+
draw = ImageDraw.Draw(img)
|
|
47
|
+
draw.rectangle((0, 0, width - 1, height - 1), fill="#FFFFFF")
|
|
48
|
+
draw.text((width // 2, height // 2), str(number), fill="#000000", anchor="mm")
|
|
49
|
+
img_bytes = io.BytesIO()
|
|
50
|
+
img.save(img_bytes, format='PNG')
|
|
51
|
+
img_bytes.seek(0)
|
|
52
|
+
return customtkinter.CTkImage(Image.open(img_bytes), size=(width, height))
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
# Create main window
|
|
56
|
+
root = customtkinter.CTk()
|
|
57
|
+
root.geometry("500x400")
|
|
58
|
+
|
|
59
|
+
# Create CTkComboBox
|
|
60
|
+
combobox = customtkinter.CTkComboBox(root, width=250)
|
|
61
|
+
combobox.pack(pady=50)
|
|
62
|
+
|
|
63
|
+
# Data for dropdown list
|
|
64
|
+
colors = {
|
|
65
|
+
"Red": "#FF0000",
|
|
66
|
+
"Green": "#00FF00",
|
|
67
|
+
"Blue": "#0000FF",
|
|
68
|
+
"Yellow": "#FFFF00",
|
|
69
|
+
"Orange": "#FFA500",
|
|
70
|
+
"Purple": "#800080",
|
|
71
|
+
"Pink": "#FFC0CB",
|
|
72
|
+
"Brown": "#A52A2A",
|
|
73
|
+
"Black": "#000000",
|
|
74
|
+
"White": "#FFFFFF"
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
numbers = [str(i) for i in range(10)] # Digits from 0 to 9
|
|
78
|
+
|
|
79
|
+
# Create lists of values and images
|
|
80
|
+
color_values = list(colors.keys())
|
|
81
|
+
color_images = [create_color_image(color_code) for color_code in colors.values()]
|
|
82
|
+
|
|
83
|
+
number_values = numbers
|
|
84
|
+
number_images = [create_number_image(num) for num in numbers]
|
|
85
|
+
|
|
86
|
+
# Combine all values and images
|
|
87
|
+
all_values = color_values + number_values
|
|
88
|
+
all_images = color_images + number_images
|
|
89
|
+
|
|
90
|
+
# Groups for sorting
|
|
91
|
+
groups = [
|
|
92
|
+
["Numbers", "^[0-9]$"],
|
|
93
|
+
["Colors", "__OTHERS__"]
|
|
94
|
+
]
|
|
95
|
+
|
|
96
|
+
# Create dropdown list
|
|
97
|
+
dropdown = CTkScrollableDropdown(attach=combobox, button_color="#2b2b2b", height=200, width=300, fg_color="#333333",
|
|
98
|
+
values=all_values, command=lambda value: print(f"Selected: {value}"),
|
|
99
|
+
image_values=all_images, text_color="#ffffff", hover_color="#3a3a3a",
|
|
100
|
+
font=("Arial", 12), groups=groups, items_per_page=10)
|
|
101
|
+
|
|
102
|
+
root.mainloop()
|
|
103
|
+
```
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: CTkScrollableDropdownPP
|
|
3
|
-
Version: 2.0.3
|
|
4
|
-
Summary: Enhanced CTkScrollableDropdown with pagination, search and groups support
|
|
5
|
-
Author: PLauncher-Team, Akash Bora
|
|
6
|
-
License: MIT
|
|
7
|
-
Project-URL: Homepage, https://github.com/PLauncher-Team/CTkScrollableDropdownPP
|
|
8
|
-
Project-URL: Original, https://github.com/Akascape/CTkScrollableDropdown
|
|
9
|
-
Keywords: customtkinter,dropdown,pagination,search,groups
|
|
10
|
-
Classifier: Programming Language :: Python :: 3
|
|
11
|
-
Classifier: Operating System :: OS Independent
|
|
12
|
-
Requires-Python: >=3.8
|
|
13
|
-
Description-Content-Type: text/markdown
|
|
14
|
-
License-File: LICENSE
|
|
15
|
-
Requires-Dist: customtkinter>=5.2.0
|
|
16
|
-
Dynamic: license-file
|
|
17
|
-
|
|
18
|
-
# CTkScrollableDropdownPP
|
|
19
|
-
|
|
20
|
-
**CTkScrollableDropdownPP** is an enhanced dropdown widget for CustomTkinter featuring pagination, live search, and grouping support.
|
|
21
|
-
|
|
22
|
-
> Based on the original [CTkScrollableDropdown](https://github.com/Akascape/CTkScrollableDropdown) project.
|
|
23
|
-
|
|
24
|
-
## Features
|
|
25
|
-
|
|
26
|
-
* Pagination for large lists
|
|
27
|
-
* Real-time filtering
|
|
28
|
-
* Grouped items (using regex or labels)
|
|
29
|
-
* Autocomplete on typing
|
|
30
|
-
* Fully customizable appearance
|
|
31
|
-
|
|
32
|
-
## Installation
|
|
33
|
-
|
|
34
|
-
```bash
|
|
35
|
-
pip install ctkscrollabledropdownpp
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
## Quick Start
|
|
39
|
-
|
|
40
|
-
```python
|
|
41
|
-
import customtkinter as ctk
|
|
42
|
-
from CTkScrollableDropdownPP import CTkScrollableDropdown
|
|
43
|
-
|
|
44
|
-
app = ctk.CTk()
|
|
45
|
-
app.geometry("400x300")
|
|
46
|
-
|
|
47
|
-
combobox = ctk.CTkComboBox(
|
|
48
|
-
master=app,
|
|
49
|
-
values=[],
|
|
50
|
-
width=200,
|
|
51
|
-
height=30
|
|
52
|
-
)
|
|
53
|
-
combobox.pack(pady=50)
|
|
54
|
-
|
|
55
|
-
values = [f"Item {i}" for i in range(1, 101)]
|
|
56
|
-
|
|
57
|
-
dropdown = CTkScrollableDropdown(
|
|
58
|
-
attach=combobox,
|
|
59
|
-
values=values,
|
|
60
|
-
command=lambda v: print("Selected:", v),
|
|
61
|
-
autocomplete=True,
|
|
62
|
-
groups=[
|
|
63
|
-
('1-50', r'^Item ([1-9]|[1-4][0-9]|50)$'),
|
|
64
|
-
('Others', '__OTHERS__')
|
|
65
|
-
],
|
|
66
|
-
)
|
|
67
|
-
|
|
68
|
-
app.mainloop()
|
|
69
|
-
```
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: CTkScrollableDropdownPP
|
|
3
|
-
Version: 2.0.3
|
|
4
|
-
Summary: Enhanced CTkScrollableDropdown with pagination, search and groups support
|
|
5
|
-
Author: PLauncher-Team, Akash Bora
|
|
6
|
-
License: MIT
|
|
7
|
-
Project-URL: Homepage, https://github.com/PLauncher-Team/CTkScrollableDropdownPP
|
|
8
|
-
Project-URL: Original, https://github.com/Akascape/CTkScrollableDropdown
|
|
9
|
-
Keywords: customtkinter,dropdown,pagination,search,groups
|
|
10
|
-
Classifier: Programming Language :: Python :: 3
|
|
11
|
-
Classifier: Operating System :: OS Independent
|
|
12
|
-
Requires-Python: >=3.8
|
|
13
|
-
Description-Content-Type: text/markdown
|
|
14
|
-
License-File: LICENSE
|
|
15
|
-
Requires-Dist: customtkinter>=5.2.0
|
|
16
|
-
Dynamic: license-file
|
|
17
|
-
|
|
18
|
-
# CTkScrollableDropdownPP
|
|
19
|
-
|
|
20
|
-
**CTkScrollableDropdownPP** is an enhanced dropdown widget for CustomTkinter featuring pagination, live search, and grouping support.
|
|
21
|
-
|
|
22
|
-
> Based on the original [CTkScrollableDropdown](https://github.com/Akascape/CTkScrollableDropdown) project.
|
|
23
|
-
|
|
24
|
-
## Features
|
|
25
|
-
|
|
26
|
-
* Pagination for large lists
|
|
27
|
-
* Real-time filtering
|
|
28
|
-
* Grouped items (using regex or labels)
|
|
29
|
-
* Autocomplete on typing
|
|
30
|
-
* Fully customizable appearance
|
|
31
|
-
|
|
32
|
-
## Installation
|
|
33
|
-
|
|
34
|
-
```bash
|
|
35
|
-
pip install ctkscrollabledropdownpp
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
## Quick Start
|
|
39
|
-
|
|
40
|
-
```python
|
|
41
|
-
import customtkinter as ctk
|
|
42
|
-
from CTkScrollableDropdownPP import CTkScrollableDropdown
|
|
43
|
-
|
|
44
|
-
app = ctk.CTk()
|
|
45
|
-
app.geometry("400x300")
|
|
46
|
-
|
|
47
|
-
combobox = ctk.CTkComboBox(
|
|
48
|
-
master=app,
|
|
49
|
-
values=[],
|
|
50
|
-
width=200,
|
|
51
|
-
height=30
|
|
52
|
-
)
|
|
53
|
-
combobox.pack(pady=50)
|
|
54
|
-
|
|
55
|
-
values = [f"Item {i}" for i in range(1, 101)]
|
|
56
|
-
|
|
57
|
-
dropdown = CTkScrollableDropdown(
|
|
58
|
-
attach=combobox,
|
|
59
|
-
values=values,
|
|
60
|
-
command=lambda v: print("Selected:", v),
|
|
61
|
-
autocomplete=True,
|
|
62
|
-
groups=[
|
|
63
|
-
('1-50', r'^Item ([1-9]|[1-4][0-9]|50)$'),
|
|
64
|
-
('Others', '__OTHERS__')
|
|
65
|
-
],
|
|
66
|
-
)
|
|
67
|
-
|
|
68
|
-
app.mainloop()
|
|
69
|
-
```
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
# CTkScrollableDropdownPP
|
|
2
|
-
|
|
3
|
-
**CTkScrollableDropdownPP** is an enhanced dropdown widget for CustomTkinter featuring pagination, live search, and grouping support.
|
|
4
|
-
|
|
5
|
-
> Based on the original [CTkScrollableDropdown](https://github.com/Akascape/CTkScrollableDropdown) project.
|
|
6
|
-
|
|
7
|
-
## Features
|
|
8
|
-
|
|
9
|
-
* Pagination for large lists
|
|
10
|
-
* Real-time filtering
|
|
11
|
-
* Grouped items (using regex or labels)
|
|
12
|
-
* Autocomplete on typing
|
|
13
|
-
* Fully customizable appearance
|
|
14
|
-
|
|
15
|
-
## Installation
|
|
16
|
-
|
|
17
|
-
```bash
|
|
18
|
-
pip install ctkscrollabledropdownpp
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
## Quick Start
|
|
22
|
-
|
|
23
|
-
```python
|
|
24
|
-
import customtkinter as ctk
|
|
25
|
-
from CTkScrollableDropdownPP import CTkScrollableDropdown
|
|
26
|
-
|
|
27
|
-
app = ctk.CTk()
|
|
28
|
-
app.geometry("400x300")
|
|
29
|
-
|
|
30
|
-
combobox = ctk.CTkComboBox(
|
|
31
|
-
master=app,
|
|
32
|
-
values=[],
|
|
33
|
-
width=200,
|
|
34
|
-
height=30
|
|
35
|
-
)
|
|
36
|
-
combobox.pack(pady=50)
|
|
37
|
-
|
|
38
|
-
values = [f"Item {i}" for i in range(1, 101)]
|
|
39
|
-
|
|
40
|
-
dropdown = CTkScrollableDropdown(
|
|
41
|
-
attach=combobox,
|
|
42
|
-
values=values,
|
|
43
|
-
command=lambda v: print("Selected:", v),
|
|
44
|
-
autocomplete=True,
|
|
45
|
-
groups=[
|
|
46
|
-
('1-50', r'^Item ([1-9]|[1-4][0-9]|50)$'),
|
|
47
|
-
('Others', '__OTHERS__')
|
|
48
|
-
],
|
|
49
|
-
)
|
|
50
|
-
|
|
51
|
-
app.mainloop()
|
|
52
|
-
```
|
{ctkscrollabledropdownpp-2.0.3 → ctkscrollabledropdownpp-2.1}/CTkScrollableDropdownPP/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|