Custom object display (repr)#

The default way of displaying objects is as follows: ClassName(param1=..., param2=..., param3=..., ...). This printout / repr can b overridden with the use of tkclasswiz.convert.ObjectInfo.register_repr() method.

classmethod ObjectInfo.register_repr(class_: type, repr: Callable[[ObjectInfo], str], inherited: bool = False)

Registers a custom __repr__ (string representation of object) function. The function must as a single parameter accept the ObjectInfo instance being represented as a string.

Parameters:
  • class (type) – The class for which this custom repr is being register.

  • repr (Callable[[ObjectInfo], str]) – The function that will provide custom __repr__. As a parameter it accepts the ObjectInfo object. It returns a str (string).

  • inherited (bool) – Boolean flag. Setting it to True will register repr for inherited members as well. Defaults to False.

For example, let’s say I want to define some logical operators and want them to be displayed differently. The example shows how a custom repr display can be made. It may look a bit much, but the only thing that matters is the emphasized register_repr() method call. Inside the call, a lambda function is provided. The lambda accepts the ObjectInfo object and outputs a string. That string is made up of the name of a logical operator and the operants in the following format: <op1> <operator name> <op2> <operator name> <op3> .... If the operator’s name is or_op, it will be displayed as <op1> or <op2> or <op3> .... If the operator’s name is and_op, it will be displayed as <op1> and <op2> and <op3> ....

../_images/object_info_custom_repr.png
 1from typing import List
 2from abc import ABC, abstractmethod
 3
 4import tkinter as tk
 5import tkinter.ttk as ttk
 6import tkclasswiz as wiz
 7
 8class base_op(ABC):
 9    @abstractmethod
10    def evaluate(self):
11        pass
12
13class bool_op(base_op):
14    def __init__(self, operants: List["base_op"]) -> None:
15        self.operants = operants
16
17class and_op(bool_op):
18    def evaluate(self):
19        return all(op.evaluate() for op in self.operants)
20
21class or_op(bool_op):
22    def evaluate(self):
23        return any(op.evaluate() for op in self.operants)
24
25class contains(base_op):
26    def __init__(self, op: str) -> None:
27        pass
28
29    def evaluate(self):
30        # For demonstration purposes. Otherwise, we would usually check if op is contained within string
31        return True
32
33class MyLogicResult:
34    def __init__(self, expression: base_op) -> None:
35        self.expression = expression
36
37
38wiz.ObjectInfo.register_repr(
39    bool_op,
40    lambda oi: "(" +
41            f' {oi.class_.__name__.removesuffix("_op")} '
42            .join(map(repr, oi.data["operants"])) +
43            ")",
44    True
45)
46
47# Tkinter main window
48root = tk.Tk("Test")
49
50# Modified tkinter Combobox that will store actual objects instead of strings
51combo = wiz.ComboBoxObjects(root)
52combo.pack(fill=tk.X, padx=5)
53
54def define(old = None):
55    """
56    Function for opening a window either in new definition mode (old = None) or
57    edit mode (old != None)
58    """
59    assert old is None or isinstance(old, wiz.ObjectInfo)
60    window = wiz.ObjectEditWindow()
61    window.open_object_edit_frame(MyLogicResult, combo)
62
63# Main GUI structure
64ttk.Button(text="Open", command=define).pack()
65root.mainloop()