How to make a button using the tkinter Canvas widget?

I want to get a button from the canvas. I tried pack canvas in a button widget, but that didn't work. Looks like I found (here: How do you create a button on the tkinter canvas? ) That the Canvas create_window method can help. But there must be something wrong with how I use it.

 import Tkinter DIM = 100 root = Tkinter.Tk() frame = Tkinter.Frame(root) button = Tkinter.Button(None, width=DIM, height=DIM, command=root.quit) circle = Tkinter.Canvas(frame, width=DIM, height=DIM) circle.create_oval(5, 5, DIM-5, DIM-5, fill="red") circle.create_window(0, 0, window=button) frame.grid() circle.grid(row=1, column=1) root.mainloop() 

If you erase the create_window line, I can put my picture in, but I cannot (obviously) click on it. But in this way, the button widget covers my circle and shows a sad blank button.

Basically, I want to create a button with a red circle drawn inside.

+6
source share
2 answers

Tkinter does not allow you to directly draw widgets other than canvas, and canvas drawings will always be below the built-in widgets.

A simple solution is to create a button effect using only the canvas. There is nothing special about this: just create a canvas, then add bindings for ButtonPress and ButtonRelease to simulate the button you clicked.

Here is a rough idea:

 class CustomButton(tk.Canvas): def __init__(self, parent, width, height, color, command=None): tk.Canvas.__init__(self, parent, borderwidth=1, relief="raised", highlightthickness=0) self.command = command padding = 4 id = self.create_oval((padding,padding, width+padding, height+padding), outline=color, fill=color) (x0,y0,x1,y1) = self.bbox("all") width = (x1-x0) + padding height = (y1-y0) + padding self.configure(width=width, height=height) self.bind("<ButtonPress-1>", self._on_press) self.bind("<ButtonRelease-1>", self._on_release) def _on_press(self, event): self.configure(relief="sunken") def _on_release(self, event): self.configure(relief="raised") if self.command is not None: self.command() 

To complete the illusion, you want to set the binding to <Enter> and <Leave> (to simulate an active state), and also make sure that the cursor is above the button on the release button - note how real buttons do nothing if you release the mouse before release.

+10
source

What you can do is snap the canvas to the mouse:

 import Tkinter DIM = 100 root = Tkinter.Tk() frame = Tkinter.Frame(root) circle = Tkinter.Canvas(frame) circle.create_oval(5, 5, DIM-5, DIM-5, fill="red") frame.grid() circle.grid(row=1, column=1) ################################## def click(event): root.quit() circle.bind("<Button-1>", click) ################################## root.mainloop() 

Now, if the user clicks inside the canvas, the click function will be called (essentially, the canvas is now made with a button).

Note that this click function will be called if the user clicks anywhere on the canvas. If you want to make click only called when the user clicks the circle, you can use event.x and event.y to hold the x and y coordinates of the click. After that, you can perform a calculation to determine if these coordinates are within the circle. Here is a link to this.

+1
source

Source: https://habr.com/ru/post/955937/


All Articles