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?
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.
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()
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With