Module TkZero.Text

Creates a "classic" Text.

Expand source code
"""
Creates a "classic" Text.
"""

import tkinter as tk
from typing import Union

from TkZero.Platform import on_aqua


class TextWrap:
    """
    The ways a tk.Text can wrap.
    NoWrapping - no wrapping.
    CharWrapping - wrap at any character and can br
     eak randomly.
    WordWrapping - wrap at word
     spaces.
    """

    NoWrapping = tk.NONE
    CharWrapping = tk.CHAR
    WordWrapping = tk.WORD


class Text(tk.Text):
    def __init__(
        self,
        parent: Union[tk.Widget, Union[tk.Tk, tk.Toplevel]],
        width: int = None,
        height: int = None,
        wrapping: str = TextWrap.WordWrapping,
    ):
        """
        Initiate a tk.Text.

        :param parent: The parent of the text.
        :param width: The width of the text. Defaults to None.
        :param height: The width of the text. Defaults to None.
        :param wrapping: How to wrap words in the text. Defaults to
         TextWrap.WordWrapping
        """
        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))})"
            )
        if not isinstance(width, int) and width is not None:
            raise TypeError(
                f"width is not a int! (type passed in: {repr(type(width))})"
            )
        if not isinstance(height, int) and height is not None:
            raise TypeError(
                f"height is not a int! (type passed in: {repr(type(height))})"
            )
        if not isinstance(wrapping, str):
            raise TypeError(
                f"wrapping is not a str! " f"(type passed in: {repr(type(wrapping))})"
            )
        super().__init__(master=parent, width=width, height=height, wrap=wrapping)
        self._enabled = True
        self._readonly = False
        if on_aqua(self):
            self.bind("<2>", lambda event: self._popup(event=event))
            self.bind("<Control-1>", lambda event: self._popup(event=event))
        else:
            self.bind("<3>", lambda event: self._popup(event=event))
        self._make_context_menu()
        # https://stackoverflow.com/a/40618152/10291933
        self._orig = self._w + "_orig"
        self.tk.call("rename", self._w, self._orig)
        self.tk.createcommand(self._w, self._proxy)

    def _proxy(self, command, *args):
        cmd = (self._orig, command) + args
        result = self.tk.call(cmd)
        if command in ("insert", "delete", "replace"):
            self.event_generate("<<TextModified>>")
        return result

    @property
    def text(self) -> str:
        """
        Get the text in this text.

        :return: A str of the text.
        """
        return self.get("1.0", tk.END)

    @text.setter
    def text(self, new_text: str) -> None:
        """
        Set the text on this entry.

        :param new_text: The new text.
        :return: None.
        """
        if not isinstance(new_text, str):
            raise TypeError(
                f"new_text is not a str! " f"(type passed in: {repr(type(new_text))})"
            )
        self.delete("1.0", tk.END)
        self.insert("1.0", new_text)

    @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._readonly = False
        self.configure(state=tk.NORMAL if self._enabled else tk.DISABLED)

    def _make_context_menu(self) -> None:
        """
        Initiate the context menu.

        :return: None.
        """
        self._context_menu = tk.Menu(self, tearoff=0)
        self._context_menu.add_command(
            label="Copy",
            command=self.copy_contents,
            underline=0,
            accelerator="Command-C" if on_aqua(self) else "Control+C",
        )
        self._context_menu.add_command(
            label="Cut",
            command=self.cut_contents,
            accelerator="Command-X" if on_aqua(self) else "Control+X",
        )
        self._context_menu.add_command(
            label="Paste",
            command=self.paste_contents,
            underline=0,
            accelerator="Command-V" if on_aqua(self) else "Control+V",
        )
        self._context_menu.add_separator()
        self._context_menu.add_command(
            label="Delete", command=self.delete_contents, accelerator="Delete"
        )
        self._context_menu.add_separator()
        self._context_menu.add_command(
            label="Select all",
            command=self.select_all_contents,
            underline=7,
            accelerator="Command-A" if on_aqua(self) else "Control+A",
        )

    def _update_context_menu_states(self) -> None:
        """
        Update the context menu states, like whether to allow copying or not.

        :return: None.
        """
        if not self.enabled:
            self._context_menu.entryconfigure("Copy", state=tk.DISABLED)
            self._context_menu.entryconfigure("Cut", state=tk.DISABLED)
            self._context_menu.entryconfigure("Paste", state=tk.DISABLED)
            self._context_menu.entryconfigure("Delete", state=tk.DISABLED)
            self._context_menu.entryconfigure("Select all", state=tk.DISABLED)
            return
        if self.tag_ranges(tk.SEL):
            self._context_menu.entryconfigure("Copy", state=tk.NORMAL)
            self._context_menu.entryconfigure("Cut", state=tk.NORMAL)
            self._context_menu.entryconfigure("Paste", state=tk.NORMAL)
            self._context_menu.entryconfigure("Delete", state=tk.NORMAL)
            self._context_menu.entryconfigure("Select all", state=tk.DISABLED)
        else:
            self._context_menu.entryconfigure("Copy", state=tk.DISABLED)
            self._context_menu.entryconfigure("Cut", state=tk.DISABLED)
            self._context_menu.entryconfigure("Paste", state=tk.NORMAL)
            self._context_menu.entryconfigure("Delete", state=tk.DISABLED)
            self._context_menu.entryconfigure("Select all", state=tk.NORMAL)

    def _popup(self, event) -> None:
        """
        Try to pop up the context menu.

        :param event: An object that Tk passes in with information about the
         event that we need.
        :return: None.
        """
        self._update_context_menu_states()
        if self.enabled:
            try:
                self._context_menu.tk_popup(event.x_root, event.y_root, 0)
            finally:
                self._context_menu.grab_release()

    def select_all_contents(self) -> None:
        """
        Select everything.

        :return: None.
        """
        self.tag_add(tk.SEL, "1.0", tk.END)
        self.mark_set(tk.INSERT, "1.0")
        self.see(tk.INSERT)

    def delete_contents(self) -> None:
        """
        Delete the highlighted things.

        :return: None.
        """
        if self.tag_ranges(tk.SEL):
            self.delete(tk.SEL_FIRST, tk.SEL_LAST)

    def paste_contents(self) -> None:
        """
        Paste into the entry.

        :return: None.
        """
        self.delete_contents()
        self.insert(self.index(tk.INSERT), self.clipboard_get())

    def cut_contents(self) -> None:
        """
        Cut the highlighted contents.

        :return: None.
        """
        if self.tag_ranges(tk.SEL):
            self.clipboard_clear()
            self.clipboard_append(self.selection_get())
            self.update()
            self.delete_contents()

    def copy_contents(self) -> None:
        """
        Copy the highlighted contents.

        :return: None.
        """
        if self.tag_ranges(tk.SEL):
            self.clipboard_clear()
            self.clipboard_append(self.selection_get())
            self.update()

