当我隐藏按钮并取消隐藏按钮时,tkinter中会添加另一个重复的按钮。如何解决这个问题?

2024-04-27 00:02:46 发布

您现在位置:Python中文网/ 问答频道 /正文

enter image description here功能:当我单击“音乐理论”按钮时,我希望它显示另一个按钮(“视觉阅读”按钮),当我再次单击“音乐理论”按钮时,我希望“视觉阅读”按钮隐藏

在musictheorysubbtns()中,当我单击“视觉阅读”按钮时,我可以隐藏下拉选项菜单。我尝试对函数外部的“音乐理论”按钮执行相同操作,它在窗口上添加了两个按钮。我可以隐藏它,但当我再次点击“音乐理论”按钮时,它又增加了2个重复按钮,现在总共有4个按钮

如何解决这个问题

...
tab6 = ttk.Frame(tabControl)
tabControl.add(tab6, text="Music")
tabControl.pack(expand=5, fill='both')

musicbtnsframe = tk.Frame(tab6)
musicbtnsframe.pack(side='top')

mtheorysubbtsframe = tk.Frame(tab6)
mtheorysubbtsframe.pack(anchor='center')

mtdropdownframe = tk.Frame(tab6)
mtdropdownframe.pack(anchor='center')

mrefreshingframe = tk.Frame(tab6)
mrefreshingframe.pack(anchor='center')

def musictheorysubbtns():
    def mtheorydrops():
        mtheory_opt = mtdropdown
        mtheory_opt.config(width=50, font=('Helvetica', 12))
        mtheory_opt.pack()   
    def mtheory_images(mt):
        print(mt)  # selected option
        mt_label.config(image=mtimgz[mt])
    mt_label = tk.Label(mtdropdownframe)
    mt_label.pack(side = 'bottom', pady=padylength)
    mtimgz = {}
    for mtimgz_name in tradinglists.retracements:
        mtimgz[mtimgz_name] = ImageTk.PhotoImage(Image.open("./Images/{}.png".format(mtimgz_name)))
    mtvariable = tk.StringVar(tab2)
    mtvariable.set(tradinglists.retracements[0])
    mtdropdown = tk.OptionMenu(mtdropdownframe, mtvariable, *tradinglists.retracements, command=mtheory_images)
    def refreshmtsub():
        mtdropdownframe.pack_forget() if mtdropdownframe.winfo_manager() else mtdropdownframe.pack(anchor='center')
    mtheory_k = tk.Button(mtheorysubbtsframe, text="Sight reading", width = artbtn_width, height = btnsize_height, command=lambda:[mtheorydrops(), refreshmtsub()])
    mtheory_k.pack(side = 'left', padx=padxwidth, pady=padylength)

def refreshmt():
        mtheorysubbtsframe.pack_forget() if mtheorysubbtsframe.winfo_manager() else mtheorysubbtsframe.pack(anchor='center')
        

theory_k = tk.Button(musicbtnsframe, text="Music theory", width = btnsize_width, height = btnsize_height, command=lambda:[musictheorysubbtns(), refreshmt()])
theory_k.pack(side='left', padx=padxwidth, pady=padylength)

v2:

tab6 = ttk.Frame(tabControl)
tabControl.add(tab6, text="Music")
tabControl.pack(expand=5, fill='both')

class ShowHideButton(tk.Button):
    def __init__(self, parent, target_widget, *args, **kwargs):
        self.target = target_widget
        super().__init__(parent, *args, **kwargs)
        self.config(command=self.toggle)
    def toggle(self, force_off = False):
        if force_off or self.target.winfo_manager():
            self.target.pack_forget()
        else:
            self.target.pack()
        if isinstance(self.target, ShowHideButton):
            self.target.toggle(force_off=True)

musicbtnsframe = tk.Frame(tab6)
musicbtnsframe.pack(side='top')
mt_sub_frame = tk.Frame(tab6)
mt_sub_frame.pack(side='top')
mt_SRframe = tk.Frame(tab6)
mt_SRframe.pack(anchor='center')
mt_compframe = tk.Frame(tab6)
mt_compframe.pack(anchor='center')


def mt_images(m1t):
    print(m1t)  # selected option
    mt_label.config(image=mtimgz[m1t])
mt_label = tk.Label(mt_SRframe)
mt_label.pack(side = 'bottom', pady=padylength)
mtimgz = {}
for mt_name in musiclists.sightReaing:
    mtimgz[mt_name] = ImageTk.PhotoImage(importImageWithResize("./Music_images/Sightreading/{}.png".format(mt_name)))
mtvar = tk.StringVar(tab2)
mtvar.set(musiclists.sightReaing[0])
mt = tk.OptionMenu(mt_SRframe, mtvar, *musiclists.sightReaing, command=mt_images)
mt_opt = mt
mt_opt.config(width=50, font=('Helvetica', 12))
mt_opt.pack()   

def mtcomp_images(mtcomp1t):
    print(mtcomp1t)  # selected option
    mtcomp_label.config(image=mtcompimgz[mtcomp1t])
mtcomp_label = tk.Label(mt_compframe)
mtcomp_label.pack(side = 'bottom', pady=padylength)
mtcompimgz = {}
for mtcomp_name in musiclists.composition:
    mtcompimgz[mtcomp_name] = ImageTk.PhotoImage(importImageWithResize("./Music_images/Composition/{}.png".format(mtcomp_name)))
