I have an entry form with (among other widgets) an Entry
widget to enter some value and a Listbox
to show the valid values entered so far. Below the Entry
widget I show a validation message (empty when value is valid or error description if not) along with a big symbol ('🗴'
for error and '🗸'
for valid).
The following is a minimal example to simulate valid and invalid entries by clicking the button:
import tkinter as tk
root = tk.Tk()
tk.Entry(root).grid(column=0, row=0, sticky=tk.N)
tk.Listbox(root, height=10).grid(column=1, row=0, rowspan=3, sticky=tk.N)
label = tk.Label(root)
label.grid(column=0, row=1, sticky=tk.N)
symbol = tk.Label(root, font='Arial 72 bold')
symbol.grid(column=0, row=2, sticky=tk.S)
def toggle():
n = 0 if len(label['text']) > 10 else 3
label['text'] = '\n'.join([f'error message line {i}' for i in range(n)])
symbol['text'] = '🗴' if n else '🗸'
tk.Button(root, text='toggle message', command=toggle).grid(column=0, row=3)
root.mainloop()
The symbol moves down when the error message becomes longer although there's still plenty of space between the bottom of the last error message line and the top of the 🗴 symbol. The reason is that the maximum character hight of the 72 pt font could use this extra space (can be easyly verified by inserting a full hight vertical line ︳
before the symbol.
Apart from decreasing the symbol font size (which I don't want) or increasing the total hight reserved for the message and the symbol (which I can't) I see the only workaround in replacing the character symbol by an image symbol where the strokes extend over the full image hight.
So my question is: how to keep the button in place when the message line hight changes? Is it possible to somehow overlap the symbol and the message (knowing that the symbol character strokes don't fill the full font hight). I tried negative paddings but tkinter does not allow that. I also want to stick with the grid
layout manager.
By making the second row resize to adapt to the window height and setting grid_propagate
to False, then the button stays in place:
import tkinter as tk
root = tk.Tk()
tk.Entry(root).grid(column=0, row=0, sticky=tk.N)
tk.Listbox(root, height=10).grid(column=1, row=0, rowspan=3, sticky=tk.N)
root.rowconfigure(2, weight=1) # make second row resize to fit window height
label = tk.Label(root)
label.grid(column=0, row=1, sticky=tk.N)
symbol = tk.Label(root, font='Arial 72 bold')
symbol.grid(column=0, row=2, sticky=tk.S)
def toggle():
n = 0 if len(label['text']) > 10 else 3
label['text'] = '\n'.join([f'error message line {i}' for i in range(n)])
symbol['text'] = '🗴' if n else '🗸'
tk.Button(root, text='toggle message', command=toggle).grid(column=0, row=3)
root.update_idletasks()
root.grid_propagate(False) # disable window resizing when its children change size
root.mainloop()
Note that if the error message is very long, the symbol will not be visible.