Classes

class Text (parent: Union[tkinter.Widget, tkinter.Tk, tkinter.Toplevel], width: int = None, height: int = None, wrapping: str = 'word')

Text widget which can display text in various forms.

Initiate a tk.Text.

:param parent: The parent of the text. :param width: The width of the text. Defaults to None. :param height: The width of the text. Defaults to None. :param wrapping: How to wrap words in the text. Defaults to TextWrap.WordWrapping

Expand source code
class Text(tk.Text):
    def __init__(
        self,
        parent: Union[tk.Widget, Union[tk.Tk, tk.Toplevel]],
        width: int = None,
        height: int = None,
        wrapping: str = TextWrap.WordWrapping,
    ):
        """
        Initiate a tk.Text.

        :param parent: The parent of the text.
        :param width: The width of the text. Defaults to None.
        :param height: The width of the text. Defaults to None.
        :param wrapping: How to wrap words in the text. Defaults to
         TextWrap.WordWrapping
        """
        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))})"
            )
        if not isinstance(width, int) and width is not None:
            raise TypeError(
                f"width is not a int! (type passed in: {repr(type(width))})"
            )
        if not isinstance(height, int) and height is not None:
            raise TypeError(
                f"height is not a int! (type passed in: {repr(type(height))})"
            )
        if not isinstance(wrapping, str):
            raise TypeError(
                f"wrapping is not a str! " f"(type passed in: {repr(type(wrapping))})"
            )
        super().__init__(master=parent, width=width, height=height, wrap=wrapping)
        self._enabled = True
        self._readonly = False
        if on_aqua(self):
            self.bind("<2>", lambda event: self._popup(event=event))
            self.bind("<Control-1>", lambda event: self._popup(event=event))
        else:
            self.bind("<3>", lambda event: self._popup(event=event))
        self._make_context_menu()
        # https://stackoverflow.com/a/40618152/10291933
        self._orig = self._w + "_orig"
        self.tk.call("rename", self._w, self._orig)
        self.tk.createcommand(self._w, self._proxy)

    def _proxy(self, command, *args):
        cmd = (self._orig, command) + args
        result = self.tk.call(cmd)
        if command in ("insert", "delete", "replace"):
            self.event_generate("<<TextModified>>")
        return result

    @property
    def text(self) -> str:
        """
        Get the text in this text.

        :return: A str of the text.
        """
        return self.get("1.0", tk.END)

    @text.setter
    def text(self, new_text: str) -> None:
        """
        Set the text on this entry.

        :param new_text: The new text.
        :return: None.
        """
        if not isinstance(new_text, str):
            raise TypeError(
                f"new_text is not a str! " f"(type passed in: {repr(type(new_text))})"
            )
        self.delete("1.0", tk.END)
        self.insert("1.0", new_text)

    @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._readonly = False
        self.configure(state=tk.NORMAL if self._enabled else tk.DISABLED)

    def _make_context_menu(self) -> None:
        """
        Initiate the context menu.

        :return: None.
        """
        self._context_menu = tk.Menu(self, tearoff=0)
        self._context_menu.add_command(
            label="Copy",
            command=self.copy_contents,
            underline=0,
            accelerator="Command-C" if on_aqua(self) else "Control+C",
        )
        self._context_menu.add_command(
            label="Cut",
            command=self.cut_contents,
            accelerator="Command-X" if on_aqua(self) else "Control+X",
        )
        self._context_menu.add_command(
            label="Paste",
            command=self.paste_contents,
            underline=0,
            accelerator="Command-V" if on_aqua(self) else "Control+V",
        )
        self._context_menu.add_separator()
        self._context_menu.add_command(
            label="Delete", command=self.delete_contents, accelerator="Delete"
        )
        self._context_menu.add_separator()
        self._context_menu.add_command(
            label="Select all",
            command=self.select_all_contents,
            underline=7,
            accelerator="Command-A" if on_aqua(self) else "Control+A",
        )

    def _update_context_menu_states(self) -> None:
        """
        Update the context menu states, like whether to allow copying or not.

        :return: None.
        """
        if not self.enabled:
            self._context_menu.entryconfigure("Copy", state=tk.DISABLED)
            self._context_menu.entryconfigure("Cut", state=tk.DISABLED)
            self._context_menu.entryconfigure("Paste", state=tk.DISABLED)
            self._context_menu.entryconfigure("Delete", state=tk.DISABLED)
            self._context_menu.entryconfigure("Select all", state=tk.DISABLED)
            return
        if self.tag_ranges(tk.SEL):
            self._context_menu.entryconfigure("Copy", state=tk.NORMAL)
            self._context_menu.entryconfigure("Cut", state=tk.NORMAL)
            self._context_menu.entryconfigure("Paste", state=tk.NORMAL)
            self._context_menu.entryconfigure("Delete", state=tk.NORMAL)
            self._context_menu.entryconfigure("Select all", state=tk.DISABLED)
        else:
            self._context_menu.entryconfigure("Copy", state=tk.DISABLED)
            self._context_menu.entryconfigure("Cut", state=tk.DISABLED)
            self._context_menu.entryconfigure("Paste", state=tk.NORMAL)
            self._context_menu.entryconfigure("Delete", state=tk.DISABLED)
            self._context_menu.entryconfigure("Select all", state=tk.NORMAL)

    def _popup(self, event) -> None:
        """
        Try to pop up the context menu.

        :param event: An object that Tk passes in with information about the
         event that we need.
        :return: None.
        """
        self._update_context_menu_states()
        if self.enabled:
            try:
                self._context_menu.tk_popup(event.x_root, event.y_root, 0)
            finally:
                self._context_menu.grab_release()

    def select_all_contents(self) -> None:
        """
        Select everything.

        :return: None.
        """
        self.tag_add(tk.SEL, "1.0", tk.END)
        self.mark_set(tk.INSERT, "1.0")
        self.see(tk.INSERT)

    def delete_contents(self) -> None:
        """
        Delete the highlighted things.

        :return: None.
        """
        if self.tag_ranges(tk.SEL):
            self.delete(tk.SEL_FIRST, tk.SEL_LAST)

    def paste_contents(self) -> None:
        """
        Paste into the entry.

        :return: None.
        """
        self.delete_contents()
        self.insert(self.index(tk.INSERT), self.clipboard_get())

    def cut_contents(self) -> None:
        """
        Cut the highlighted contents.

        :return: None.
        """
        if self.tag_ranges(tk.SEL):
            self.clipboard_clear()
            self.clipboard_append(self.selection_get())
            self.update()
            self.delete_contents()

    def copy_contents(self) -> None:
        """
        Copy the highlighted contents.

        :return: None.
        """
        if self.tag_ranges(tk.SEL):
            self.clipboard_clear()
            self.clipboard_append(self.selection_get())
            self.update()

