Python Tkinter-记住创建新窗口的状态(复选框)

时间:2018-11-08 13:28:00

标签: python tkinter listbox

我有一个名为view的按钮,当单击它时,将创建一个新窗口,其中包含一个列表框中的列表以及与该列表框相对应的复选框列表。切换列表框中的项目时,您会看到列表框中的项目彼此独立,并且具有自己的复选框值。截至目前,它会记住每个列表框项目的复选框值,除非您关闭创建的窗口。当您关闭创建的第二个窗口时,尝试再次打开该窗口时,所有这些信息都会消失。我需要一种方法来创建第二个窗口,使用列表框和复选框来完成它现在要做的所有事情,但是当关闭窗口时,可以再次打开它并从上次退出的地方继续。

例如,如果我突出显示列表框中的第一项并选中第一个复选框,那么我应该能够关闭该窗口并再次打开它,并且当突出显示列表框中的第一项时,我看到有一个选中第一个复选框。

import tkinter
from tkinter import *


def myfunction(event):
    canvas1.configure(scrollregion=canvas1.bbox("all"))

def onselect(evt):
    # Note here that Tkinter passes an event object to onselect()
    w = evt.widget
    x = 0
    index = int(w.curselection()[0])
    value = w.get(index)
    print('You selected item %d: "%s"' % (index, value))

    for y in enable:
        for item in list_for_listbox:
            checkbuttons[item][y][1].grid_forget()
        checkbuttons[value][y][1].grid(row=x, column=0)
        # Label(frame2, text="some text").grid(row=x, column=1)
        x += 1

def printcommand():
    for item in list_for_listbox:
        for y in enable:
            print(item + " [" + y + "] " + str(checkbuttons[item][y][0].get()))

def create_new_window():
    global new_window
    new_window = tkinter.Toplevel()
    new_window.geometry("750x500")
    new_window_commands()

master = tkinter.Tk()
master.title("Checkboxes test")
master.geometry("750x500")

button1 = Button(master, command =create_new_window,text="View")
button1.place(x=50,y=250)

def new_window_commands():
    # enable = ['button 1', 'button 2', 'button 3', 'button 4', 'button 5', 'button 6', 'button 7']
    global list_for_listbox
    global enable
    global checkbuttons
    global canvas1
    enable = []
    for x_number_of_items in range(1, 15):
        enable.append("button " + str(x_number_of_items))

    list_for_listbox = ["one", "two", "three", "four"]

    listbox = Listbox(new_window)
    listbox.place(x=5, y=5, width=100, height=10 + 16*len(list_for_listbox))
    listbox.update()

    frame1 = Frame(new_window, borderwidth=1, relief=GROOVE, highlightthickness=1, highlightbackground="black",
                   highlightcolor="black")
    frame1.place(x=listbox.winfo_width() + 10, y=5, width=300, height=listbox.winfo_height())
    canvas1 = Canvas(frame1)
    frame2 = Frame(canvas1, height=500)
    scrollbar1 = Scrollbar(frame1, orient="vertical", command=canvas1.yview)
    canvas1.configure(yscrollcomman=scrollbar1.set)
    scrollbar1.pack(side="right", fill="y")
    canvas1.pack(side="left")
    canvas1.create_window((0, 0), window=frame2, anchor='nw')
    frame2.bind("<Configure>", myfunction)

    printbutton = Button(new_window, text="Print", command=printcommand)
    printbutton.place(x=100, y=250)

    checkbuttons = {}
    for item in list_for_listbox:
        listbox.insert(END, item)
        checkbuttons[item] = (dict())
        for y in enable:
            temp_var = BooleanVar()
            checkbuttons[item][y] = [temp_var, Checkbutton(frame2, text=y, variable=temp_var)]

    listbox.bind('<<ListboxSelect>>', onselect)

    print(enable)

mainloop()

printcommand()

1 个答案:

答案 0 :(得分:2)

使用当前结构,最简单的解决方法是:

  1. 仅创建一次new_window
  2. withdraw() new_window,而不是每次都关闭它。
  3. 在被调用时再次打开new_window的相同实例。

您需要实现以下内容:

# Default your new_window to None
new_window = None

def create_new_window():
    global new_window
    # If new_window doesn't exist, create a new one
    if not new_window:
        new_window = tkinter.Toplevel()
        new_window.geometry("750x500")
        # add a new protocol to redirect on closing the window.
        new_window.protocol("WM_DELETE_WINDOW", hide_window)
        new_window_commands()
    else:
        # if new_window already exist, just unhide it
        new_window.deiconify()

# add a new function for when window is closing
def hide_window():
    global new_window
    new_window.withdraw()

您可能还想在protocol下添加相同的master方法,以便在关闭时销毁masternew_window对象:

master.protocol('WM_DELETE_WINDOW', destroy_all)
def destroy_all():
    global master
    global new_window
    master.destroy()
    new_window.destroy()

如果可能,我建议您在下一个tkinter代码中考虑使用object oriented approach。我稍后再看能否提供简短的示例。

作为旁注,尽管我了解tkinter的许多文档都使用from tkinter import *方法,但我不鼓励这种做法,建议改用import tkinter as tk(或者您已经这样做了) ,import tkinter,可以完成相同的操作)。 See relevant answer here


以下是类似的OOP方法的快速示例:

import tkinter as tk

# Here the main window can be called upon as its own instance with its own instance attributes.
class Window(tk.Tk):
    def __init__(self):
        super().__init__()
        self.main_button = tk.Button(self, text="Creat a sub window", command=self.open_sub_window)
        self.main_button.pack()

        # define the things you wish to retain under the main window as an instance attribute
        self.sub_check_var = tk.BooleanVar()
        self.sub_entry_var = tk.StringVar()

    # when creating a new window, just reference back to the main attributes you've already created.
    def open_sub_window(self):
        self.sub_window = tk.Toplevel()
        tk.Checkbutton(self.sub_window, text="I'm a checkbox!", variable=self.sub_check_var).pack()
        lbl_frm = tk.LabelFrame(self.sub_window, text="I am an entry!")
        lbl_frm.pack()
        tk.Entry(lbl_frm, text=self.sub_entry_var).pack()

gui = Window()
gui.mainloop()

请注意,这只是一种方法。您只需要四处摸索以熟悉自己的实现,就没有做对/错做事的方式。