mirror of
https://github.com/TomSchimansky/CustomTkinter.git
synced 2023-08-10 21:13:13 +03:00
fixed focus bug of CTk and CTkToplevel on macOS
This commit is contained in:
parent
2288c255ac
commit
9d7eca7bb1
@ -102,7 +102,7 @@ class CTkComboBox(CTkBaseClass):
|
|||||||
highlightthickness=0,
|
highlightthickness=0,
|
||||||
font=self._apply_font_scaling(self._font))
|
font=self._apply_font_scaling(self._font))
|
||||||
|
|
||||||
self._configure_grid_system()
|
self._create_grid()
|
||||||
|
|
||||||
# insert default value
|
# insert default value
|
||||||
if len(self._values) > 0:
|
if len(self._values) > 0:
|
||||||
@ -123,21 +123,21 @@ class CTkComboBox(CTkBaseClass):
|
|||||||
if self._variable is not None:
|
if self._variable is not None:
|
||||||
self._entry.configure(textvariable=self._variable)
|
self._entry.configure(textvariable=self._variable)
|
||||||
|
|
||||||
def _configure_grid_system(self):
|
def _create_grid(self):
|
||||||
self._canvas.grid(row=0, column=0, rowspan=1, columnspan=1, sticky="nsew")
|
self._canvas.grid(row=0, column=0, rowspan=1, columnspan=1, sticky="nsew")
|
||||||
|
|
||||||
left_section_width = self._current_width - self._current_height
|
left_section_width = self._current_width - self._current_height
|
||||||
self._entry.grid(row=0, column=0, rowspan=1, columnspan=1, sticky="ew",
|
self._entry.grid(row=0, column=0, rowspan=1, columnspan=1, sticky="ew",
|
||||||
padx=(max(self._apply_widget_scaling(self._corner_radius), self._apply_widget_scaling(3)),
|
padx=(max(self._apply_widget_scaling(self._corner_radius), self._apply_widget_scaling(3)),
|
||||||
max(self._apply_widget_scaling(self._current_width - left_section_width + 3), self._apply_widget_scaling(3))),
|
max(self._apply_widget_scaling(self._current_width - left_section_width + 3), self._apply_widget_scaling(3))),
|
||||||
pady=self._border_width)
|
pady=self._apply_widget_scaling(self._border_width))
|
||||||
|
|
||||||
def _set_scaling(self, *args, **kwargs):
|
def _set_scaling(self, *args, **kwargs):
|
||||||
super()._set_scaling(*args, **kwargs)
|
super()._set_scaling(*args, **kwargs)
|
||||||
|
|
||||||
# change entry font size and grid padding
|
# change entry font size and grid padding
|
||||||
self._entry.configure(font=self._apply_font_scaling(self._font))
|
self._entry.configure(font=self._apply_font_scaling(self._font))
|
||||||
self._configure_grid_system()
|
self._create_grid()
|
||||||
|
|
||||||
self._canvas.configure(width=self._apply_widget_scaling(self._desired_width),
|
self._canvas.configure(width=self._apply_widget_scaling(self._desired_width),
|
||||||
height=self._apply_widget_scaling(self._desired_height))
|
height=self._apply_widget_scaling(self._desired_height))
|
||||||
@ -157,7 +157,7 @@ class CTkComboBox(CTkBaseClass):
|
|||||||
# Workaround to force grid to be resized when text changes size.
|
# Workaround to force grid to be resized when text changes size.
|
||||||
# Otherwise grid will lag and only resizes if other mouse action occurs.
|
# Otherwise grid will lag and only resizes if other mouse action occurs.
|
||||||
self._canvas.grid_forget()
|
self._canvas.grid_forget()
|
||||||
self._canvas.grid(row=0, column=0, columnspan=3, sticky="nswe")
|
self._canvas.grid(row=0, column=0, rowspan=1, columnspan=1, sticky="nsew")
|
||||||
|
|
||||||
def destroy(self):
|
def destroy(self):
|
||||||
if isinstance(self._font, CTkFont):
|
if isinstance(self._font, CTkFont):
|
||||||
@ -219,7 +219,7 @@ class CTkComboBox(CTkBaseClass):
|
|||||||
|
|
||||||
if "border_width" in kwargs:
|
if "border_width" in kwargs:
|
||||||
self._border_width = kwargs.pop("border_width")
|
self._border_width = kwargs.pop("border_width")
|
||||||
self._configure_grid_system()
|
self._create_grid()
|
||||||
require_redraw = True
|
require_redraw = True
|
||||||
|
|
||||||
if "state" in kwargs:
|
if "state" in kwargs:
|
||||||
|
@ -5,6 +5,7 @@ from .ctk_canvas import CTkCanvas
|
|||||||
from ..theme_manager import ThemeManager
|
from ..theme_manager import ThemeManager
|
||||||
from ..draw_engine import DrawEngine
|
from ..draw_engine import DrawEngine
|
||||||
from .widget_base_class import CTkBaseClass
|
from .widget_base_class import CTkBaseClass
|
||||||
|
from ..utility.ctk_font import CTkFont
|
||||||
|
|
||||||
from customtkinter.utility.utility_functions import pop_from_dict_by_set, check_kwargs_empty
|
from customtkinter.utility.utility_functions import pop_from_dict_by_set, check_kwargs_empty
|
||||||
|
|
||||||
@ -37,7 +38,7 @@ class CTkEntry(CTkBaseClass):
|
|||||||
|
|
||||||
textvariable: tkinter.Variable = None,
|
textvariable: tkinter.Variable = None,
|
||||||
placeholder_text: str = None,
|
placeholder_text: str = None,
|
||||||
font: Union[str, Tuple] = "default_theme",
|
font: Union[tuple, CTkFont] = "default_theme",
|
||||||
state: str = tkinter.NORMAL,
|
state: str = tkinter.NORMAL,
|
||||||
**kwargs):
|
**kwargs):
|
||||||
|
|
||||||
@ -59,7 +60,6 @@ class CTkEntry(CTkBaseClass):
|
|||||||
self._border_width = ThemeManager.theme["shape"]["entry_border_width"] if border_width == "default_theme" else border_width
|
self._border_width = ThemeManager.theme["shape"]["entry_border_width"] if border_width == "default_theme" else border_width
|
||||||
|
|
||||||
# text and state
|
# text and state
|
||||||
self._font = (ThemeManager.theme["text"]["font"], ThemeManager.theme["text"]["size"]) if font == "default_theme" else font
|
|
||||||
self._is_focused: bool = True
|
self._is_focused: bool = True
|
||||||
self._placeholder_text = placeholder_text
|
self._placeholder_text = placeholder_text
|
||||||
self._placeholder_text_active = False
|
self._placeholder_text_active = False
|
||||||
@ -68,6 +68,11 @@ class CTkEntry(CTkBaseClass):
|
|||||||
self._state = state
|
self._state = state
|
||||||
self._textvariable_callback_name: str = ""
|
self._textvariable_callback_name: str = ""
|
||||||
|
|
||||||
|
# font
|
||||||
|
self._font = CTkFont() if font == "default_theme" else self._check_font_type(font)
|
||||||
|
if isinstance(self._font, CTkFont):
|
||||||
|
self._font.add_size_configure_callback(self._update_font)
|
||||||
|
|
||||||
if not (self._textvariable is None or self._textvariable == ""):
|
if not (self._textvariable is None or self._textvariable == ""):
|
||||||
self._textvariable_callback_name = self._textvariable.trace_add("write", self._textvariable_callback)
|
self._textvariable_callback_name = self._textvariable.trace_add("write", self._textvariable_callback)
|
||||||
|
|
||||||
@ -75,7 +80,6 @@ class CTkEntry(CTkBaseClass):
|
|||||||
highlightthickness=0,
|
highlightthickness=0,
|
||||||
width=self._apply_widget_scaling(self._current_width),
|
width=self._apply_widget_scaling(self._current_width),
|
||||||
height=self._apply_widget_scaling(self._current_height))
|
height=self._apply_widget_scaling(self._current_height))
|
||||||
self._canvas.grid(column=0, row=0, sticky="nswe")
|
|
||||||
self._draw_engine = DrawEngine(self._canvas)
|
self._draw_engine = DrawEngine(self._canvas)
|
||||||
|
|
||||||
self._entry = tkinter.Entry(master=self,
|
self._entry = tkinter.Entry(master=self,
|
||||||
@ -86,14 +90,8 @@ class CTkEntry(CTkBaseClass):
|
|||||||
state=self._state,
|
state=self._state,
|
||||||
textvariable=self._textvariable,
|
textvariable=self._textvariable,
|
||||||
**pop_from_dict_by_set(kwargs, self._valid_tk_entry_attributes))
|
**pop_from_dict_by_set(kwargs, self._valid_tk_entry_attributes))
|
||||||
if self._corner_radius >= self._minimum_x_padding:
|
|
||||||
self._entry.grid(column=0, row=0, sticky="nswe",
|
self._create_grid()
|
||||||
padx=min(self._apply_widget_scaling(self._corner_radius), round(self._apply_widget_scaling(self._current_height/2))),
|
|
||||||
pady=(self._apply_widget_scaling(self._border_width), self._apply_widget_scaling(self._border_width + 1)))
|
|
||||||
else:
|
|
||||||
self._entry.grid(column=0, row=0, sticky="nswe",
|
|
||||||
padx=self._apply_widget_scaling(self._minimum_x_padding),
|
|
||||||
pady=(self._apply_widget_scaling(self._border_width), self._apply_widget_scaling(self._border_width + 1)))
|
|
||||||
|
|
||||||
check_kwargs_empty(kwargs, raise_error=True)
|
check_kwargs_empty(kwargs, raise_error=True)
|
||||||
|
|
||||||
@ -103,6 +101,18 @@ class CTkEntry(CTkBaseClass):
|
|||||||
self._activate_placeholder()
|
self._activate_placeholder()
|
||||||
self._draw()
|
self._draw()
|
||||||
|
|
||||||
|
def _create_grid(self):
|
||||||
|
self._canvas.grid(column=0, row=0, sticky="nswe")
|
||||||
|
|
||||||
|
if self._corner_radius >= self._minimum_x_padding:
|
||||||
|
self._entry.grid(column=0, row=0, sticky="nswe",
|
||||||
|
padx=min(self._apply_widget_scaling(self._corner_radius), round(self._apply_widget_scaling(self._current_height/2))),
|
||||||
|
pady=(self._apply_widget_scaling(self._border_width), self._apply_widget_scaling(self._border_width + 1)))
|
||||||
|
else:
|
||||||
|
self._entry.grid(column=0, row=0, sticky="nswe",
|
||||||
|
padx=self._apply_widget_scaling(self._minimum_x_padding),
|
||||||
|
pady=(self._apply_widget_scaling(self._border_width), self._apply_widget_scaling(self._border_width + 1)))
|
||||||
|
|
||||||
def _textvariable_callback(self, var_name, index, mode):
|
def _textvariable_callback(self, var_name, index, mode):
|
||||||
if self._textvariable.get() == "":
|
if self._textvariable.get() == "":
|
||||||
self._activate_placeholder()
|
self._activate_placeholder()
|
||||||
@ -111,10 +121,8 @@ class CTkEntry(CTkBaseClass):
|
|||||||
super()._set_scaling(*args, **kwargs)
|
super()._set_scaling(*args, **kwargs)
|
||||||
|
|
||||||
self._entry.configure(font=self._apply_font_scaling(self._font))
|
self._entry.configure(font=self._apply_font_scaling(self._font))
|
||||||
self._entry.grid(column=0, row=0, sticky="we",
|
|
||||||
padx=self._apply_widget_scaling(self._corner_radius) if self._corner_radius >= 6 else self._apply_widget_scaling(6))
|
|
||||||
|
|
||||||
self._canvas.configure(width=self._apply_widget_scaling(self._desired_width), height=self._apply_widget_scaling(self._desired_height))
|
self._canvas.configure(width=self._apply_widget_scaling(self._desired_width), height=self._apply_widget_scaling(self._desired_height))
|
||||||
|
self._create_grid()
|
||||||
self._draw(no_color_updates=True)
|
self._draw(no_color_updates=True)
|
||||||
|
|
||||||
def _set_dimensions(self, width=None, height=None):
|
def _set_dimensions(self, width=None, height=None):
|
||||||
@ -124,6 +132,21 @@ class CTkEntry(CTkBaseClass):
|
|||||||
height=self._apply_widget_scaling(self._desired_height))
|
height=self._apply_widget_scaling(self._desired_height))
|
||||||
self._draw()
|
self._draw()
|
||||||
|
|
||||||
|
def _update_font(self):
|
||||||
|
""" pass font to tkinter widgets with applied font scaling and update grid with workaround """
|
||||||
|
self._entry.configure(font=self._apply_font_scaling(self._font))
|
||||||
|
|
||||||
|
# Workaround to force grid to be resized when text changes size.
|
||||||
|
# Otherwise grid will lag and only resizes if other mouse action occurs.
|
||||||
|
self._canvas.grid_forget()
|
||||||
|
self._canvas.grid(column=0, row=0, sticky="nswe")
|
||||||
|
|
||||||
|
def destroy(self):
|
||||||
|
if isinstance(self._font, CTkFont):
|
||||||
|
self._font.remove_size_configure_callback(self._update_font)
|
||||||
|
|
||||||
|
super().destroy()
|
||||||
|
|
||||||
def _draw(self, no_color_updates=False):
|
def _draw(self, no_color_updates=False):
|
||||||
self._canvas.configure(bg=ThemeManager.single_color(self._bg_color, self._appearance_mode))
|
self._canvas.configure(bg=ThemeManager.single_color(self._bg_color, self._appearance_mode))
|
||||||
|
|
||||||
@ -180,16 +203,12 @@ class CTkEntry(CTkBaseClass):
|
|||||||
|
|
||||||
if "border_width" in kwargs:
|
if "border_width" in kwargs:
|
||||||
self._border_width = kwargs.pop("border_width")
|
self._border_width = kwargs.pop("border_width")
|
||||||
|
self._create_grid()
|
||||||
require_redraw = True
|
require_redraw = True
|
||||||
|
|
||||||
if "corner_radius" in kwargs:
|
if "corner_radius" in kwargs:
|
||||||
self._corner_radius = kwargs.pop("corner_radius")
|
self._corner_radius = kwargs.pop("corner_radius")
|
||||||
if self._corner_radius >= self._minimum_x_padding:
|
self._create_grid()
|
||||||
self._entry.grid(column=0, row=0, sticky="we",
|
|
||||||
padx=min(self._apply_widget_scaling(self._corner_radius), round(self._apply_widget_scaling(self._current_height/2))))
|
|
||||||
else:
|
|
||||||
self._entry.grid(column=0, row=0, sticky="we",
|
|
||||||
padx=self._apply_widget_scaling(self._minimum_x_padding))
|
|
||||||
require_redraw = True
|
require_redraw = True
|
||||||
|
|
||||||
if "placeholder_text" in kwargs:
|
if "placeholder_text" in kwargs:
|
||||||
@ -209,8 +228,13 @@ class CTkEntry(CTkBaseClass):
|
|||||||
self._entry.configure(textvariable=self._textvariable)
|
self._entry.configure(textvariable=self._textvariable)
|
||||||
|
|
||||||
if "font" in kwargs:
|
if "font" in kwargs:
|
||||||
self._font = kwargs.pop("font")
|
if isinstance(self._font, CTkFont):
|
||||||
self._entry.configure(font=self._apply_font_scaling(self._font))
|
self._font.remove_size_configure_callback(self._update_font)
|
||||||
|
self._font = self._check_font_type(kwargs.pop("font"))
|
||||||
|
if isinstance(self._font, CTkFont):
|
||||||
|
self._font.add_size_configure_callback(self._update_font)
|
||||||
|
|
||||||
|
self._update_font()
|
||||||
|
|
||||||
if "show" in kwargs:
|
if "show" in kwargs:
|
||||||
if self._placeholder_text_active:
|
if self._placeholder_text_active:
|
||||||
|
@ -239,9 +239,9 @@ class CTkBaseClass(tkinter.Frame):
|
|||||||
if len(font) == 1:
|
if len(font) == 1:
|
||||||
return font
|
return font
|
||||||
elif len(font) == 2:
|
elif len(font) == 2:
|
||||||
return font[0], round(font[1] * self._widget_scaling)
|
return font[0], -abs(round(font[1] * self._widget_scaling))
|
||||||
elif len(font) == 3:
|
elif len(font) == 3:
|
||||||
return font[0], round(font[1] * self._widget_scaling), font[2]
|
return font[0], -abs(round(font[1] * self._widget_scaling)), font[2]
|
||||||
else:
|
else:
|
||||||
raise ValueError(f"Can not scale font {font}. font needs to be tuple of len 1, 2 or 3")
|
raise ValueError(f"Can not scale font {font}. font needs to be tuple of len 1, 2 or 3")
|
||||||
|
|
||||||
|
@ -76,9 +76,9 @@ class CTk(tkinter.Tk):
|
|||||||
self._block_update_dimensions_event = False
|
self._block_update_dimensions_event = False
|
||||||
|
|
||||||
def _focus_in_event(self, event):
|
def _focus_in_event(self, event):
|
||||||
# sometimes window looses focus on macOS if window is selected from Mission Control, so focus has to be forced again
|
# sometimes window looses jumps back on macOS if window is selected from Mission Control, so has to be lifted again
|
||||||
if sys.platform == "darwin":
|
if sys.platform == "darwin":
|
||||||
self.focus_force()
|
self.lift()
|
||||||
|
|
||||||
def _update_dimensions_event(self, event=None):
|
def _update_dimensions_event(self, event=None):
|
||||||
if not self._block_update_dimensions_event:
|
if not self._block_update_dimensions_event:
|
||||||
|
@ -70,9 +70,9 @@ class CTkToplevel(tkinter.Toplevel):
|
|||||||
self.bind('<FocusIn>', self._focus_in_event)
|
self.bind('<FocusIn>', self._focus_in_event)
|
||||||
|
|
||||||
def _focus_in_event(self, event):
|
def _focus_in_event(self, event):
|
||||||
# sometimes window looses focus on macOS if window is selected from Mission Control, so focus has to be forced again
|
# sometimes window looses jumps back on macOS if window is selected from Mission Control, so has to be lifted again
|
||||||
if sys.platform == "darwin":
|
if sys.platform == "darwin":
|
||||||
self.focus_force()
|
self.lift()
|
||||||
|
|
||||||
def _update_dimensions_event(self, event=None):
|
def _update_dimensions_event(self, event=None):
|
||||||
detected_width = self.winfo_width() # detect current window size
|
detected_width = self.winfo_width() # detect current window size
|
||||||
|
@ -42,7 +42,7 @@ b.pack(pady=2)
|
|||||||
b1 = customtkinter.CTkButton(frame_1, text="object default modified")
|
b1 = customtkinter.CTkButton(frame_1, text="object default modified")
|
||||||
b1.pack(pady=(10, 2))
|
b1.pack(pady=(10, 2))
|
||||||
b1.cget("font").configure(size=9)
|
b1.cget("font").configure(size=9)
|
||||||
print(b1.cget("font").cget("size"), b1.cget("font").cget("family"))
|
print("test_font.py:", b1.cget("font").cget("size"), b1.cget("font").cget("family"))
|
||||||
|
|
||||||
b2 = customtkinter.CTkButton(frame_1, text="object default overridden")
|
b2 = customtkinter.CTkButton(frame_1, text="object default overridden")
|
||||||
b2.pack(pady=10)
|
b2.pack(pady=10)
|
||||||
@ -58,7 +58,9 @@ for i in range(30):
|
|||||||
c.grid(row=i, column=2, pady=1)
|
c.grid(row=i, column=2, pady=1)
|
||||||
c = customtkinter.CTkComboBox(frame_2, font=label_font, height=15)
|
c = customtkinter.CTkComboBox(frame_2, font=label_font, height=15)
|
||||||
c.grid(row=i, column=3, pady=1)
|
c.grid(row=i, column=3, pady=1)
|
||||||
frame_2.grid_columnconfigure((0, 1, 2, 3), weight=1)
|
e = customtkinter.CTkEntry(frame_2, font=label_font, height=15, placeholder_text="testtest")
|
||||||
|
e.grid(row=i, column=4, pady=1)
|
||||||
|
frame_2.grid_columnconfigure((0, 1, 2, 3, 4), weight=1)
|
||||||
|
|
||||||
app.after(1500, lambda: label_font.configure(size=10))
|
app.after(1500, lambda: label_font.configure(size=10))
|
||||||
# app.after(1500, lambda: l.configure(text="dshgfldjskhfjdslafhdjsgkkjdaslö"))
|
# app.after(1500, lambda: l.configure(text="dshgfldjskhfjdslafhdjsgkkjdaslö"))
|
||||||
|
@ -8,9 +8,9 @@ app.title("CustomTkinter Test")
|
|||||||
|
|
||||||
|
|
||||||
def change_state(widget):
|
def change_state(widget):
|
||||||
if widget.state == tkinter.NORMAL:
|
if widget.cget("state") == tkinter.NORMAL:
|
||||||
widget.configure(state=tkinter.DISABLED)
|
widget.configure(state=tkinter.DISABLED)
|
||||||
elif widget.state == tkinter.DISABLED:
|
elif widget.cget("state") == tkinter.DISABLED:
|
||||||
widget.configure(state=tkinter.NORMAL)
|
widget.configure(state=tkinter.NORMAL)
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user