在 tkinter 中,有没有办法更改重叠画布的绘制堆栈顺序?

编程入门 行业动态 更新时间:2024-10-28 13:13:34
本文介绍了在 tkinter 中,有没有办法更改重叠画布的绘制堆栈顺序?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

限时送ChatGPT账号..

使用 Python 的 tkinter,我尝试通过扩展 画布小部件.当用户与它们交互时,如何更改将哪些自定义画布小部件绘制在顶部?

Using Python's tkinter, I'm trying to create custom buttons and other widgets by extending the Canvas widget. How can I change which custom canvas widgets get drawn on top as the user interacts with them?

lift() 适用于常规 tkinter 按钮和其他小部件,但是当我尝试使用它来提升 Canvas 时会引发错误,因为 Canvas 有自己的lift() 方法.Canvas 的lift() 已被Canvas 弃用,而支持tag_raise().但是,tag_raise() 文档说它没有使用窗口项目",这符合我的经验,并指导我改用lift().我的大脑一直在追逐这个看似循环的文档,直到它引发了自己的 StackOverflow 异常,这让我来问你.

lift() works for regular tkinter Buttons and other widgets, but raises an error when I try to use it to lift a Canvas, because Canvas has its own lift() method. Canvas's lift() is deprecated for Canvas in favor of tag_raise(). However, tag_raise() documentation says it "doesn’t work with window items", which fits my experience, and directs me to use lift() instead. My brain chased this seemingly circular documentation until it raised its own kind of StackOverflow exception, which brings me to ask you.

这是一些运行并说明我的问题的基本代码.我已经包含了 button3,一个可以按预期提升 () 的常规按钮.但是,如果我单击 custom_button1,则 click_handler 会引发异常.

Here's some basic code that runs and illustrates my problem. I've included button3, a regular button that can lift() as expected. If I click on custom_button1, however, the click_handler raises an exception.

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,引发的异常是:

This works for as desired for button3, but for custom_button1, the exception that is raised is:

_tkinter.TclError: wrong # args: should be ".!example.!canvas.!mycustombutton2 raise tagOrId ?aboveThis?"

在 Canvas.lift() 和 Canvas.tag_raise() 通常用于通过标签或 id 影响画布上的项目而不是画布本身的上下文中,该异常是有意义的.我只是不知道如何更改画布本身的堆栈顺序,以便我可以将其用作自定义小部件.

That exception makes sense in the context that Canvas.lift() and Canvas.tag_raise() are normally used to affect an item on the canvas by tag or id, not the canvas itself. I just don't know what to do about changing the stack order of the canvas itself so I can use it as a custom widget.

我可以在画布上管理一堆自定义小部件,只需要一个画布来处理所有绘图和所有鼠标事件所有小部件.我仍然可以拥有小部件的类,但不是从 Canvas 继承,而是接受 Canvas 参数.所以添加看起来类似于下面的代码,我必须编写类似的代码来提升、移动、确定点击事件是否应用于此按钮、更改活动状态等.

I could manage a bunch of custom widgets on a canvas by only having one canvas that handles all drawing and all the mouse events for all the widgets. I could still have classes for the widgets, but instead of inheriting from Canvas, they'd accept Canvas parameters. So adding would look something like the code below, and I'd have to write similar code for lifting, moving, determining if a click event applied to this button, changing active state, and so forth.

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() 文档你不能画小部件顶部的其他画布项目."在此变通方法中,所有自定义按钮都是画布项目,因此如果我正确阅读本文,则无法绘制在其他小部件之上.)更不用说实现所需的额外代码.也就是说,我目前对如何实现这一点没有更好的想法.

This work-around seems to go against established coding paradigms in tkinter, though. Furthermore, I believe this approach would prevent me from drawing these custom buttons above other window objects. (According to the create_window() documentation "You cannot draw other canvas items on top of a widget." In this work-around, all the custom buttons would be canvas items, and so if I'm reading this correctly, couldn't be drawn on top of other widgets.) Not to mention the extra code it would take to implement. That said, I don't currently have a better idea of how to implement this.

预先感谢您的帮助!

推荐答案

不幸的是,您偶然发现了 tkinter 实现中的错误.您可以通过多种方式解决此问题.您可以创建一个方法来执行 tkinter lift 方法所做的事情,也可以直接调用 tkinter Misc 类中的方法.

Unfortunately you've stumbled on a bug in the tkinter implementation. You can work around this in a couple of ways. You can create a method that does what the tkinter lift method does, or you can directly call the method in the tkinter Misc class.

由于您正在创建自己的类,因此您可以覆盖 lift 方法以使用其中任何一种方法.

Since you are creating your own class, you can override the lift method to use either of these methods.

以下是使用现有函数的方法.确保从 tkinter 导入 Misc:

Here's how you do it using the existing function. Be sure to import Misc from tkinter:

from tkinter import Misc
...
class MyCustomButton(Canvas):
    ...
    def lift(self, aboveThis=None):
        Misc.tkraise(self)

以下是直接调用底层 tk 解释器的方法:

Here's how you directly call the underlying tk interpreter:

class MyCustomButton(Canvas):
    ...
    def lift(self, aboveThis=None):
        self.tk.call('raise', self._w, aboveThis)

这样,您可以通过调用 lift 方法将一个按钮抬高到另一个按钮上:

With that, you can raise one button over the other by calling the lift method:

def click_handler(self,event):
    event.widget.lift()

这篇关于在 tkinter 中,有没有办法更改重叠画布的绘制堆栈顺序?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

更多推荐

[db:关键词]

本文发布于:2023-04-30 06:54:50,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1390549.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:堆栈   画布   没有办法   顺序   tkinter

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!