Ancestors

  • tkinter.Text
  • tkinter.Widget
  • tkinter.BaseWidget
  • tkinter.Misc
  • tkinter.Pack
  • tkinter.Place
  • tkinter.Grid
  • tkinter.XView
  • tkinter.YView

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 text : str

Get the text in this text.

:return: A str of the text.

Expand source code
@property
def text(self) -> str:
    """
    Get the text in this text.

    :return: A str of the text.
    """
    return self.get("1.0", tk.END)

Methods

def copy_contents(self) ‑> NoneType

Copy the highlighted contents.

:return: None.

Expand source code
def copy_contents(self) -> None:
    """
    Copy the highlighted contents.

    :return: None.
    """
    if self.tag_ranges(tk.SEL):
        self.clipboard_clear()
        self.clipboard_append(self.selection_get())
        self.update()
def cut_contents(self) ‑> NoneType

Cut the highlighted contents.

:return: None.

Expand source code
def cut_contents(self) -> None:
    """
    Cut the highlighted contents.

    :return: None.
    """
    if self.tag_ranges(tk.SEL):
        self.clipboard_clear()
        self.clipboard_append(self.selection_get())
        self.update()
        self.delete_contents()
def delete_contents(self) ‑> NoneType

Delete the highlighted things.

:return: None.

