创建在使用Tkinter单击时切换Reliefs的按钮



我试图制作一类凸起按钮,在";凸起的";以及";沉没的";每次点击。

我设法找到了这篇关于如何创建一类自定义按钮的帖子。它自己制作自定义按钮效果很好:

class TypButton(Button):
def __init__(self, *args, **kwargs):
Button.__init__(self, *args, **kwargs)
self["relief"] = "raised"

然后我发现了这篇关于如何在按钮上切换Reliefs的帖子:

def toggle_btn():
if TypButton("relief")[-1] == "raised":
TypButton.config(relief="sunken")
else:
TypButton.config(relief="raised")

这是一个TypButton小部件,带有切换命令:

btn_this = TypButton(root, text="This", command=toggle_btn()).grid(row=0, column=0)

我运行了代码:

`...line 17, in __init__
Button.__init__(self, *args, **kwargs)`
`...PythonPython310libtkinter__init__.py", line 2679, in __init__
Widget.__init__(self, master, 'button', cnf, kw)`
`...PythonPython310libtkinter__init__.py", line 2595, in __init__
BaseWidget._setup(self, master, cnf)`
`...PythonPython310libtkinter__init__.py", line 2564, in _setup
self.tk = master.tk`
`AttributeError: 'str' object has no attribute 'tk'`

尝试添加";tk";任何地方的错误都超出了我的能力范围。

我尝试将if TypButton("relief")[-1] == "raised":更改为if TypButton["relief"] == "raised":出现了这个错误:

`line 26, in main
btn_this = TypButton(root, text="This", command=toggle_btn()).grid(row=0, column=0)`
`line 21, in toggle_btn
if TypButton["relief"] == "raised":`
`TypeError: 'type' object is not subscriptable`

老实说,我不知道如何修复这两个错误。

我主要怀疑的是Toggle函数,因为Class运行良好。

我希望代码检查救济是否已引发,并继续执行函数。我在网上发现的大多数帖子都有太多内容,或者对我的案件没有帮助。

很抱歉发了这么长的帖子。

附录:

我尝试了以下方法来解决切换问题。然而,我将创建超过10个具有不同名称的按钮(如示例所示(,并且我无法手动在切换功能中键入所有不同的名称。

在这种情况下,That按钮影响This按钮,而不是其本身:

global is_on
is_on = False
def toggle_btn():
global is_on
if is_on:
btn_this.config(relief="raised")
is_on = False
else:
btn_this.config(relief="sunken")
is_on = True
btn_this = Button(root, text="This", command=toggle_btn)
btn_this.grid(row=0, column=0)
btn_that = Button(root, text="That", command=toggle_btn)
btn_that.grid(row=1, column=0)

这可以使用前面提到的Checkbutton小部件来实现。然而,为了说明如何通过额外的事件处理来扩展Button小部件类,这里有一个将自定义类重命名为ToggleButton的演示。

"""
Demo creation of a derived tk.Button with extra event handling.
Someone wanted to have a button that locks down or up as you click it.
https://stackoverflow.com/q/73193733/291641
Better off using a Checkbutton(indicatoron=False)
Note: the default event handling for a tk.Button manipulates the relief
value to create the 'clicked' visual effect. This means to override this
the custom class must apply it's relief setting after the command invocation
is completed (ie at the application handler).
"""
import sys
import tkinter as tk

class ToggleButton(tk.Button):
def __init__(self, master, *args, **kwargs):
# Add a custom property "toggle"
self.toggle = False
if "toggle" in kwargs:
self.toggle = kwargs["toggle"]
del kwargs["toggle"]
super(ToggleButton, self).__init__(master=master, *args, **kwargs)
# Add a custom bind class (before the Button class)
bindtags = list(self.bindtags())
bindtags.insert(bindtags.index("Button"), "ToggleButton")
self.bindtags(tuple(bindtags))
# Include a class invoke handler.
master.bind_class("ToggleButton", '<Button-1>', ToggleButton.on_invoke)
@staticmethod
def on_invoke(event):
event.widget.toggle = not event.widget.toggle

class App(tk.Frame):
def __init__(self, master, *args, **kwargs):
super(App, self).__init__(master=master, *args, **kwargs)
self.checked = tk.IntVar(master)
f = tk.Frame(self)
self.button = ToggleButton(f, text="Toggle", command=self.on_click)
self.check = tk.Checkbutton(f, text="Checked", indicatoron=0, command=self.on_checked, variable=self.checked)
self.button.pack(side=tk.LEFT)
self.check.pack(side=tk.LEFT)
self.text = tk.Text(self)
vs = tk.Scrollbar(self, command=self.text.yview)
self.text.configure(yscrollcommand=vs.set)
f.grid(row=0, column=0, sticky=tk.NSEW)
self.text.grid(row=1, column=0, sticky=tk.NSEW)
vs.grid(row=1, column=1, sticky=tk.NSEW)
self.grid_rowconfigure(1, weight=1)
self.grid_columnconfigure(0, weight=1)
self.pack(side=tk.TOP, expand=True, fill=tk.BOTH)
def log(self, msg, tags=None):
self.text.insert(tk.END, msg, tags)
self.text.see(tk.END)
def on_click(self):
state = self.button.toggle
relief = "sunken" if state else "raised"
self.button.configure(relief=relief)
self.log(f"Toggle state is {state}n")
def on_checked(self):
self.log(f"Checked state is {self.checked.get()}n")

def main(args=None):
global app
root = tk.Tk()
app = App(root)
try:
import idlelib.pyshell
sys.argv = [sys.argv[0], "-n"]
root.bind("<Control-F2>", lambda ev: idlelib.pyshell.main())
except Exception as e:
print(e)
root.mainloop()
return 0
if __name__ == '__main__':
sys.exit(main(sys.argv[1:]))

最新更新