Darkstar
Darkstar

Reputation: 79

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

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.

Upvotes: 0

Views: 754

Answers (1)

acw1668
acw1668

Reputation: 46692

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()

Upvotes: 3

Related Questions