是否可以将 canvas 作为按钮的图标?

Is it possible to put a canvas as the icon of a button?

我在 Tkinter 中绘制了漂亮的多边形 canvas。我想把它作为 Tkinter 按钮的图标。

我在 this 中看到了如何在 canvas 上放置一个按钮,但这会掩盖多边形。当然,如果我将多边形放在按钮上,则无法访问该按钮。

我尽量避免使用外部图像。我想保持代码独立,而不是依赖于图像的路径。如果我们移动代码,事情就会崩溃。

from Tkinter import *

class Example(Frame):
    def __init__(self, master=None):
        Frame.__init__(self, master)
        self.widget()

    def Xshape (self,canvas,x,y,p,t,outline='black',fill='green',width=1):

        points =  []
        s = t - p
        for i in (1,-1):
            points.extend(( x,         y + (i*p) ))
            points.extend(( x + (i*s), y + (i*t) ))
            points.extend(( x + (i*t), y + (i*s) ))
            points.extend(( x + (i*p), y))
            points.extend(( x + (i*t), y - (i*s)  ))
            points.extend(( x + (i*s), y - (i*t)  ))

        canvas.create_polygon(points,outline=outline,
                              fill=fill,width=width)

    def widget(self):

        cWidth=64.
        cHeight=64.
        self.canv = Canvas(frame,width=cWidth,height=cHeight)
        self.Xshape(self.canv, (cWidth+2)/2,(cHeight+2)/2, cHeight/5,cHeight/2)
        self.toggle = Button(frame,relief=FLAT,text='test')
        self.win = self.canv.create_window(cWidth/2,cHeight/2,anchor=CENTER,window=self.toggle)  
        self.canv.grid(row=0,column=2)


root = Tk()
root.geometry('100x100+10+50')
root.wm_title("Telescope Health Status")
root.grid_rowconfigure( 1, weight=1)
root.grid_columnconfigure( 0, weight=1)

frame = Frame(root,bg='light blue',padx=30)
frame.grid(row=0, column=0, columnspan=20, sticky='ew')

app = Example(root)
app.mainloop()

这只会在多边形上放置一个按钮。我想把多边形放在按钮里面。

您可以通过在 Enter、Leave 和鼠标事件上使用绑定,使 canvas 本身模拟按钮的行为,而不是将 canvas 放在按钮中:

  • Canvas浮雕设置为"raised",边框宽度为 1,使其看起来像一个按钮

  • 当光标进入Canvas

  • 时背景颜色变为浅灰色
  • 按下鼠标按钮1时浮雕设置为"sunken"

  • 参数中给出的命令在释放按钮 1 时执行,但前提是光标仍在 Canvas 上并且浮雕返回 "raised"

  • 当光标离开 Canvas

    时浮雕设置回 "raised" 并且恢复正常背景颜色
    from Tkinter import *
    
    class ButtonCanvas(Canvas):
        def __init__(self, master=None, command=lambda: None, **kw):
            Canvas.__init__(self, master, relief="raised", bd=1, **kw)
            self._bg = self.cget("bg")
            cWidth = 64
            cHeight = 64
            self.configure(width=64, height=64)
            self.Xshape((cWidth+2)/2,(cHeight+2)/2, cHeight/5,cHeight/2)
            self.command = command
    
            self.bind("<Enter>", self.on_enter)
            self.bind("<Leave>", self.on_leave)
            self.bind("<ButtonPress-1>", self.on_b1press)
            self.bind("<ButtonRelease-1>", self.on_b1release)
    
        def on_enter(self, event):
            self.configure(background="#ececec")
    
        def on_leave(self, event):
            self.configure(background=self._bg)
            self.configure(relief="raised")
    
        def on_b1press(self, event):
            self.configure(relief="sunken")
    
        def on_b1release(self, event):
            self.configure(relief="raised")
            if self.winfo_containing(event.x_root, event.y_root) == self:
                self.command()
    
        def Xshape (self,x,y,p,t,outline='black',fill='green',width=1):
    
            points =  []
            s = t - p
            for i in (1,-1):
                points.extend(( x,         y + (i*p) ))
                points.extend(( x + (i*s), y + (i*t) ))
                points.extend(( x + (i*t), y + (i*s) ))
                points.extend(( x + (i*p), y))
                points.extend(( x + (i*t), y - (i*s)  ))
                points.extend(( x + (i*s), y - (i*t)  ))
    
            self.create_polygon(points,outline=outline,
                                fill=fill,width=width)
    
    
    root = Tk()
    
    def cmd():
        print("ok")
    
    ButtonCanvas(root, command=cmd).pack()
    Button(root, command=cmd).pack()
    
    root.mainloop()