问题
使用 Python 的 tkinter,我尝试通过扩展来创建自定义按钮和其他小部件画布小部件 http://effbot.org/tkinterbook/canvas.htm#when-to-use。当用户与它们交互时,如何更改在顶部绘制哪些自定义画布小部件?
lift() https://effbot.org/tkinterbook/widget.htm#Tkinter.Widget.lift-method适用于常规 tkinter 按钮和其他小部件,但当我尝试使用它来抬起画布时会引发错误,因为Canvas 有自己的 lift() 方法 http://effbot.org/tkinterbook/canvas.htm#Tkinter.Canvas.lift-method。 Canvas 的 lift() 已被弃用,转而使用 tag_raise()。然而,tag_raise() http://effbot.org/tkinterbook/canvas.htm#Tkinter.Canvas.tag_raise-method文档说它“不适用于窗口项目”,这符合我的经验,并指示我改用 lift() 。我的大脑一直在追踪这个看似循环的文档,直到它引发了自己的 StackOverflow 异常,这让我不得不问你。
代码说明
这是一些运行并说明我的问题的基本代码。我已经添加了button3,一个可以按预期 lift() 的常规按钮。但是,如果我单击 custom_button1,click_handler 会引发异常。
from tkinter import Button, Canvas, Frame, Tk
from tkinter.constants import NW
class Example(Frame):
def __init__(self, root):
Frame.__init__(self, root)
self.canvas = Canvas(self, width=200, height=200, background="black")
self.canvas.grid(row=0, column=0, sticky="nsew")
self.button3 = Button(self.canvas, text="button3")
self.custom_button1 = MyCustomButton(self.canvas)
self.custom_button2 = MyCustomButton(self.canvas)
self.canvas.create_window(20, 20, anchor=NW, window=self.button3)
self.canvas.create_window(40, 40, anchor=NW, window=self.custom_button1)
self.canvas.create_window(34, 34, anchor=NW, window=self.custom_button2)
self.button3.bind("<Button-1>", self.click_handler)
self.custom_button1.bind("<Button-1>", self.click_handler)
self.custom_button2.bind("<Button-1>", self.click_handler)
def click_handler(self,event):
event.widget.lift() #raises exception if event.widget is a MyCustomButton
#note that Canvas.lift() is deprecated, but documentation
#says Canvas.tag_raise() doesn't work with window items
class MyCustomButton(Canvas):
def __init__(self, master):
super().__init__(master, width=40, height=25, background='blue')
if __name__ == "__main__":
root = Tk()
Example(root).pack(fill="both", expand=True)
root.mainloop()
这适用于button3,但对于custom_button1,引发的异常是:
_tkinter.TclError: wrong # args: should be ".!example.!canvas.!mycustombutton2 raise tagOrId ?aboveThis?"
在 Canvas.lift() 和 Canvas.tag_raise() 通常用于通过标签或 id 影响画布上的项目(而不是画布本身)的上下文中,该异常是有意义的。我只是不知道如何更改画布本身的堆栈顺序,以便我可以将其用作自定义小部件。
我考虑过的解决方法
我只需在画布上管理一堆自定义小部件one处理的画布all绘图和all鼠标事件all小部件。我仍然可以拥有小部件的类,但它们不是从 Canvas 继承,而是接受 Canvas 参数。因此,添加看起来类似于下面的代码,我必须编写类似的代码来提升、移动、确定单击事件是否应用于此按钮、更改活动状态等等。
def add_to_canvas(self, canvas, offset_x=0, offset_y=0):
self.button_border = canvas.create_rectangle(
offset_x + 0, offset_y + 0,
offset_x + 40, offset_y + 25
)
#create additional button features
不过,这种解决方法似乎违背了 tkinter 中既定的编码范例。此外,我相信这种方法会阻止我在其他窗口对象之上绘制这些自定义按钮。 (根据create_window() 文档 http://effbot.org/tkinterbook/canvas.htm#Tkinter.Canvas.create_window-method“您不能在小部件之上绘制其他画布项目。”在此解决方法中,所有自定义按钮都将是画布项,因此如果我正确阅读此内容,则无法在其他小部件之上绘制。)更不用说实现时需要的额外代码了。也就是说,我目前不知道如何实现这一点。
预先感谢您的帮助!