Search code examples
pythontkintertkinter-canvastkinter-entry

Python/tkinter: Adding an Entry widget hides my canvas items


For a game I'm making, I need the user to input data, and I want to call a method that adds a little Entry box to my GUI (to get the user's name), but when I try to do so the Entry widget basically masks all other things and makes them disappear. Any ideas on why this happens or how to fix? Here's an example of the problematic code:

root = tkinter.Tk()
root.title('2048')
width = 500
height = 800
root.geometry('%sx%s' % (width, height))
canvas = tkinter.Canvas(root, width=width, height=height, highlightthickness=0)
canvas.pack()
r = canvas.create_rectangle(0, 0, 50, 50)
canvas.move(r, 50, 50)


def keyed(event):
    e = tkinter.Entry(canvas)
    e.pack()


canvas.bind('<Key>', keyed)
canvas.focus_set()
root.mainloop()

Solution

  • This is the standard behavior when you use pack or grid - widgets will grow or shrink to fit their contents. when you pack an entry in the canvas, the canvas will shrink or grow to fit the canvas. This is called geometry propagation.

    There are at least three ways to solve this. The first is to not put the widget inside the canvas. Instead, put it above, below, or to one side (eg: e = tkinter.Entry(root))

    Another solution is to not use pack (or grid). Instead, use the canvas create_window method to make the entry widget a first class canvas object. You will have to decide where to put it since the create_window method requires an x/y coordinate.

    A third option is to contiue to use pack but turn geometry propagation off. Personally I think this feature should almost never be used. The fact that widgets grow or shrink is a feature rather than a bug, and it's a feature that makes it easier to create responsive user interfaces.

    To turn geometry propagation off for the canvas you can call canvas.pack_propagate(False) if you continue to use pack, or canvas.grid_propagate(False) if you switch to using grid inside the canvas.