15

I created a Frame and then a Canvas.
What I want to do next is to add a Button on the Canvas.
However, when I packed the Button I cannot see the Canvas!

Here is what I tried:

from Tkinter import Tk, Canvas, Frame, Button from Tkinter import BOTH, W, NW, SUNKEN, TOP, X, FLAT, LEFT class Example(Frame): def __init__(self, parent): Frame.__init__(self, parent) self.parent = parent self.initUI() def initUI(self): self.parent.title("Layout Test") self.config(bg = '#F0F0F0') self.pack(fill = BOTH, expand = 1) #create canvas canvas1 = Canvas(self, relief = FLAT, background = "#D2D2D2", width = 180, height = 500) canvas1.pack(side = TOP, anchor = NW, padx = 10, pady = 10) #add quit button button1 = Button(canvas1, text = "Quit", command = self.quit, anchor = W) button1.configure(width = 10, activebackground = "#33B5E5", relief = FLAT) button1.pack(side = TOP) def main(): root = Tk() root.geometry('800x600+10+50') app = Example(root) app.mainloop() if __name__ == '__main__': main() 

3 Answers 3

20

The Tkinter pack manager tries to resize the parent widget to the correct size to contain its child widgets, and no larger, by default. So the canvas is there - but it's precisely the same size as the button, and thus invisible.

If you want to place a widget on a canvas without causing the canvas to dynamically resize, you want the Canvas.create_window() function:

# ... snip ... button1 = Button(self, text = "Quit", command = self.quit, anchor = W) button1.configure(width = 10, activebackground = "#33B5E5", relief = FLAT) button1_window = canvas1.create_window(10, 10, anchor=NW, window=button1) 

This will create your button with upper-left corner at (10, 10) relative to the canvas, without resizing the canvas itself.

Note that you could replace the window argument with a reference to any other Tkinter widget. One caveat, though: the named widget must be a child of the top-level window that contains the canvas, or a child of some widget located in the same top-level window.

Sign up to request clarification or add additional context in comments.

Comments

3

you can use button1.place(x=0,y=0) geometry manager instead of pack(side =TOP) pack resize the master widget to makes it large enough to hold the child widget

http://effbot.org/tkinterbook/pack.htm#Tkinter.Pack.pack_propagate-method

http://effbot.org/tkinterbook/place.htm

Comments

3

I had the exact same problem. There isn't an official way that I know, but here's a way around it:

from Tkinter import * root = Tk() def clicked(event): print("pressed") canvas1 = Canvas(root, relief = FLAT, background = "#D2D2D2") canvas1.pack() buttonBG = canvas1.create_rectangle(0, 0, 100, 30, fill="grey40", outline="grey60") buttonTXT = canvas1.create_text(50, 15, text="click") canvas1.tag_bind(buttonBG, "<Button-1>", clicked) ## when the square is clicked runs function "clicked". canvas1.tag_bind(buttonTXT, "<Button-1>", clicked) ## same, but for the text. root.mainloop() 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.