mirror of
https://github.com/TomSchimansky/CustomTkinter.git
synced 2023-08-10 21:13:13 +03:00
parent
73ab410a96
commit
deebaa9163
@ -142,41 +142,52 @@ class CTk(tkinter.Tk):
|
|||||||
|
|
||||||
def geometry(self, geometry_string: str = None):
|
def geometry(self, geometry_string: str = None):
|
||||||
if geometry_string is not None:
|
if geometry_string is not None:
|
||||||
print(self.apply_geometry_scaling(geometry_string), geometry_string)
|
|
||||||
super().geometry(self.apply_geometry_scaling(geometry_string))
|
super().geometry(self.apply_geometry_scaling(geometry_string))
|
||||||
|
|
||||||
# update width and height attributes
|
# update width and height attributes
|
||||||
numbers = list(map(int, re.split(r"[x+-]", geometry_string))) # split geometry string into list of numbers
|
width, height, x, y = self.parse_geometry_string(geometry_string)
|
||||||
self.current_width = max(self.min_width, min(numbers[0], self.max_width)) # bound value between min and max
|
if width is not None and height is not None:
|
||||||
self.current_height = max(self.min_height, min(numbers[1], self.max_height))
|
self.current_width = max(self.min_width, min(width, self.max_width)) # bound value between min and max
|
||||||
|
self.current_height = max(self.min_height, min(height, self.max_height))
|
||||||
else:
|
else:
|
||||||
return self.reverse_geometry_scaling(super().geometry())
|
return self.reverse_geometry_scaling(super().geometry())
|
||||||
|
|
||||||
def apply_geometry_scaling(self, geometry_string):
|
@staticmethod
|
||||||
value_list = re.split(r"[x+-]", geometry_string)
|
def parse_geometry_string(geometry_string: str) -> tuple:
|
||||||
separator_list = re.split(r"\d+", geometry_string)
|
# index: 1 2 3 4 5 6
|
||||||
|
# regex group structure: ('<width>x<height>', '<width>', '<height>', '+-<x>+-<y>', '-<x>', '-<y>')
|
||||||
|
result = re.search(r"((\d+)x(\d+)){0,1}(\+{0,1}([+-]{0,1}\d+)\+{0,1}([+-]{0,1}\d+)){0,1}", geometry_string)
|
||||||
|
|
||||||
if len(value_list) == 2:
|
width = int(result.group(2)) if result.group(2) is not None else None
|
||||||
scaled_width = str(round(int(value_list[0]) * self.window_scaling))
|
height = int(result.group(3)) if result.group(3) is not None else None
|
||||||
scaled_height = str(round(int(value_list[1]) * self.window_scaling))
|
x = int(result.group(5)) if result.group(5) is not None else None
|
||||||
return f"{scaled_width}x{scaled_height}"
|
y = int(result.group(6)) if result.group(6) is not None else None
|
||||||
elif len(value_list) == 4:
|
|
||||||
scaled_width = str(round(int(value_list[0]) * self.window_scaling))
|
|
||||||
scaled_height = str(round(int(value_list[1]) * self.window_scaling))
|
|
||||||
return f"{scaled_width}x{scaled_height}{separator_list[2]}{value_list[2]}{separator_list[3]}{value_list[3]}"
|
|
||||||
|
|
||||||
def reverse_geometry_scaling(self, scaled_geometry_string):
|
return width, height, x, y
|
||||||
value_list = re.split(r"[x+-]", scaled_geometry_string)
|
|
||||||
separator_list = re.split(r"\d+", scaled_geometry_string)
|
|
||||||
|
|
||||||
if len(value_list) == 2:
|
def apply_geometry_scaling(self, geometry_string: str) -> str:
|
||||||
width = str(round(int(value_list[0]) / self.window_scaling))
|
width, height, x, y = self.parse_geometry_string(geometry_string)
|
||||||
height = str(round(int(value_list[1]) / self.window_scaling))
|
|
||||||
return f"{width}x{height}"
|
if x is None and y is None: # no <x> and <y> in geometry_string
|
||||||
elif len(value_list) == 4:
|
return f"{round(width * self.window_scaling)}x{round(height * self.window_scaling)}"
|
||||||
width = str(round(int(value_list[0]) / self.window_scaling))
|
|
||||||
height = str(round(int(value_list[1]) / self.window_scaling))
|
elif width is None and height is None: # no <width> and <height> in geometry_string
|
||||||
return f"{width}x{height}{separator_list[2]}{value_list[2]}{separator_list[3]}{value_list[3]}"
|
return f"+{x}+{y}"
|
||||||
|
|
||||||
|
else:
|
||||||
|
return f"{round(width * self.window_scaling)}x{round(height * self.window_scaling)}+{x}+{y}"
|
||||||
|
|
||||||
|
def reverse_geometry_scaling(self, scaled_geometry_string: str) -> str:
|
||||||
|
width, height, x, y = self.parse_geometry_string(scaled_geometry_string)
|
||||||
|
|
||||||
|
if x is None and y is None: # no <x> and <y> in geometry_string
|
||||||
|
return f"{round(width / self.window_scaling)}x{round(height / self.window_scaling)}"
|
||||||
|
|
||||||
|
elif width is None and height is None: # no <width> and <height> in geometry_string
|
||||||
|
return f"+{x}+{y}"
|
||||||
|
|
||||||
|
else:
|
||||||
|
return f"{round(width / self.window_scaling)}x{round(height / self.window_scaling)}+{x}+{y}"
|
||||||
|
|
||||||
def apply_window_scaling(self, value):
|
def apply_window_scaling(self, value):
|
||||||
if isinstance(value, (int, float)):
|
if isinstance(value, (int, float)):
|
||||||
|
@ -83,31 +83,54 @@ class CTkToplevel(tkinter.Toplevel):
|
|||||||
if self.max_width is not None or self.max_height is not None:
|
if self.max_width is not None or self.max_height is not None:
|
||||||
super().maxsize(self.apply_window_scaling(self.max_width), self.apply_window_scaling(self.max_height))
|
super().maxsize(self.apply_window_scaling(self.max_width), self.apply_window_scaling(self.max_height))
|
||||||
|
|
||||||
def apply_geometry_scaling(self, geometry_string):
|
def geometry(self, geometry_string: str = None):
|
||||||
value_list = re.split(r"[x+-]", geometry_string)
|
if geometry_string is not None:
|
||||||
separator_list = re.split(r"\d+", geometry_string)
|
super().geometry(self.apply_geometry_scaling(geometry_string))
|
||||||
|
|
||||||
if len(value_list) == 2:
|
# update width and height attributes
|
||||||
scaled_width = str(round(int(value_list[0]) * self.window_scaling))
|
width, height, x, y = self.parse_geometry_string(geometry_string)
|
||||||
scaled_height = str(round(int(value_list[1]) * self.window_scaling))
|
if width is not None and height is not None:
|
||||||
return f"{scaled_width}x{scaled_height}"
|
self.current_width = max(self.min_width, min(width, self.max_width)) # bound value between min and max
|
||||||
elif len(value_list) == 4:
|
self.current_height = max(self.min_height, min(height, self.max_height))
|
||||||
scaled_width = str(round(int(value_list[0]) * self.window_scaling))
|
else:
|
||||||
scaled_height = str(round(int(value_list[1]) * self.window_scaling))
|
return self.reverse_geometry_scaling(super().geometry())
|
||||||
return f"{scaled_width}x{scaled_height}{separator_list[2]}{value_list[2]}{separator_list[3]}{value_list[3]}"
|
|
||||||
|
|
||||||
def reverse_geometry_scaling(self, scaled_geometry_string):
|
@staticmethod
|
||||||
value_list = re.split(r"[x+-]", scaled_geometry_string)
|
def parse_geometry_string(geometry_string: str) -> tuple:
|
||||||
separator_list = re.split(r"\d+", scaled_geometry_string)
|
# index: 1 2 3 4 5 6
|
||||||
|
# regex group structure: ('<width>x<height>', '<width>', '<height>', '+-<x>+-<y>', '-<x>', '-<y>')
|
||||||
|
result = re.search(r"((\d+)x(\d+)){0,1}(\+{0,1}([+-]{0,1}\d+)\+{0,1}([+-]{0,1}\d+)){0,1}", geometry_string)
|
||||||
|
|
||||||
if len(value_list) == 2:
|
width = int(result.group(2)) if result.group(2) is not None else None
|
||||||
width = str(round(int(value_list[0]) / self.window_scaling))
|
height = int(result.group(3)) if result.group(3) is not None else None
|
||||||
height = str(round(int(value_list[1]) / self.window_scaling))
|
x = int(result.group(5)) if result.group(5) is not None else None
|
||||||
return f"{width}x{height}"
|
y = int(result.group(6)) if result.group(6) is not None else None
|
||||||
elif len(value_list) == 4:
|
|
||||||
width = str(round(int(value_list[0]) / self.window_scaling))
|
return width, height, x, y
|
||||||
height = str(round(int(value_list[1]) / self.window_scaling))
|
|
||||||
return f"{width}x{height}{separator_list[2]}{value_list[2]}{separator_list[3]}{value_list[3]}"
|
def apply_geometry_scaling(self, geometry_string: str) -> str:
|
||||||
|
width, height, x, y = self.parse_geometry_string(geometry_string)
|
||||||
|
|
||||||
|
if x is None and y is None: # no <x> and <y> in geometry_string
|
||||||
|
return f"{round(width * self.window_scaling)}x{round(height * self.window_scaling)}"
|
||||||
|
|
||||||
|
elif width is None and height is None: # no <width> and <height> in geometry_string
|
||||||
|
return f"+{x}+{y}"
|
||||||
|
|
||||||
|
else:
|
||||||
|
return f"{round(width * self.window_scaling)}x{round(height * self.window_scaling)}+{x}+{y}"
|
||||||
|
|
||||||
|
def reverse_geometry_scaling(self, scaled_geometry_string: str) -> str:
|
||||||
|
width, height, x, y = self.parse_geometry_string(scaled_geometry_string)
|
||||||
|
|
||||||
|
if x is None and y is None: # no <x> and <y> in geometry_string
|
||||||
|
return f"{round(width / self.window_scaling)}x{round(height / self.window_scaling)}"
|
||||||
|
|
||||||
|
elif width is None and height is None: # no <width> and <height> in geometry_string
|
||||||
|
return f"+{x}+{y}"
|
||||||
|
|
||||||
|
else:
|
||||||
|
return f"{round(width / self.window_scaling)}x{round(height / self.window_scaling)}+{x}+{y}"
|
||||||
|
|
||||||
def apply_window_scaling(self, value):
|
def apply_window_scaling(self, value):
|
||||||
if isinstance(value, (int, float)):
|
if isinstance(value, (int, float)):
|
||||||
@ -115,17 +138,6 @@ class CTkToplevel(tkinter.Toplevel):
|
|||||||
else:
|
else:
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def geometry(self, geometry_string: str = None):
|
|
||||||
if geometry_string is not None:
|
|
||||||
super().geometry(self.apply_geometry_scaling(geometry_string))
|
|
||||||
|
|
||||||
# update width and height attributes
|
|
||||||
numbers = list(map(int, re.split(r"[x+]", geometry_string))) # split geometry string into list of numbers
|
|
||||||
self.current_width = max(self.min_width, min(numbers[0], self.max_width)) # bound value between min and max
|
|
||||||
self.current_height = max(self.min_height, min(numbers[1], self.max_height))
|
|
||||||
else:
|
|
||||||
return self.reverse_geometry_scaling(super().geometry())
|
|
||||||
|
|
||||||
def destroy(self):
|
def destroy(self):
|
||||||
AppearanceModeTracker.remove(self.set_appearance_mode)
|
AppearanceModeTracker.remove(self.set_appearance_mode)
|
||||||
ScalingTracker.remove_window(self.set_scaling, self)
|
ScalingTracker.remove_window(self.set_scaling, self)
|
||||||
|
@ -12,7 +12,7 @@ class App(customtkinter.CTk):
|
|||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
self.title("CustomTkinter complex_example.py")
|
self.title("CustomTkinter complex_example.py")
|
||||||
self.geometry(f"{920}x{500}")
|
self.geometry(f"{920}x{500}-100-100")
|
||||||
self.protocol("WM_DELETE_WINDOW", self.on_closing) # call .on_closing() when app gets closed
|
self.protocol("WM_DELETE_WINDOW", self.on_closing) # call .on_closing() when app gets closed
|
||||||
|
|
||||||
# configure grid layout (4x4)
|
# configure grid layout (4x4)
|
||||||
|
35
test/manual_integration_tests/test_window_geometry.py
Normal file
35
test/manual_integration_tests/test_window_geometry.py
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import customtkinter
|
||||||
|
|
||||||
|
customtkinter.set_window_scaling(1.3)
|
||||||
|
|
||||||
|
app = customtkinter.CTk()
|
||||||
|
app.geometry("300x300")
|
||||||
|
app.geometry("-100-100")
|
||||||
|
app.geometry("+-100+-100")
|
||||||
|
app.geometry("+100+100")
|
||||||
|
app.geometry("300x300-100-100")
|
||||||
|
app.geometry("300x300+-100+-100")
|
||||||
|
app.geometry("300x300+100+100")
|
||||||
|
|
||||||
|
app.geometry("400x400")
|
||||||
|
app.geometry("+400+400")
|
||||||
|
app.update()
|
||||||
|
print(app.geometry())
|
||||||
|
assert app.geometry() == "400x400+400+400"
|
||||||
|
|
||||||
|
toplevel = customtkinter.CTkToplevel(app)
|
||||||
|
toplevel.geometry("300x300")
|
||||||
|
toplevel.geometry("-100-100")
|
||||||
|
toplevel.geometry("+-100+-100")
|
||||||
|
toplevel.geometry("+100+100")
|
||||||
|
toplevel.geometry("300x300-100-100")
|
||||||
|
toplevel.geometry("300x300+-100+-100")
|
||||||
|
toplevel.geometry("300x300+100+100")
|
||||||
|
|
||||||
|
toplevel.geometry("300x300")
|
||||||
|
toplevel.geometry("+500+500")
|
||||||
|
toplevel.update()
|
||||||
|
print(toplevel.geometry())
|
||||||
|
assert toplevel.geometry() == "300x300+500+500"
|
||||||
|
|
||||||
|
app.mainloop()
|
Loading…
Reference in New Issue
Block a user