Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Subclassing Tkinter.Text 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 OK to create my custom widget like this or should I rather put it in a Tkinter.frame and write my own methods?

like image 236
user2830098 Avatar asked Sep 30 '13 06:09

user2830098


People also ask

What is the difference between entry and text widget in Tkinter?

The Entry widget is used to accept single-line text strings from a user. If you want to display multiple lines of text that can be edited, then you should use the Text widget.


2 Answers

It's very normal to subclass a widget to create a custom one. However, if this custom widget is made up of more than one widget, you would normally subclass Frame. For example, to create a widget that is a text widget with a scrollbar 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, notice how you need to reference the inner 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 text widget functions. For example:

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()
like image 178
Bryan Oakley Avatar answered Oct 22 '22 06:10

Bryan Oakley


I would use subclass for middle, big project or for project with support in future because subclassing can easy to replace or update. In any case costs for subclassing is small. But if your task is disposable do it dirty and quick.

In this case I would subclassing from Frame because it most general widget and not need override pack, grid and others methods.

like image 23
Michael Kazarian Avatar answered Oct 22 '22 06:10

Michael Kazarian