Как сделать кнопку с помощью виджета Tkinter Canvas?

Я хочу получить кнопку из холста. Я пытался pack холст в виджете кнопки, но это не сработало. Немного погуглив, я нашел (здесь: как вы создаете кнопку на холсте tkinter?), что метод Canvas create_window может помочь. Но должно быть что-то не так в том, как я его использую.

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

если я сотру create_window line, я могу видеть свою картину, но я не могу (очевидно) нажать на нее. Но таким образом, виджет кнопки покрывает мой круг и показывает грустную пустую кнопку.

в принципе, я хочу создать кнопку с красным кружком внутри расписана.

2 ответов


Tkinter не позволяет напрямую рисовать на виджетах, отличных от холста, а рисунки холста всегда будут ниже встроенных виджетов.

простое решение состоит в том, чтобы создать эффект кнопки, используя только холст. В этом нет ничего особенного: просто создайте холст, затем добавьте привязки для ButtonPress и ButtonRelease, чтобы имитировать нажатие кнопки.

вот примерная идея:

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

для завершения иллюзии вы будете хотите установить привязку на <Enter> и <Leave> (для имитации активного состояния), а также убедитесь, что курсор находится над кнопкой на кнопке release -- обратите внимание, как реальные кнопки ничего не делают, если вы переместите мышь, прежде чем отпустить.


что вы можете сделать, это связать полотно для мыши:

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

теперь, если пользователь щелкает внутри холста, функция click будет вызван (по сути, холст теперь сделан кнопкой).

обратите внимание, хотя эта функция click будет вызываться, если пользователь нажмет в любом месте в холст. Если вы хотите сделать это так, что click только вызывается, когда пользователь щелкает по кругу, вы можете использовать event.x и event.y, чтобы получить x и y координаты мыши. Как только они у вас есть, вы можете запустить расчет, чтобы определить, находятся ли эти координаты в пределах круга. здесь ссылка на это.