Expand source code
def delete_contents(self) -> None:
    """
    Delete the highlighted things.

    :return: None.
    """
    if self.tag_ranges(tk.SEL):
        self.delete(tk.SEL_FIRST, tk.SEL_LAST)
def paste_contents(self) ‑> NoneType

Paste into the entry.

:return: None.

Expand source code
def paste_contents(self) -> None:
    """
    Paste into the entry.

    :return: None.
    """
    self.delete_contents()
    self.insert(self.index(tk.INSERT), self.clipboard_get())
def select_all_contents(self) ‑> NoneType

Select everything.

:return: None.

Expand source code
def select_all_contents(self) -> None:
    """
    Select everything.

    :return: None.
    """
    self.tag_add(tk.SEL, "1.0", tk.END)
    self.mark_set(tk.INSERT, "1.0")
    self.see(tk.INSERT)
class TextWrap

The ways a tk.Text can wrap. NoWrapping - no wrapping. CharWrapping - wrap at any character and can br eak randomly. WordWrapping - wrap at word spaces.

Expand source code
class TextWrap:
    """
    The ways a tk.Text can wrap.
    NoWrapping - no wrapping.
    CharWrapping - wrap at any character and can br
     eak randomly.
    WordWrapping - wrap at word
     spaces.
    """

    NoWrapping = tk.NONE
    CharWrapping = tk.CHAR
    WordWrapping = tk.WORD

Class variables

var CharWrapping
var NoWrapping
var WordWrapping