【问题标题】:Change checkbox list based on OptionMenu answer with tkinter使用 tkinter 根据 OptionMenu 回答更改复选框列表
【发布时间】:2018-02-21 06:43:31
【问题描述】:

tkinter 有点麻烦

事情是这样的: 我有一个dropdown (OptionMenu),可以让我选择一些东西。

我在来自OptionMenu 的变量上设置了一个tracer,它在下拉列表更改时调用一个函数。 (函数callback_project_name_changed

当回调被调用时,我检查已选择的项目并显示我想要的相应复选框列表。

这是我目前的代码:

from tkinter import *
import os
import sys
from tkinter import filedialog


class Checkbar(Frame):
    def __init__(self, parent=None, picks=[], side=LEFT, anchor=W):
        Frame.__init__(self, parent)
        self.vars = []
        for pick in picks:
            var = IntVar()
            chk = Checkbutton(self, text=pick, variable=var)
            chk.pack(side=side, anchor=anchor, expand=YES)
            self.vars.append(var)

    def state(self):
        return map((lambda var: var.get()), self.vars)


class Application():
    def __init__(self):
        self.window = Tk()

    def close_window(self):
        self.window.destroy()
        sys.exit()

    def close_window_escape(self, event):
        self.window.destroy()
        sys.exit()

    def get_project_path(self):
        self.path = filedialog.askdirectory()
        print(self.path)

    def callback_project_name_changed(self, *args):
        # @todo: Make groups like when you tick `tests` it ticks all the tests
        self.project_selected = self.project.get()
        if self.project_selected == "other":
            # @todo: whitelist/blacklist for options
            self.options = Checkbar(self.window, ['author', 'norme', 'Makefile'])
            self.options.pack(side=LEFT)

        if self.project_selected == "42commandements":
            self.options = None

        if self.project_selected == "libft":
            self.options = Checkbar(self.window, ['author', 'forbidden-functions', 'makefile', 'norme', 'static', 'extra', 'required', 'bonus', 'benchmark', 'tests', 'libftest', 'maintest', 'moulitest', 'fillit-checker', 'libft-unit-test'])
            self.options.pack(side=LEFT)

        if self.project_selected == "fillit":
            self.options = Checkbar(self.window, ['author', 'forbidden-functions', 'makefile', 'norme', 'tests', 'fillit-checker'])
            self.options.pack(side=LEFT)

    def start(self):
        if self.options != None:
            print(list(self.options.state()))

    def create_window(self):
        self.window.title("42PyChecker")
        self.window.minsize(width=800, height=800)
        # @todo: Set a icon for app image
        #self.window.iconbitmap(os.path.dirname(os.path.realpath(__file__)) + "/favicon.ico")
        # @todo: Find a way to loop through gif frames to have animated logo
        logo = PhotoImage(file=os.path.dirname(os.path.realpath(__file__)) + "/logo.gif")
        Label(self.window, image=logo).pack()
        Button(self.window, text="Select Project Path", width=20, command=self.get_project_path).pack()

        self.project = StringVar(self.window)
        dropdown = OptionMenu(self.window, self.project, "other", "42commandements", "libft", 'fillit')
        dropdown.pack()

        Button(self.window, text="Start", command=self.start).pack(side=BOTTOM)

        Button(self.window, text="Exit", command=self.close_window).pack(side=BOTTOM)
        self.window.bind('<Escape>', self.close_window_escape)

        self.project.trace("w", self.callback_project_name_changed)
        self.window.mainloop()
app = Application()
app.create_window()

如果您运行它并多次更改下拉菜单(更改为相同或不同的选项),它只会添加更多复选框而不会删除任何复选框。 我想这应该会发生,因为我没有删除任何内容,只是在每次更改下拉菜单时添加 CheckBars。

现在让我们更改一些代码并尝试添加.destroy().pack_forget()

    def callback_project_name_changed(self, *args):
        # @todo: Make groups like when you tick `tests` it ticks all the tests
        self.project_selected = self.project.get()
        if self.project_selected == "other":
            self.options.destroy()
            # @todo: whitelist/blacklist for options
            self.options = Checkbar(self.window, ['author', 'norme', 'Makefile'])
            self.options.pack(side=LEFT)

        if self.project_selected == "42commandements":
            self.options = None

        if self.project_selected == "libft":
            self.options.destroy()
            self.options = Checkbar(self.window, ['author', 'forbidden-functions', 'makefile', 'norme', 'static', 'extra', 'required', 'bonus', 'benchmark', 'tests', 'libftest', 'maintest', 'moulitest', 'fillit-checker', 'libft-unit-test'])
            self.options.pack(side=LEFT)

        if self.project_selected == "fillit":
            self.options.destroy()
            self.options = Checkbar(self.window, ['author', 'forbidden-functions', 'makefile', 'norme', 'tests', 'fillit-checker'])
            self.options.pack(side=LEFT)

Now, when selected, the output gives me an error because self.options hasn't been initialized.所以我找到了一种解决方法,只需将 is_initialized 设置为 0 或 1 就可以了。

然而,复选框并没有被删除,只是不断被添加。

TL;DR: 更改时不会删除复选框。 我想要实现的是根据通过OptionMenu 选择的内容拥有不同的复选框列表

有没有更简单的方法?

【问题讨论】:

    标签: python user-interface checkbox tkinter drop-down-menu


    【解决方案1】:

    好吧,我研究了一段时间,基于this answer 我能够让它工作。 代码如下:

    from tkinter import *
    import os
    import sys
    from tkinter import filedialog
    
    
    class Checkbar(Frame):
        def __init__(self, parent=None, picks=[], side=LEFT, anchor=W):
            Frame.__init__(self, parent)
            self.vars = []
            for pick in picks:
                var = IntVar()
                chk = Checkbutton(self, text=pick, variable=var)
                chk.pack(side=side, anchor=anchor, expand=YES)
                self.vars.append(var)
    
        def state(self):
            return map((lambda var: var.get()), self.vars)
    
    
    class Application():
        def __init__(self):
            self.window = Tk()
            self.window.title("42PyChecker")
            self.window.minsize(width=800, height=800)
            self.options_dict = {'other': ['author', 'norme', 'Makefile'],
                                  'libft': ['author', 'forbidden-functions', 'makefile', 'norme', 'static', 'extra', 'required', 'bonus', 'benchmark', 'tests', 'libftest', 'maintest', 'moulitest', 'libft-unit-test'],
                                  'fillit': ['author', 'forbidden-functions', 'makefile', 'norme', 'tests', 'fillit-checker'],
                                  '42commandements': []}
            # @todo: Make groups like when you tick `tests` it ticks all the tests
            # @todo: Set a icon for app image
            #self.window.iconbitmap(os.path.dirname(os.path.realpath(__file__)) + "/favicon.ico")
            # @todo: Find a way to loop through gif frames to have animated logo
            logo = PhotoImage(file=os.path.dirname(os.path.realpath(__file__)) + "/logo.gif")
            Label(self.window, image=logo).pack()
            Button(self.window, text="Select Project Path", width=20, command=self.get_project_path).pack()
            self.project = StringVar(self.window)
            self.options = ['None', 'NULL']
            self.project.trace("w", self.update_options)
            dropdown = OptionMenu(self.window, self.project, *self.options_dict.keys())
            dropdown.pack()
            self.options_choices = Checkbar(self.window, self.options)
            self.options_choices.pack(side=BOTTOM)
            Button(self.window, text="Start", command=self.start).pack(side=BOTTOM)
            Button(self.window, text="Exit", command=self.close_window).pack(side=BOTTOM)
            self.window.bind('<Escape>', self.close_window_escape)
    
        def close_window(self):
            self.window.destroy()
            sys.exit()
    
        def close_window_escape(self, event):
            self.window.destroy()
            sys.exit()
    
        def get_project_path(self):
            self.path = filedialog.askdirectory()
            print(self.path)
    
        def start(self):
            print(list(self.options_choices.state()))
    
        def update_options(self, *args):
            self.options = self.options_dict[self.project.get()]
            self.options_choices.destroy()
            self.options_choices = Checkbar(self.window, self.options)
            self.options_choices.pack(side=BOTTOM)
    
        def create_window(self):
            self.window.mainloop()
    

    它的工作方式非常简单。您有一本包含所有项目和选项的字典。当下拉列表改变时,我们更新列表,删除当前列表并打包新列表。

    【讨论】:

      猜你喜欢
      • 2019-01-01
      • 2019-07-04
      • 1970-01-01
      • 2011-09-27
      • 2022-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多