From 631fb1e6fb31a25bc8f34c83beece9d1ac2be37f Mon Sep 17 00:00:00 2001 From: misygauziya Date: Sat, 15 Jul 2023 09:42:06 +0900 Subject: [PATCH] =?UTF-8?q?=E3=82=B9=E3=82=AF=E3=83=AD=E3=83=BC=E3=83=AB?= =?UTF-8?q?=E3=83=90=E3=83=BC=E3=81=AE=E6=B6=88=E3=81=88=E3=82=8B=E3=82=BF?= =?UTF-8?q?=E3=82=A4=E3=83=9F=E3=83=B3=E3=82=B0=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ctk_scrollable_dropdown.py | 90 +++++++++++++++++++------------------- window_config.py | 56 ++++++++++++------------ 2 files changed, 72 insertions(+), 74 deletions(-) diff --git a/ctk_scrollable_dropdown.py b/ctk_scrollable_dropdown.py index 8ab5296e..091e92e3 100644 --- a/ctk_scrollable_dropdown.py +++ b/ctk_scrollable_dropdown.py @@ -8,29 +8,27 @@ Homepage: https://github.com/Akascape/CTkScrollableDropdown Advanced Scrollable Dropdown class for customtkinter widgets Author: Akash Bora """ - import customtkinter import sys import time class CTkScrollableDropdown(customtkinter.CTkToplevel): - + def __init__(self, attach, x=None, y=None, button_color=None, height: int = 200, width: int = None, fg_color=None, button_height: int = 20, justify="center", scrollbar_button_color=None, scrollbar=True, scrollbar_button_hover_color=None, frame_border_width=2, values=[], command=None, image_values=[], alpha: float = 0.97, frame_corner_radius=20, double_click=False, resize=True, frame_border_color=None, text_color=None, autocomplete=False, **button_kwargs): - + super().__init__(takefocus=1) self.transient(self.master) - self.focus() self.alpha = alpha self.attach = attach self.corner = frame_corner_radius self.padding = 0 self.focus_something = False self.disable = True - + if sys.platform.startswith("win"): self.after(100, lambda: self.overrideredirect(True)) self.transparent_color = self._apply_appearance_mode(self._fg_color) @@ -53,7 +51,7 @@ class CTkScrollableDropdown(customtkinter.CTkToplevel): self.attach.winfo_toplevel().bind("", lambda e: self._withdraw() if not self.disable else None, add="+") self.attach.winfo_toplevel().bind("", lambda e: self._withdraw() if not self.disable else None, add="+") self.attach.winfo_toplevel().bind("", lambda e: self._withdraw() if not self.disable else None, add="+") - + self.attributes('-alpha', 0) self.disable = False self.fg_color = customtkinter.ThemeManager.theme["CTkFrame"]["fg_color"] if fg_color is None else fg_color @@ -62,11 +60,11 @@ class CTkScrollableDropdown(customtkinter.CTkToplevel): self.frame_border_color = customtkinter.ThemeManager.theme["CTkFrame"]["border_color"] if frame_border_color is None else frame_border_color self.button_color = customtkinter.ThemeManager.theme["CTkFrame"]["top_fg_color"] if button_color is None else button_color self.text_color = customtkinter.ThemeManager.theme["CTkLabel"]["text_color"] if text_color is None else text_color - + if scrollbar is False: self.scroll_button_color = self.fg_color self.scroll_hover_color = self.fg_color - + self.frame = customtkinter.CTkScrollableFrame(self, bg_color=self.transparent_color, fg_color=self.fg_color, scrollbar_button_hover_color=self.scroll_hover_color, corner_radius=self.corner, border_width=frame_border_width, @@ -74,6 +72,7 @@ class CTkScrollableDropdown(customtkinter.CTkToplevel): border_color=self.frame_border_color) self.frame._scrollbar.grid_configure(padx=3) self.frame.pack(expand=True, fill="both") + self.dummy_entry = customtkinter.CTkEntry(self.frame, fg_color="transparent", border_width=0, height=1, width=1) self.no_match = customtkinter.CTkLabel(self.frame, text="No Match") self.height = height @@ -85,21 +84,20 @@ class CTkScrollableDropdown(customtkinter.CTkToplevel): self.autocomplete = autocomplete self.var_update = customtkinter.StringVar() self.appear = False - + if justify.lower()=="left": self.justify = "w" elif justify.lower()=="right": self.justify = "e" else: self.justify = "c" - + self.button_height = button_height self.values = values self.button_num = len(self.values) self.image_values = None if len(image_values)!=len(self.values) else image_values - + self.resizable(width=False, height=False) - # self.transient(self.master) self._init_buttons(**button_kwargs) # Add binding for different ctk widgets @@ -113,47 +111,47 @@ class CTkScrollableDropdown(customtkinter.CTkToplevel): self.attach._canvas.tag_bind("dropdown_arrow", "", lambda e: self._iconify()) if self.command is None: self.command = self.attach.set - + if self.attach.winfo_name().startswith("!ctkoptionmenu"): self.attach._canvas.bind("", lambda e: self._iconify()) self.attach._text_label.bind("", lambda e: self._iconify()) if self.command is None: self.command = self.attach.set - + self.update_idletasks() self.x = x self.y = y if self.autocomplete: self.bind_autocomplete() - + self.deiconify() self.withdraw() - + self.attributes("-alpha", self.alpha) - + def _withdraw(self): if self.hide is False: self.withdraw() self.hide = True def _update(self, a, b, c): self.live_update(self.attach._entry.get()) - + def bind_autocomplete(self, ): def appear(x): self.appear = True - + if self.attach.winfo_name().startswith("!ctkcombobox"): self.attach._entry.configure(textvariable=self.var_update) self.attach._entry.bind("", appear) self.attach.set(self.values[0]) self.var_update.trace_add('write', self._update) - + if self.attach.winfo_name().startswith("!ctkentry"): self.attach.configure(textvariable=self.var_update) self.attach.bind("", appear) self.var_update.trace_add('write', self._update) - + def fade_out(self): for i in range(100,0,-10): if not self.winfo_exists(): @@ -161,7 +159,7 @@ class CTkScrollableDropdown(customtkinter.CTkToplevel): self.attributes("-alpha", i/100) self.update() time.sleep(1/100) - + def fade_in(self): for i in range(0,100,10): if not self.winfo_exists(): @@ -169,7 +167,7 @@ class CTkScrollableDropdown(customtkinter.CTkToplevel): self.attributes("-alpha", i/100) self.update() time.sleep(1/100) - + def _init_buttons(self, **button_kwargs): self.i = 0 self.widgets = {} @@ -184,9 +182,9 @@ class CTkScrollableDropdown(customtkinter.CTkToplevel): command=lambda k=row: self._attach_key_press(k), **button_kwargs) self.widgets[self.i].pack(fill="x", pady=2, padx=(self.padding, 0)) self.i+=1 - + self.hide = False - + def destroy_popup(self): self.destroy() self.disable = True @@ -195,9 +193,9 @@ class CTkScrollableDropdown(customtkinter.CTkToplevel): self.x_pos = self.attach.winfo_rootx() if self.x is None else self.x + self.attach.winfo_rootx() self.y_pos = self.attach.winfo_rooty() + self.attach.winfo_reqheight() + 5 if self.y is None else self.y + self.attach.winfo_rooty() self.width_new = self.attach.winfo_width() if self.width is None else self.width - + if self.resize: - if self.button_num==1: + if self.button_num==1: self.height_new = self.button_height * self.button_num + 45 else: self.height_new = self.button_height * self.button_num + 35 @@ -208,23 +206,23 @@ class CTkScrollableDropdown(customtkinter.CTkToplevel): self.x_pos, self.y_pos)) self.fade_in() self.attributes('-alpha', self.alpha) - self.attach.focus() def _iconify(self): if self.disable: return if self.hide: - self._deiconify() - self.focus() - self.hide = False + self._deiconify() self.place_dropdown() if self.focus_something: self.dummy_entry.pack() self.dummy_entry.focus_set() self.after(100, self.dummy_entry.pack_forget) + self.hide = False + self.focus_set() + self.focus() else: self.withdraw() self.hide = True - + def _attach_key_press(self, k): self.fade = True if self.command: @@ -233,7 +231,7 @@ class CTkScrollableDropdown(customtkinter.CTkToplevel): self.fade_out() self.withdraw() self.hide = True - + def live_update(self, string=None): if not self.appear: return if self.disable: return @@ -248,14 +246,14 @@ class CTkScrollableDropdown(customtkinter.CTkToplevel): else: self.widgets[key].pack(fill="x", pady=2, padx=(self.padding, 0)) i+=1 - + if i==1: self.no_match.pack(fill="x", pady=2, padx=(self.padding, 0)) else: self.no_match.pack_forget() self.button_num = i self.place_dropdown() - + else: self.no_match.pack_forget() self.button_num = len(self.values) @@ -263,10 +261,10 @@ class CTkScrollableDropdown(customtkinter.CTkToplevel): self.widgets[key].destroy() self._init_buttons() self.place_dropdown() - + self.frame._parent_canvas.yview_moveto(0.0) self.appear = False - + def insert(self, value, **kwargs): self.widgets[self.i] = customtkinter.CTkButton(self.frame, text=value, @@ -278,7 +276,7 @@ class CTkScrollableDropdown(customtkinter.CTkToplevel): self.widgets[self.i].pack(fill="x", pady=2, padx=(self.padding, 0)) self.i+=1 self.values.append(value) - + def _deiconify(self): if len(self.values)>0: self.deiconify() @@ -288,28 +286,28 @@ class CTkScrollableDropdown(customtkinter.CTkToplevel): self.y = y self.hide = True self._iconify() - + def configure(self, **kwargs): if "height" in kwargs: self.height = kwargs.pop("height") self.height_new = self.height - + if "alpha" in kwargs: self.alpha = kwargs.pop("alpha") - + if "width" in kwargs: self.width = kwargs.pop("width") - + if "fg_color" in kwargs: self.frame.configure(fg_color=kwargs.pop("fg_color")) - + if "values" in kwargs: self.values = kwargs.pop("values") self.image_values = None for key in self.widgets.keys(): self.widgets[key].destroy() self._init_buttons() - + if "image_values" in kwargs: self.image_values = kwargs.pop("image_values") self.image_values = None if len(self.image_values)!=len(self.values) else self.image_values @@ -318,10 +316,10 @@ class CTkScrollableDropdown(customtkinter.CTkToplevel): for key in self.widgets.keys(): self.widgets[key].configure(image=self.image_values[i]) i+=1 - + if "button_color" in kwargs: for key in self.widgets.keys(): self.widgets[key].configure(fg_color=kwargs.pop("button_color")) - + for key in self.widgets.keys(): self.widgets[key].configure(**kwargs) diff --git a/window_config.py b/window_config.py index c300ce1f..c6087fbd 100644 --- a/window_config.py +++ b/window_config.py @@ -533,9 +533,9 @@ class ToplevelWindowConfig(CTkToplevel): command=self.optionmenu_appearance_theme_callback, font=CTkFont(family=self.parent.FONT_FAMILY), ) - self.scrollableDropdown_appearance_theme.frame.bind( + self.scrollableDropdown_appearance_theme.bind( "", - lambda e: self.scrollableDropdown_appearance_theme._iconify(), + lambda e: self.scrollableDropdown_appearance_theme._withdraw() if not str(e.widget).startswith(str(self.scrollableDropdown_appearance_theme.frame._parent_frame)) else None, ) ## optionmenu UI scaling @@ -567,9 +567,9 @@ class ToplevelWindowConfig(CTkToplevel): command=self.optionmenu_ui_scaling_callback, font=CTkFont(family=self.parent.FONT_FAMILY), ) - self.scrollableDropdown_ui_scaling.frame.bind( + self.scrollableDropdown_ui_scaling.bind( "", - lambda e: self.scrollableDropdown_ui_scaling._iconify(), + lambda e: self.scrollableDropdown_ui_scaling._iconify() if not str(e.widget).startswith(str(self.scrollableDropdown_ui_scaling.frame._parent_frame)) else None, ) ## optionmenu font family @@ -599,9 +599,9 @@ class ToplevelWindowConfig(CTkToplevel): command=self.optionmenu_font_family_callback, font=CTkFont(family=self.parent.FONT_FAMILY), ) - self.scrollableDropdown_font_family.frame.bind( + self.scrollableDropdown_font_family.bind( "", - lambda e: self.scrollableDropdown_font_family._iconify(), + lambda e: self.scrollableDropdown_font_family._withdraw() if not str(e.widget).startswith(str(self.scrollableDropdown_font_family.frame._parent_frame)) else None, ) ## optionmenu ui language @@ -634,9 +634,9 @@ class ToplevelWindowConfig(CTkToplevel): command=self.optionmenu_ui_language_callback, font=CTkFont(family=self.parent.FONT_FAMILY), ) - self.scrollableDropdown_ui_language.frame.bind( + self.scrollableDropdown_ui_language.bind( "", - lambda e: self.scrollableDropdown_ui_language._iconify(), + lambda e: self.scrollableDropdown_ui_language._withdraw() if not str(e.widget).startswith(str(self.scrollableDropdown_ui_language.frame._parent_frame)) else None, ) # tab Translation @@ -671,9 +671,9 @@ class ToplevelWindowConfig(CTkToplevel): command=self.optionmenu_translation_translator_callback, font=CTkFont(family=self.parent.FONT_FAMILY), ) - self.scrollableDropdown_translation_translator.frame.bind( + self.scrollableDropdown_translation_translator.bind( "", - lambda e: self.scrollableDropdown_translation_translator._iconify(), + lambda e: self.scrollableDropdown_translation_translator._withdraw() if not str(e.widget).startswith(str(self.scrollableDropdown_translation_translator.frame._parent_frame)) else None, ) ## optionmenu translation input language @@ -707,9 +707,9 @@ class ToplevelWindowConfig(CTkToplevel): command=self.optionmenu_translation_input_source_language_callback, font=CTkFont(family=self.parent.FONT_FAMILY), ) - self.scrollableDropdown_translation_input_source_language.frame.bind( + self.scrollableDropdown_translation_input_source_language.bind( "", - lambda e: self.scrollableDropdown_translation_input_source_language._iconify(), + lambda e: self.scrollableDropdown_translation_input_source_language._withdraw() if not str(e.widget).startswith(str(self.scrollableDropdown_translation_input_source_language.frame._parent_frame)) else None, ) ## label translation input arrow @@ -742,9 +742,9 @@ class ToplevelWindowConfig(CTkToplevel): command=self.optionmenu_translation_input_target_language_callback, font=CTkFont(family=self.parent.FONT_FAMILY), ) - self.scrollableDropdown_translation_input_target_language.frame.bind( + self.scrollableDropdown_translation_input_target_language.bind( "", - lambda e: self.scrollableDropdown_translation_input_target_language._iconify(), + lambda e: self.scrollableDropdown_translation_input_target_language._withdraw() if not str(e.widget).startswith(str(self.scrollableDropdown_translation_input_target_language.frame._parent_frame)) else None, ) ## optionmenu translation output language @@ -778,9 +778,9 @@ class ToplevelWindowConfig(CTkToplevel): command=self.optionmenu_translation_output_source_language_callback, font=CTkFont(family=self.parent.FONT_FAMILY), ) - self.scrollableDropdown_translation_output_source_language.frame.bind( + self.scrollableDropdown_translation_output_source_language.bind( "", - lambda e: self.scrollableDropdown_translation_output_source_language._iconify(), + lambda e: self.scrollableDropdown_translation_output_source_language._withdraw() if not str(e.widget).startswith(str(self.scrollableDropdown_translation_output_source_language.frame._parent_frame)) else None, ) ## label translation output arrow @@ -813,9 +813,9 @@ class ToplevelWindowConfig(CTkToplevel): command=self.optionmenu_translation_output_target_language_callback, font=CTkFont(family=self.parent.FONT_FAMILY), ) - self.scrollableDropdown_translation_output_target_language.frame.bind( + self.scrollableDropdown_translation_output_target_language.bind( "", - lambda e: self.scrollableDropdown_translation_output_target_language._iconify(), + lambda e: self.scrollableDropdown_translation_output_target_language._withdraw() if not str(e.widget).startswith(str(self.scrollableDropdown_translation_output_target_language.frame._parent_frame)) else None, ) # tab Transcription @@ -850,9 +850,9 @@ class ToplevelWindowConfig(CTkToplevel): command=self.optionmenu_input_mic_host_callback, font=CTkFont(family=self.parent.FONT_FAMILY), ) - self.scrollableDropdown_input_mic_host.frame.bind( + self.scrollableDropdown_input_mic_host.bind( "", - lambda e: self.scrollableDropdown_input_mic_host._iconify(), + lambda e: self.scrollableDropdown_input_mic_host._withdraw() if not str(e.widget).startswith(str(self.scrollableDropdown_input_mic_host.frame._parent_frame)) else None, ) ## optionmenu input mic device @@ -884,9 +884,9 @@ class ToplevelWindowConfig(CTkToplevel): command=self.optionmenu_input_mic_device_callback, font=CTkFont(family=self.parent.FONT_FAMILY), ) - self.scrollableDropdown_input_mic_device.frame.bind( + self.scrollableDropdown_input_mic_device.bind( "", - lambda e: self.scrollableDropdown_input_mic_device._iconify(), + lambda e: self.scrollableDropdown_input_mic_device._withdraw() if not str(e.widget).startswith(str(self.scrollableDropdown_input_mic_device.frame._parent_frame)) else None, ) ## optionmenu input mic voice language @@ -918,9 +918,9 @@ class ToplevelWindowConfig(CTkToplevel): command=self.optionmenu_input_mic_voice_language_callback, font=CTkFont(family=self.parent.FONT_FAMILY), ) - self.scrollableDropdown_input_voice_language.frame.bind( + self.scrollableDropdown_input_voice_language.bind( "", - lambda e: self.scrollableDropdown_input_voice_language._iconify(), + lambda e: self.scrollableDropdown_input_voice_language._withdraw() if not str(e.widget).startswith(str(self.scrollableDropdown_input_voice_language.frame._parent_frame)) else None, ) ## slider input mic energy threshold @@ -1085,9 +1085,9 @@ class ToplevelWindowConfig(CTkToplevel): command=self.optionmenu_input_speaker_device_callback, font=CTkFont(family=self.parent.FONT_FAMILY), ) - self.scrollableDropdown_input_speaker_device.frame.bind( + self.scrollableDropdown_input_speaker_device.bind( "", - lambda e: self.scrollableDropdown_input_speaker_device._iconify(), + lambda e: self.scrollableDropdown_input_speaker_device._withdraw() if not str(e.widget).startswith(str(self.scrollableDropdown_input_speaker_device.frame._parent_frame)) else None, ) ## optionmenu input speaker voice language @@ -1119,9 +1119,9 @@ class ToplevelWindowConfig(CTkToplevel): command=self.optionmenu_input_speaker_voice_language_callback, font=CTkFont(family=self.parent.FONT_FAMILY), ) - self.scrollableDropdown_input_speaker_voice_language.frame.bind( + self.scrollableDropdown_input_speaker_voice_language.bind( "", - lambda e: self.scrollableDropdown_input_speaker_voice_language._iconify(), + lambda e: self.scrollableDropdown_input_speaker_voice_language._withdraw() if not str(e.widget).startswith(str(self.scrollableDropdown_input_speaker_voice_language.frame._parent_frame)) else None, ) ## entry input speaker energy threshold