Reputation: 1878
I just want to start by saying that I am pretty new to coding with tkinter and Python. Hope you can help me out.
I am trying to create an application with a help section that is supposed to be opened as a Toplevel with tkinter when clicking a button. The Toplevel needs to be scrollable AND wrap the text as I resize the Toplevel window.
Below is a working code which gives me a good scrollable window but won't wrap the text. The Expl(300, 300) at the bottom is in the original setup called from another Python file which has a main tk.Tk()-window. Can anyone give me advice on how the wrap functionality works, and what I am doing wrong right now?
import tkinter as tk
WIDTH = 500
HEIGHT = 500
BG = '#fff'
class Expl(tk.Frame):
def __init__(self, x, y):
self.x = x
self.y = y
self.width = round(WIDTH/2)
self.height = round(HEIGHT/1.8)
self.window = tk.Toplevel()
self.window.wm_geometry('%dx%d+%d+%d' % (self.width, self.height, max(0, self.x - (WIDTH/2 - WIDTH/2/2)), max(0, self.y - (HEIGHT/2 - HEIGHT/1.8/2))))
self.window.title('Förklaringar')
self.window.configure(background=BG)
#self.window.iconbitmap(default=ICON_PATH)
tk.Frame.__init__(self, self.window)
myframe=tk.Frame(self.window, width=self.width, height=self.height, bd=1, background=BG)
myframe.place(x=10,y=10)
self.canvas = tk.Canvas(self.window, borderwidth=0, background=BG)
self.frame = tk.Frame(self.canvas, background=BG)
self.vsb = tk.Scrollbar(self.window, orient="vertical", command=self.canvas.yview)
self.canvas.configure(yscrollcommand=self.vsb.set)
self.canvas.bind_all("<MouseWheel>", self.onmousewheel)
self.frame.bind("<Configure>", self.myfunction)
self.frame.bind("<Configure>", self.onFrameConfigure)
self.vsb.pack(side="right", fill="y")
self.canvas.create_window((0,0),window=self.frame,anchor='nw')
self.canvas.pack(side="left", fill="both", expand=True)
self.window.grid_rowconfigure(0, weight=1)
self.window.grid_columnconfigure(0, weight=1)
self.draw()
def myfunction(self, event):
self.canvas.configure(scrollregion=self.canvas.bbox("all"))
def onmousewheel(self, event):
self.canvas.yview_scroll(int(-1*(event.delta/120)), "units")
def onFrameConfigure(self, event):
self.canvas.configure(scrollregion=self.canvas.bbox("all"))
def draw(self):
# Titles
tk.Label(self.frame, text='TEST 1').grid(row=0, column=0, sticky='SW', padx=10, pady=(5, 0))
tk.Label(self.frame, text='TEST 2').grid(row=1, column=0, sticky='SW', padx=10, pady=(5, 0))
tk.Label(self.frame, text='TEST 3').grid(row=2, column=0, sticky='SW', padx=10, pady=(5, 0))
texxt = WrappingLabel(self.frame, text="TESTTTTTT TTTTTTTT T IN RSG RSG SRG RSG")
texxt.grid(row=3, column=0, sticky='SW', padx=10, pady=(5, 0))
class WrappingLabel(tk.Label):
def __init__(self, master=None, **kwargs):
tk.Label.__init__(self, master, **kwargs)
self.bind('<Configure>', lambda _: self.config(wraplength=master.winfo_width()))
Expl(300, 300)
Upvotes: 2
Views: 562
Reputation: 15533
Comment: seems to be working with one line of text at least.
Assuming you use only class WrappingLabel
, you have to do it for ever .children
in the Frame
.
# self.texxt.on_configure(event)
w = self.frame
for c in w.children:
w.children[c].on_configure(event)
Comment: Only thing is that it is centering the 2nd line of text instead of left adjusting.
Change to:
class WrappingLabel(tk.Label):
def __init__(self, master=None, **kwargs):
tk.Label.__init__(self, master, justify='left', anchor='nw', **kwargs)
Question: wrap the text as I resize the Toplevel window.
You have to bind to the <Configure>
event of the Canvas
widget because this widget resizes in sync with Toplevel
.
on startup resized large resized small
Note: For demonstration:
self.frame = tk.Frame(..., bg='blue'
,Label(..., bg='yellow'
Note: Inherit from
tk.Toplevel
instead fromtk.Frame
.
You are using:class Expl(tk.Frame): def __init__(self, x, y): self.window = tk.Toplevel() tk.Frame.__init__(self, self.window)
if you are knowing, what you do, it's ok, but the default should read:
class Expl(tk.Toplevel): def __init__(self, parent, x, y): super().__init__(parent) self.title('Förklaringar')
Wrap the text as the
Toplevel
window gets resized:
class Expl(tk.Frame):
def __init__(self, x, y):
self.window = tk.Toplevel()
...
self.canvas = tk.Canvas(self.window, borderwidth=0, background=BG)
self.canvas.bind("<Configure>", self.on_canvas_configure)
def on_canvas_configure(self, event):
# Here goes other configure for Scrollbar
self.texxt.on_configure(event)
def draw(self):
...
self.texxt = WrappingLabel(self.frame,
text="TESTTTTTT TTTTTTTT T IN RSG RSG SRG RSG",
bg='yellow')
...
class WrappingLabel(tk.Label):
def __init__(self, master=None, **kwargs):
tk.Label.__init__(self, master, **kwargs)
# No bind here: self.bind('<Configure>'
def on_configure(self, event):
widget = event.widget
# Only on Canvas event set 'wraplength'
if isinstance(widget, tk.Canvas):
width = widget.winfo_width()
# print('on_configure({})'.format((event.widget, width)))
border = 4
scrollbar = 12
self.config(wraplength=width - (border + scrollbar))
Tested with Python: 3.5 - 'TclVersion': 8.6 'TkVersion': 8.6
Upvotes: 0