Subclassing Tkinter to create a custom widget

I am trying to create a text widget with a vertical scrollbar, while retaining all the methods / functions from Tkinter.Text .

So far I have the following code:

 class ScrollableTextWidget(Tkinter.Text): def __init__(self, parent): self.parent = parent self.Frame = ttk.Frame(self.parent) Tkinter.Text.__init__(self, self.Frame, width=1, height=1) self.__initWidget() def __initWidget(self): self.Frame.grid(sticky="NSEW") self.ScrollbarY = ttk.Scrollbar(self.Frame, orient="vertical", command=self.yview) self.configure(yscrollcommand=self.ScrollbarY.set) self.grid(column=0, row=0, sticky="NSEW") self.ScrollbarY.grid(column=1, row=0, sticky="NS") self.Frame.columnconfigure(0, weight=1) self.Frame.rowconfigure(0, weight=1) 

Is it possible to create your own widget like this, or is it better to put it in a Tkinter frame and write your own methods?

+11
source share
2 answers

This is very normal for subclassing a widget to create a custom one. However, if this custom widget consists of more than one widget, you will usually be a subclass of Frame . For example, to create a widget that is a text widget with a scroll bar, I would do something like this:

 import Tkinter as tk class ScrolledText(tk.Frame): def __init__(self, parent, *args, **kwargs): tk.Frame.__init__(self, parent) self.text = tk.Text(self, *args, **kwargs) self.vsb = tk.Scrollbar(self, orient="vertical", command=self.text.yview) self.text.configure(yscrollcommand=self.vsb.set) self.vsb.pack(side="right", fill="y") self.text.pack(side="left", fill="both", expand=True) class Example(tk.Frame): def __init__(self, parent): tk.Frame.__init__(self, parent) self.scrolled_text = ScrolledText(self) self.scrolled_text.pack(side="top", fill="both", expand=True) with open(__file__, "r") as f: self.scrolled_text.text.insert("1.0", f.read()) root = tk.Tk() Example(root).pack(side="top", fill="both", expand=True) root.mainloop() 

With this approach, pay attention to how you need to reference the internal text widget when inserting text. If you want this widget to look more like a real text widget, you can create a mapping to some or all of the functions of the text widget. For instance:

 import Tkinter as tk class ScrolledText(tk.Frame): def __init__(self, parent, *args, **kwargs): tk.Frame.__init__(self, parent) self.text = tk.Text(self, *args, **kwargs) self.vsb = tk.Scrollbar(self, orient="vertical", command=self.text.yview) self.text.configure(yscrollcommand=self.vsb.set) self.vsb.pack(side="right", fill="y") self.text.pack(side="left", fill="both", expand=True) # expose some text methods as methods on this object self.insert = self.text.insert self.delete = self.text.delete self.mark_set = self.text.mark_set self.get = self.text.get self.index = self.text.index self.search = self.text.search class Example(tk.Frame): def __init__(self, parent): tk.Frame.__init__(self, parent) self.scrolled_text = ScrolledText(self) self.scrolled_text.pack(side="top", fill="both", expand=True) with open(__file__, "r") as f: self.scrolled_text.insert("1.0", f.read()) root = tk.Tk() Example(root).pack(side="top", fill="both", expand=True) root.mainloop() 
+24
source

I will use the subclass for a medium, large project or for a project with support in the future, because the subclass can easily replace or update. In any case, the costs of subclassification are small. But if your task is one-time, do it dirty and fast.

In this case, I would subclass from the frame, because it is the most general widget and there is no need to redefine pack , grid and other methods.

+2
source

Source: https://habr.com/ru/post/954916/


All Articles