diff --git a/customtkinter/customtkinter_entry.py b/customtkinter/customtkinter_entry.py index e8a9571..9acf6e7 100644 --- a/customtkinter/customtkinter_entry.py +++ b/customtkinter/customtkinter_entry.py @@ -132,6 +132,12 @@ class CTkEntry(tkinter.Frame): self.entry.configure(fg=self.text_color, insertbackground=self.text_color) + def config(self, *args, **kwargs): + self.configure(*args, **kwargs) + + def configure(self, *args, **kwargs): + super().configure(*args, **kwargs) + def change_appearance_mode(self, mode_string): if mode_string.lower() == "dark": self.appearance_mode = 1 diff --git a/customtkinter/customtkinter_label.py b/customtkinter/customtkinter_label.py index 5e89e50..fa54bc6 100644 --- a/customtkinter/customtkinter_label.py +++ b/customtkinter/customtkinter_label.py @@ -44,9 +44,9 @@ class CTkLabel(tkinter.Frame): if sys.platform == "darwin": # macOS self.text_font = ("Avenir", 13) elif "win" in sys.platform: # Windows - self.text_font = ("Century Gothic", 11) + self.text_font = ("Century Gothic", 10) else: - self.text_font = ("TkDefaultFont", 11) + self.text_font = ("TkDefaultFont", 10) else: self.text_font = text_font self.configure(width=self.width, height=self.height) @@ -143,17 +143,8 @@ class CTkLabel(tkinter.Frame): else: self.text_label.configure(bg=self.fg_color) - def configure_color(self, bg_color=None, fg_color=None, text_color=None): - if bg_color is not None: - self.bg_color = bg_color - - if fg_color is not None: - self.fg_color = fg_color - - if text_color is not None: - self.text_color = text_color - - self.draw() + def config(self, *args, **kwargs): + self.configure(*args, **kwargs) def configure(self, *args, **kwargs): require_redraw = False # some attribute changes require a call of self.draw() at the end diff --git a/customtkinter/customtkinter_progressbar.py b/customtkinter/customtkinter_progressbar.py index 430451d..082a0e6 100644 --- a/customtkinter/customtkinter_progressbar.py +++ b/customtkinter/customtkinter_progressbar.py @@ -1,3 +1,4 @@ +import sys import tkinter from .customtkinter_frame import CTkFrame @@ -46,52 +47,146 @@ class CTkProgressBar(tkinter.Frame): self.draw() + # set progress + self.set(self.value) + def detect_color_of_master(self): if isinstance(self.master, CTkFrame): return self.master.fg_color else: return self.master.cget("bg") - def draw(self): - self.canvas.delete("all") - self.border_parts = [] - self.fg_parts = [] - self.progress_parts = [] + def draw(self, no_color_updates=False): + + # decide the drawing method + if sys.platform == "darwin": + # on macOS draw button with polygons (positions are more accurate, macOS has Antialiasing) + self.draw_with_polygon_shapes() + else: + # on Windows and other draw with ovals (corner_radius can be optimised to look better than with polygons) + self.draw_with_ovals_and_rects() + + if no_color_updates is False: + self.canvas.configure(bg=CTkColorManager.single_color(self.bg_color, self.appearance_mode)) + self.canvas.itemconfig("border_parts", fill=CTkColorManager.single_color(self.border_color, self.appearance_mode)) + self.canvas.itemconfig("inner_parts", fill=CTkColorManager.single_color(self.fg_color, self.appearance_mode)) + self.canvas.itemconfig("progress_parts", fill=CTkColorManager.single_color(self.progress_color, self.appearance_mode)) + + def draw_with_polygon_shapes(self): + """ draw the progress bar parts with just three polygons that have a rounded border """ + + coordinate_shift = -1 + width_reduced = -1 + + # create border button parts (only if border exists) + if self.border_width > 0: + if not self.canvas.find_withtag("border_parts"): + self.canvas.create_line((0, 0, 0, 0), tags=("border_line_1", "border_parts")) + + self.canvas.coords("border_line_1", + (self.height / 2, + self.height / 2, + self.width - self.height / 2 + coordinate_shift, + self.height / 2)) + self.canvas.itemconfig("border_line_1", + capstyle=tkinter.ROUND, + width=self.height + width_reduced) + + # create inner button parts + if not self.canvas.find_withtag("inner_parts"): + self.canvas.create_line((0, 0, 0, 0), tags=("inner_line_1", "inner_parts")) + + self.canvas.coords("inner_line_1", + (self.height / 2, + self.height / 2, + self.width - self.height / 2 + coordinate_shift, + self.height / 2)) + self.canvas.itemconfig("inner_line_1", + capstyle=tkinter.ROUND, + width=self.height - self.border_width * 2 + width_reduced) + + # progress parts + if not self.canvas.find_withtag("progress_parts"): + self.canvas.create_line((0, 0, 0, 0), tags=("progress_line_1", "progress_parts")) + + self.canvas.coords("progress_line_1", + (self.height / 2, + self.height / 2, + self.height / 2 + (self.width + coordinate_shift - self.height) * self.value, + self.height / 2)) + self.canvas.itemconfig("progress_line_1", + capstyle=tkinter.ROUND, + width=self.height - self.border_width * 2 + width_reduced) + + def draw_with_ovals_and_rects(self): + """ draw the progress bar parts with ovals and rectangles """ + + if sys.platform == "darwin": + oval_bottom_right_shift = 0 + rect_bottom_right_shift = 0 + else: + # ovals and rects are always rendered too large on Windows and need to be made smaller by -1 + oval_bottom_right_shift = -1 + rect_bottom_right_shift = -1 # frame_border - self.border_parts.append(self.canvas.create_oval(0, 0, - self.height, self.height)) - self.border_parts.append(self.canvas.create_rectangle(self.height/2, 0, - self.width-(self.height/2), self.height)) - self.border_parts.append(self.canvas.create_oval(self.width-self.height, 0, - self.width, self.height)) + if self.border_width > 0: + if not self.canvas.find_withtag("border_parts"): + self.canvas.create_oval((0, 0, 0, 0), tags=("border_oval_1", "border_parts"), width=0) + self.canvas.create_rectangle((0, 0, 0, 0), tags=("border_rect_1", "border_parts"), width=0) + self.canvas.create_oval((0, 0, 0, 0), tags=("border_oval_2", "border_parts"), width=0) + + self.canvas.coords("border_oval_1", (0, + 0, + self.height + oval_bottom_right_shift, + self.height + oval_bottom_right_shift)) + self.canvas.coords("border_rect_1", (self.height/2, + 0, + self.width-(self.height/2) + rect_bottom_right_shift, + self.height + rect_bottom_right_shift)) + self.canvas.coords("border_oval_2", (self.width-self.height, + 0, + self.width + oval_bottom_right_shift, + self.height + oval_bottom_right_shift)) # foreground - self.fg_parts.append(self.canvas.create_oval(self.border_width, self.border_width, - self.height-self.border_width, self.height-self.border_width)) - self.fg_parts.append(self.canvas.create_rectangle(self.height/2, self.border_width, - self.width-(self.height/2), self.height-self.border_width)) - self.fg_parts.append(self.canvas.create_oval(self.width-self.height+self.border_width, self.border_width, - self.width-self.border_width, self.height-self.border_width)) + if not self.canvas.find_withtag("inner_parts"): + self.canvas.create_oval((0, 0, 0, 0), tags=("inner_oval_1", "inner_parts"), width=0) + self.canvas.create_rectangle((0, 0, 0, 0), tags=("inner_rect_1", "inner_parts"), width=0) + self.canvas.create_oval((0, 0, 0, 0), tags=("inner_oval_2", "inner_parts"), width=0) - if type(self.bg_color) == tuple: - self.canvas.configure(bg=self.bg_color[self.appearance_mode]) - else: - self.canvas.configure(bg=self.bg_color) + self.canvas.coords("inner_oval_1", (self.border_width, + self.border_width, + self.height-self.border_width + oval_bottom_right_shift, + self.height-self.border_width + oval_bottom_right_shift)) + self.canvas.coords("inner_rect_1", (self.height/2, + self.border_width, + self.width-(self.height/2 + rect_bottom_right_shift), + self.height-self.border_width + rect_bottom_right_shift)) + self.canvas.coords("inner_oval_2", (self.width-self.height+self.border_width, + self.border_width, + self.width-self.border_width + oval_bottom_right_shift, + self.height-self.border_width + oval_bottom_right_shift)) - for part in self.border_parts: - if type(self.border_color) == tuple: - self.canvas.itemconfig(part, fill=self.border_color[self.appearance_mode], width=0) - else: - self.canvas.itemconfig(part, fill=self.border_color, width=0) + # progress parts + if not self.canvas.find_withtag("progress_parts"): + self.canvas.create_oval((0, 0, 0, 0), tags=("progress_oval_1", "progress_parts"), width=0) + self.canvas.create_rectangle((0, 0, 0, 0), tags=("progress_rect_1", "progress_parts"), width=0) + self.canvas.create_oval((0, 0, 0, 0), tags=("progress_oval_2", "progress_parts"), width=0) - for part in self.fg_parts: - if type(self.fg_color) == tuple: - self.canvas.itemconfig(part, fill=self.fg_color[self.appearance_mode], width=0) - else: - self.canvas.itemconfig(part, fill=self.fg_color, width=0) - - self.set(self.value) + self.canvas.coords("progress_oval_1", (self.border_width, + self.border_width, + self.height - self.border_width + oval_bottom_right_shift, + self.height - self.border_width + oval_bottom_right_shift)) + self.canvas.coords("progress_rect_1", (self.height / 2, + self.border_width, + self.height / 2 + (self.width - self.height) * self.value + rect_bottom_right_shift, + self.height - self.border_width + rect_bottom_right_shift)) + self.canvas.coords("progress_oval_2", + (self.height / 2 + (self.width - self.height) * self.value - self.height / 2 + self.border_width, + self.border_width, + self.height / 2 + (self.width - self.height) * self.value + self.height / 2 - self.border_width + oval_bottom_right_shift, + self.height - self.border_width + oval_bottom_right_shift)) def set(self, value): self.value = value @@ -101,33 +196,7 @@ class CTkProgressBar(tkinter.Frame): elif self.value < 0: self.value = 0 - for part in self.progress_parts: - self.canvas.delete(part) - - # progress - self.progress_parts.append(self.canvas.create_oval(self.border_width, - self.border_width, - self.height - self.border_width, - self.height - self.border_width)) - - self.progress_parts.append(self.canvas.create_rectangle(self.height / 2, - self.border_width, - self.height / 2 + (self.width - self.height) * self.value, - self.height - self.border_width)) - - self.progress_parts.append(self.canvas.create_oval(self.height / 2 + (self.width - self.height) * self.value - (self.height) / 2 + self.border_width, - self.border_width, - self.height / 2 + (self.width - self.height) * self.value + (self.height) / 2 - self.border_width, - self.height - self.border_width)) - - for part in self.progress_parts: - if type(self.progress_color) == tuple: - self.canvas.itemconfig(part, fill=self.progress_color[self.appearance_mode], width=0) - else: - self.canvas.itemconfig(part, fill=self.progress_color, width=0) - - self.canvas.update() - self.canvas.update_idletasks() + self.draw(no_color_updates=True) def change_appearance_mode(self, mode_string): if mode_string.lower() == "dark": diff --git a/customtkinter/customtkinter_slider.py b/customtkinter/customtkinter_slider.py index a3940c4..4922749 100644 --- a/customtkinter/customtkinter_slider.py +++ b/customtkinter/customtkinter_slider.py @@ -107,7 +107,7 @@ class CTkSlider(tkinter.Frame): for part in self.button_parts: self.canvas.itemconfig(part, fill=CTkColorManager.single_color(self.button_color, self.appearance_mode), width=0) - def clicked(self, event=0): + def clicked(self, event=None): self.value = event.x / self.width if self.value > 1: diff --git a/examples/complex_example.py b/examples/complex_example.py index bc00696..fbdcbaf 100644 --- a/examples/complex_example.py +++ b/examples/complex_example.py @@ -90,8 +90,10 @@ class App(tkinter.Tk): self.progressbar = customtkinter.CTkProgressBar(master=self.frame_info, width=250, - height=15, - border_width=0) + height=16, + border_color="gray10", + progress_color="green", + border_width=2) self.progressbar.place(relx=0.5, rely=0.85, anchor=tkinter.S) # ============ frame_right <- ============ @@ -142,7 +144,7 @@ class App(tkinter.Tk): corner_radius=8) self.button_5.place(relx=0.66, rely=0.92, anchor=tkinter.CENTER) - self.progressbar.set(0.65) + #self.progressbar.set(0.65) def button_event(self): print("Button pressed")