Module TkZero.Frame
Creates a themed frame.
Expand source code
"""
Creates a themed frame.
"""
import tkinter as tk
from tkinter import ttk
from typing import Union
from TkZero import Platform
class Frame(ttk.Frame):
def __init__(self, parent: Union[tk.Widget, Union[tk.Tk, tk.Toplevel]]):
"""
Initiate a ttk.Frame.
:param parent: The parent of the frame.
"""
if not isinstance(parent, (tk.Widget, tk.Tk, tk.Toplevel)):
raise TypeError(
f"parent is not a "
f"Union[tk.Widget, Union[tk.Tk, tk.Toplevel]]! "
f"(type passed in: {repr(type(parent))})"
)
super().__init__(master=parent)
self._style_root = "TFrame"
self._enabled = True
@property
def width(self) -> int:
"""
Get the width of the frame.
:return: An int which is the width of the frame.
"""
return self.cget("width")
@width.setter
def width(self, new_width: int) -> None:
"""
Set the width of the frame.
:param new_width: An int which should be the new width of the frame.
Cannot be less than 1.
:return: None.
"""
if not isinstance(new_width, int):
raise TypeError(
f"new_height is not a int! "
f"(type passed in: {repr(type(new_width))})"
)
if new_width < 1:
raise ValueError(
f"new_height is less than 1! " f"(value passed in: {repr(new_width)})"
)
self.configure(width=new_width)
@property
def height(self) -> int:
"""
Get the height of the frame.
:return: An int which is the height of the frame.
"""
return self.cget("height")
@height.setter
def height(self, new_height: int) -> None:
"""
Set the width of the frame.
:param new_height: An int which should be the new height of the frame.
Cannot be less than 1.
:return: None.
"""
if not isinstance(new_height, int):
raise TypeError(
f"new_height is not an int! "
f"(type passed in: {repr(type(new_height))})"
)
if new_height < 1:
raise ValueError(
f"new_height is less than 1! " f"(value passed in: {repr(new_height)})"
)
self.configure(height=new_height)
def _enable_children(
self, parent: Union[tk.Widget, None] = None, enable: bool = True
) -> None:
"""
Enable or disable the children.
:param parent: A tk.Widget that is our parent. If None then default to
self.
:param enable: Whether to enable or disable the children.
:return: None.
"""
if parent is None:
parent = self
for child in parent.winfo_children():
if child.winfo_class() not in ("Frame", "LabelFrame"):
try:
child.state(["!disabled" if enable else "disabled"])
except AttributeError:
child.configure(state=tk.NORMAL if enable else tk.DISABLED)
else:
self._enable_children(parent, enable)
@property
def enabled(self) -> bool:
"""
Get whether this widget is in normal mode or disabled mode. (grayed
out and cannot interact with)
:return: A bool, True if normal otherwise False.
"""
return self._enabled
@enabled.setter
def enabled(self, new_state: bool) -> None:
"""
Set whether this widget is in normal mode or disabled mode. (grayed
out and cannot interact with)
:param new_state: The new state (a bool) True for enabled and False
for disabled.
:return: None.
"""
if not isinstance(new_state, bool):
raise TypeError(
f"new_state is not a bool! "
f"(type passed in: {repr(type(new_state))})"
)
self._enabled = new_state
self._enable_children(enable=self._enabled)
def apply_style(self, style_name: str) -> None:
"""
Apply a theme to this frame.
:param style_name: The name of the theme as a str, ex. "Warning"
:return: None.
"""
if not isinstance(style_name, str):
raise TypeError(
f"style_name is not a str! "
f"(type passed in: {repr(type(style_name))})"
)
self.configure(style=f"{style_name}.{self._style_root}")
class ScrollableFrame(Frame):
def __init__(
self,
parent: Union[tk.Widget, Union[tk.Tk, tk.Toplevel]],
x_scrolling: bool = False,
y_scrolling: bool = True,
):
"""
Create a scrollable frame.
MAKE SURE WHEN GRIDING WIDGETS TO THIS FRAME TO USE THE FRAME
ATTRIBUTE INSTEAD OF THIS FRAME DIRECTLY.
:param parent: The parent of this frame.
:param x_scrolling: A bool on whether to add a scrollbar in the x
direction.
:param y_scrolling: A bool on whether to add a scrollbar in the y
direction.
"""
# https://blog.teclado.com/tkinter-scrollable-frames/
super().__init__(parent)
self.canvas = tk.Canvas(self)
if x_scrolling:
x_scrollbar = ttk.Scrollbar(
self, orient=tk.HORIZONTAL, command=self.canvas.xview
)
if y_scrolling:
y_scrollbar = ttk.Scrollbar(
self, orient=tk.VERTICAL, command=self.canvas.yview
)
self.frame = Frame(self.canvas)
self.frame.bind(
"<Configure>",
lambda _: self.canvas.configure(scrollregion=self.canvas.bbox(tk.ALL)),
)
self.canvas.create_window((0, 0), window=self.frame, anchor=tk.NW)
if x_scrolling:
self.canvas.configure(xscrollcommand=x_scrollbar.set)
if y_scrolling:
self.canvas.configure(yscrollcommand=y_scrollbar.set)
self.canvas.grid(row=0, column=0)
if x_scrolling:
x_scrollbar.grid(row=1, column=0, sticky=tk.NSEW)
if y_scrolling:
y_scrollbar.grid(row=0, column=1, sticky=tk.NSEW)
# https://stackoverflow.com/a/37858368/10291933
self.frame.bind("<Enter>", self._bind_to_mousewheel)
self.frame.bind("<Leave>", self._unbind_to_mousewheel)
self._shift_pressed = False
# https://stackoverflow.com/a/8089241/10291933
# http://www.tcl.tk/man/tcl8.4/TkCmd/keysyms.htm
self.frame.bind_all("<Shift_L>", lambda _: self._set_shift_pressed(True))
self.frame.bind_all("<Shift_R>", lambda _: self._set_shift_pressed(True))
self.frame.bind_all(
"<KeyRelease-Shift_L>", lambda _: self._set_shift_pressed(False)
)
self.frame.bind_all(
"<KeyRelease-Shift_R>", lambda _: self._set_shift_pressed(False)
)
def _set_shift_pressed(self, is_pressed: bool) -> None:
"""
Set whether shift is pressed or not.
:param is_pressed: A bool.
:return: None.
"""
self._shift_pressed = is_pressed
def _bind_to_mousewheel(self, event) -> None:
"""
Bind to the mousewheel.
:param event: An event that Tkinter passes in.
:return: None
"""
self.canvas.bind_all("<MouseWheel>", self._on_mousewheel)
def _unbind_to_mousewheel(self, event) -> None:
"""
Unbind to the mousewheel.
:param event: An event that Tkinter passes in.
:return: None
"""
self.canvas.unbind_all("<MouseWheel>")
def _on_mousewheel(self, event) -> None:
"""
A callback for the mousewheel to scroll.
:param event: An event that Tkinter passes in.
:return: None.
"""
if Platform.on_aqua(self):
scroll = str(int(-1 * event.delta))
else:
scroll = str(int(-1 * (event.delta / 120)))
if self._shift_pressed:
self.canvas.xview_scroll(scroll, tk.UNITS)
else:
self.canvas.yview_scroll(scroll, tk.UNITS)
def _enable_children(
self, parent: Union[tk.Widget, None] = None, enable: bool = True
) -> None:
"""
Enable or disable the children.
:param parent: A tk.Widget that is our parent. If None then default to
self.
:param enable: Whether to enable or disable the children.
:return: None.
"""
if parent is None:
parent = self.frame
for child in parent.winfo_children():
if child.winfo_class() not in ("Frame", "LabelFrame"):
try:
child.state(["!disabled" if enable else "disabled"])
except AttributeError:
child.configure(state=tk.NORMAL if enable else tk.DISABLED)
else:
self._enable_children(parent, enable)
def apply_style(self, style_name: str) -> None:
"""
Apply a theme to this frame.
:param style_name: The name of the theme as a str, ex. "Warning"
:return: None.
"""
if not isinstance(style_name, str):
raise TypeError(
f"style_name is not a str! "
f"(type passed in: {repr(type(style_name))})"
)
self.frame.configure(style=f"{style_name}.{self._style_root}")
Classes
class Frame (parent: Union[tkinter.Widget, tkinter.Tk, tkinter.Toplevel])
-
Ttk Frame widget is a container, used to group other widgets together.
Initiate a ttk.Frame.
:param parent: The parent of the frame.
Expand source code
class Frame(ttk.Frame): def __init__(self, parent: Union[tk.Widget, Union[tk.Tk, tk.Toplevel]]): """ Initiate a ttk.Frame. :param parent: The parent of the frame. """ if not isinstance(parent, (tk.Widget, tk.Tk, tk.Toplevel)): raise TypeError( f"parent is not a " f"Union[tk.Widget, Union[tk.Tk, tk.Toplevel]]! " f"(type passed in: {repr(type(parent))})" ) super().__init__(master=parent) self._style_root = "TFrame" self._enabled = True @property def width(self) -> int: """ Get the width of the frame. :return: An int which is the width of the frame. """ return self.cget("width") @width.setter def width(self, new_width: int) -> None: """ Set the width of the frame. :param new_width: An int which should be the new width of the frame. Cannot be less than 1. :return: None. """ if not isinstance(new_width, int): raise TypeError( f"new_height is not a int! " f"(type passed in: {repr(type(new_width))})" ) if new_width < 1: raise ValueError( f"new_height is less than 1! " f"(value passed in: {repr(new_width)})" ) self.configure(width=new_width) @property def height(self) -> int: """ Get the height of the frame. :return: An int which is the height of the frame. """ return self.cget("height") @height.setter def height(self, new_height: int) -> None: """ Set the width of the frame. :param new_height: An int which should be the new height of the frame. Cannot be less than 1. :return: None. """ if not isinstance(new_height, int): raise TypeError( f"new_height is not an int! " f"(type passed in: {repr(type(new_height))})" ) if new_height < 1: raise ValueError( f"new_height is less than 1! " f"(value passed in: {repr(new_height)})" ) self.configure(height=new_height) def _enable_children( self, parent: Union[tk.Widget, None] = None, enable: bool = True ) -> None: """ Enable or disable the children. :param parent: A tk.Widget that is our parent. If None then default to self. :param enable: Whether to enable or disable the children. :return: None. """ if parent is None: parent = self for child in parent.winfo_children(): if child.winfo_class() not in ("Frame", "LabelFrame"): try: child.state(["!disabled" if enable else "disabled"]) except AttributeError: child.configure(state=tk.NORMAL if enable else tk.DISABLED) else: self._enable_children(parent, enable) @property def enabled(self) -> bool: """ Get whether this widget is in normal mode or disabled mode. (grayed out and cannot interact with) :return: A bool, True if normal otherwise False. """ return self._enabled @enabled.setter def enabled(self, new_state: bool) -> None: """ Set whether this widget is in normal mode or disabled mode. (grayed out and cannot interact with) :param new_state: The new state (a bool) True for enabled and False for disabled. :return: None. """ if not isinstance(new_state, bool): raise TypeError( f"new_state is not a bool! " f"(type passed in: {repr(type(new_state))})" ) self._enabled = new_state self._enable_children(enable=self._enabled) def apply_style(self, style_name: str) -> None: """ Apply a theme to this frame. :param style_name: The name of the theme as a str, ex. "Warning" :return: None. """ if not isinstance(style_name, str): raise TypeError( f"style_name is not a str! " f"(type passed in: {repr(type(style_name))})" ) self.configure(style=f"{style_name}.{self._style_root}")
Ancestors
- tkinter.ttk.Frame
- tkinter.ttk.Widget
- tkinter.Widget
- tkinter.BaseWidget
- tkinter.Misc
- tkinter.Pack
- tkinter.Place
- tkinter.Grid
Subclasses
Instance variables
var enabled : bool
-
Get whether this widget is in normal mode or disabled mode. (grayed out and cannot interact with)
:return: A bool, True if normal otherwise False.
Expand source code
@property def enabled(self) -> bool: """ Get whether this widget is in normal mode or disabled mode. (grayed out and cannot interact with) :return: A bool, True if normal otherwise False. """ return self._enabled
var height : int
-
Get the height of the frame.
:return: An int which is the height of the frame.
Expand source code
@property def height(self) -> int: """ Get the height of the frame. :return: An int which is the height of the frame. """ return self.cget("height")
var width : int
-
Get the width of the frame.
:return: An int which is the width of the frame.
Expand source code
@property def width(self) -> int: """ Get the width of the frame. :return: An int which is the width of the frame. """ return self.cget("width")
Methods
def apply_style(self, style_name: str) ‑> NoneType
-
Apply a theme to this frame.
:param style_name: The name of the theme as a str, ex. "Warning" :return: None.
Expand source code
def apply_style(self, style_name: str) -> None: """ Apply a theme to this frame. :param style_name: The name of the theme as a str, ex. "Warning" :return: None. """ if not isinstance(style_name, str): raise TypeError( f"style_name is not a str! " f"(type passed in: {repr(type(style_name))})" ) self.configure(style=f"{style_name}.{self._style_root}")
class ScrollableFrame (parent: Union[tkinter.Widget, tkinter.Tk, tkinter.Toplevel], x_scrolling: bool = False, y_scrolling: bool = True)
-
Ttk Frame widget is a container, used to group other widgets together.
Create a scrollable frame. MAKE SURE WHEN GRIDING WIDGETS TO THIS FRAME TO USE THE FRAME ATTRIBUTE INSTEAD OF THIS FRAME DIRECTLY.
:param parent: The parent of this frame. :param x_scrolling: A bool on whether to add a scrollbar in the x direction. :param y_scrolling: A bool on whether to add a scrollbar in the y direction.
Expand source code
class ScrollableFrame(Frame): def __init__( self, parent: Union[tk.Widget, Union[tk.Tk, tk.Toplevel]], x_scrolling: bool = False, y_scrolling: bool = True, ): """ Create a scrollable frame. MAKE SURE WHEN GRIDING WIDGETS TO THIS FRAME TO USE THE FRAME ATTRIBUTE INSTEAD OF THIS FRAME DIRECTLY. :param parent: The parent of this frame. :param x_scrolling: A bool on whether to add a scrollbar in the x direction. :param y_scrolling: A bool on whether to add a scrollbar in the y direction. """ # https://blog.teclado.com/tkinter-scrollable-frames/ super().__init__(parent) self.canvas = tk.Canvas(self) if x_scrolling: x_scrollbar = ttk.Scrollbar( self, orient=tk.HORIZONTAL, command=self.canvas.xview ) if y_scrolling: y_scrollbar = ttk.Scrollbar( self, orient=tk.VERTICAL, command=self.canvas.yview ) self.frame = Frame(self.canvas) self.frame.bind( "<Configure>", lambda _: self.canvas.configure(scrollregion=self.canvas.bbox(tk.ALL)), ) self.canvas.create_window((0, 0), window=self.frame, anchor=tk.NW) if x_scrolling: self.canvas.configure(xscrollcommand=x_scrollbar.set) if y_scrolling: self.canvas.configure(yscrollcommand=y_scrollbar.set) self.canvas.grid(row=0, column=0) if x_scrolling: x_scrollbar.grid(row=1, column=0, sticky=tk.NSEW) if y_scrolling: y_scrollbar.grid(row=0, column=1, sticky=tk.NSEW) # https://stackoverflow.com/a/37858368/10291933 self.frame.bind("<Enter>", self._bind_to_mousewheel) self.frame.bind("<Leave>", self._unbind_to_mousewheel) self._shift_pressed = False # https://stackoverflow.com/a/8089241/10291933 # http://www.tcl.tk/man/tcl8.4/TkCmd/keysyms.htm self.frame.bind_all("<Shift_L>", lambda _: self._set_shift_pressed(True)) self.frame.bind_all("<Shift_R>", lambda _: self._set_shift_pressed(True)) self.frame.bind_all( "<KeyRelease-Shift_L>", lambda _: self._set_shift_pressed(False) ) self.frame.bind_all( "<KeyRelease-Shift_R>", lambda _: self._set_shift_pressed(False) ) def _set_shift_pressed(self, is_pressed: bool) -> None: """ Set whether shift is pressed or not. :param is_pressed: A bool. :return: None. """ self._shift_pressed = is_pressed def _bind_to_mousewheel(self, event) -> None: """ Bind to the mousewheel. :param event: An event that Tkinter passes in. :return: None """ self.canvas.bind_all("<MouseWheel>", self._on_mousewheel) def _unbind_to_mousewheel(self, event) -> None: """ Unbind to the mousewheel. :param event: An event that Tkinter passes in. :return: None """ self.canvas.unbind_all("<MouseWheel>") def _on_mousewheel(self, event) -> None: """ A callback for the mousewheel to scroll. :param event: An event that Tkinter passes in. :return: None. """ if Platform.on_aqua(self): scroll = str(int(-1 * event.delta)) else: scroll = str(int(-1 * (event.delta / 120))) if self._shift_pressed: self.canvas.xview_scroll(scroll, tk.UNITS) else: self.canvas.yview_scroll(scroll, tk.UNITS) def _enable_children( self, parent: Union[tk.Widget, None] = None, enable: bool = True ) -> None: """ Enable or disable the children. :param parent: A tk.Widget that is our parent. If None then default to self. :param enable: Whether to enable or disable the children. :return: None. """ if parent is None: parent = self.frame for child in parent.winfo_children(): if child.winfo_class() not in ("Frame", "LabelFrame"): try: child.state(["!disabled" if enable else "disabled"]) except AttributeError: child.configure(state=tk.NORMAL if enable else tk.DISABLED) else: self._enable_children(parent, enable) def apply_style(self, style_name: str) -> None: """ Apply a theme to this frame. :param style_name: The name of the theme as a str, ex. "Warning" :return: None. """ if not isinstance(style_name, str): raise TypeError( f"style_name is not a str! " f"(type passed in: {repr(type(style_name))})" ) self.frame.configure(style=f"{style_name}.{self._style_root}")
Ancestors
- Frame
- tkinter.ttk.Frame
- tkinter.ttk.Widget
- tkinter.Widget
- tkinter.BaseWidget
- tkinter.Misc
- tkinter.Pack
- tkinter.Place
- tkinter.Grid
Inherited members