mtcompvar = tk.StringVar(tab2)
mtcompvar.set(musiclists.composition[0])
mtcomp = tk.OptionMenu(mt_compframe, mtcompvar, *musiclists.composition, command=mtcomp_images)
mtcomp_opt = mtcomp
mtcomp_opt.config(width=50, font=('Helvetica', 12))
mtcomp_opt.pack()   

def mt_sub_btns():
    theory_k_sightreading_k = ShowHideButton(mt_sub_frame, mt_opt, text='Sight Reading')
    theory_k_composition_k = ShowHideButton(mt_sub_frame, mtcomp_opt, text='Composition')
theory_k = ShowHideButton(musicbtnsframe, mt_sub_btns, text='Music theory')
theory_k.pack(side='left', padx=padxwidth, pady=padylength)

Tags: nameselfdef按钮framesidelabelpack
1条回答
网友
1楼 · 发布于 2024-04-27 00:02:46

当您希望将功能添加到tkinter中的某个功能时,通常最好自定义小部件来完成您需要的工作,而不是将功能串在一起。让我举个例子来说明我的意思。由于您需要一个按钮来显示/隐藏另一个按钮,以及另一个按钮来显示/隐藏optionmenu,因此您最好使用显示/隐藏其他小部件的按钮。 为此,请制作自己版本的按钮:

import tkinter as tk

class ShowHideButton(tk.Button):
    def __init__(self, parent, target_widget, *args, **kwargs):
        self.target = target_widget
        super().__init__(parent, *args, **kwargs)
        self.config(command=self.toggle)

ShowHideButton是我们新小部件的自定义名称。(tk.Button)说明我们基于哪个小部件。
__init__方法(即init,每边有两个下划线)是在创建此小部件时正确发生的。我们输入的参数基本上都需要存在self只是python需要的原因,parent*args, **kwargstk.Button需要的东西,但是target_widget只是我添加的东西,作为我们的显示/隐藏工具的目标。
self.target = target_widget将通过参数传递的小部件保存到按钮的实例。
以“super”开头的行使python运行tk.Button的init方法,因此它将构建成为按钮所需的所有内容。(这很好,因为我正在尝试使用tkinter的按钮小部件并调整它以满足我们的需要。)
最后一行将按钮的命令设置为名为self.toggle的函数。既然发生了这种情况,您就永远不需要设置按钮的命令。事实上,我们希望我们的按钮隐藏/显示其他一些小部件,其全部目的是内置该功能,这样手动设置命令就没有意义了。
将其置于init方法下,以定义self.toggle的功能:

    def toggle(self):
        if or self.target.winfo_manager():
            self.target.pack_forget()
        else:
            self.target.pack()

这应该与init方法的缩进级别相同。你可能会看到它的作用。它检查self.target是否已打包,然后对其进行更改。
如果你使用这个,你可能会注意到一些奇怪的事情:如果你隐藏了一个小部件,而这个小部件已经打开了一些东西,它会将这些东西打包。如果希望它向下传递隐藏,请将其更改为以下内容:

    def toggle(self, force_off = False):
        if force_off or self.target.winfo_manager():
            self.target.pack_forget()
        else:
            self.target.pack()
        if isinstance(self.target, ShowHideButton):
            self.target.toggle(force_off=True)

这将检查目标本身是否为ShowHideButton,如果是,则将其关闭

下面是我演示新按钮的整个测试脚本:

import tkinter as tk

root = tk.Tk()

class ShowHideButton(tk.Button):
    def __init__(self, parent, target_widget, *args, **kwargs):
        self.target = target_widget
        super().__init__(parent, *args, **kwargs)
        self.config(command=self.toggle)
    def toggle(self, force_off = False):
        if force_off or self.target.winfo_manager():
            self.target.pack_forget()
        else:
            self.target.pack()
        if isinstance(self.target, ShowHideButton):
            self.target.toggle(force_off=True)

my_option_value = tk.StringVar()
my_option_value.set('opt1')
my_option_menu = tk.OptionMenu(root, my_option_value, 'opt1', 'opt2', 'etc')
s_r_button = ShowHideButton(root, my_option_menu, text='Sight Reading')
m_t_button = ShowHideButton(root, s_r_button, text='Music theory')
m_t_button.pack()

root.mainloop()

您可以将该类块复制并粘贴到代码中,然后开始使用ShowHideButtons,就像它们是任何其他小部件一样。注意我在上面的演示中按钮的顺序。当你制定目标时,他们需要有自己的目标,所以你必须先制定目标,然后再制定目标

这也可以调整为使用网格或位置代替包装。实际上,您可以用任何喜欢的方式修改tkinter小部件。如果您有任何其他问题等,请告知我们

编辑:如果您想要一个通过按钮切换多个项目的版本,请点击这里:

class ShowHideButton(tk.Button):
    def __init__(self, parent, target_widgets, *args, **kwargs):
        self.targets = target_widgets
        super().__init__(parent, *args, **kwargs)
        self.config(command=self.toggle)
    def toggle(self, force_off = False):
        for i in self.targets:
            if force_off or i.winfo_manager():
                i.pack_forget()
            else:
                i.pack()
            if isinstance(i, ShowHideButton):
                self.target.toggle(force_off=True)

请注意,在这种情况下,必须将target_widgets设为可编辑项(如列表或元组)。如果您使用此版本,但只希望切换一个小部件,则可以将其名称用[]括起来,形成一个单一长度的列表

相关问题 更多 >