Home > front end >  How to dynamically wrap label text in tkinter with .bind and <Configure>
How to dynamically wrap label text in tkinter with .bind and <Configure>

Time:12-30

I'm trying to create a page that outputs a large amount of data, and wraps the text dynamically depending on window size. I started by setting wraplength = self.master.winfo_width(), which sets the text wrapping to the current window size, but it does not change when the window does. I found this answer, which seemed like it would solve the problem, but when trying to recreate it myself, something went wrong. I suspect that I'm misunderstanding something with .bind or <Configure>, but I can't be sure. My base code is as follows:

from tkinter import *

class Wrap_example(Frame):
    def __init__(self):
        Frame.__init__(self)
        self.place(relx=0.5, anchor='n')
#Initalize list and variable that populates it  
        self.data_list = []
        self.data = 0
#Button and function for creating a bunch of numbers to fill the space
        self.button = Button(self, text = "Go", command = self.go)
        self.button.grid()
    def go(self):
        for self.data in range(1, 20000, 100):
            self.data_list.append(self.data)
#Label that holds the data, text = list, wraplength = current window width       
        self.data = Label(self, text = self.data_list, wraplength = self.master.winfo_width(), font = 'arial 30')
        self.data.grid()
#Ostensibly sets the label to dynamically change wraplength to match new window size when window size changes
        self.data.bind('<Configure>', self.rewrap())
    def rewrap(self):
        self.data.config(wraplength = self.master.winfo_width())
        
frame01 = Wrap_example()
frame01.mainloop()

A few things of note: I tried using the lambda directly as shown in the linked answer, but it didn't work. If I remove the rewrap function and use self.data.bind('<Configure>', lambda e: self.data.config(wraplength=self.winfo_width()), it throws a generic Syntax error, always targeting the first character after that line, (the d in def if the function is left in, the f in frame01 if it's commented out). Leaving rewrap as-is doesn't throw an error, but it doesn't perform any other apparent function, either. Clicking 'Go' will always spawn data that wraps at the current window size, and never changes.

CodePudding user response:

There are few issues:

  • frame Wrap_example does not fill all the horizontal space when window is resized
  • label self.data does not fill all the horizontal space inside frame Wrap_example when the frame is resized
  • self.rewrap() will be executed immediately when executing the line self.data.bind('<Configure>', self.rewrap())

To fix the above issues:

  • set relwidth=1 in self.place(...)
  • call self.columnconfigure(0, weight=1)
  • use self.data.bind('<Configure>', self.rewrap) (without () after rewrap) and add event argument in rewrap()
from tkinter import *

class Wrap_example(Frame):
    def __init__(self):
        Frame.__init__(self)
        self.place(relx=0.5, anchor='n', relwidth=1)  ### add relwidth=1
        self.columnconfigure(0, weight=1) ### make column 0 use all available horizontal space
#Initalize list and variable that populates it
        self.data_list = []
        self.data = 0
#Button and function for creating a bunch of numbers to fill the space
        self.button = Button(self, text = "Go", command = self.go)
        self.button.grid()
    def go(self):
        for self.data in range(1, 20000, 100):
            self.data_list.append(self.data)
#Label that holds the data, text = list, wraplength = current window width
        self.data = Label(self, text = self.data_list, wraplength = self.master.winfo_width(), font = 'arial 30')
        self.data.grid()
#Ostensibly sets the label to dynamically change wraplength to match new window size when window size changes
        self.data.bind('<Configure>', self.rewrap) ### remove () after rewrap
    def rewrap(self, event): ### add event argument
        self.data.config(wraplength = self.master.winfo_width())

frame01 = Wrap_example()
frame01.mainloop()
  • Related