modalPane关闭后无法关闭tkinter根窗口

时间:2019-02-06 20:31:47

标签: python tkinter listbox window python-2.x

我克隆了一个名为ListBoxChoice的类,该类在网上发现(添加了一些必需的功能)如下:

from Tkinter import *

class ListBoxChoice(object):
    def __init__(self, master=None, title=None, message=None,\
                 list=[]):
    self.master = master
    self.value = None
    self.list = list[:]

    self.modalPane = Toplevel(self.master)

    self.modalPane.transient(self.master)
    self.modalPane.grab_set()

    self.modalPane.bind("<Return>", self._choose)
    self.modalPane.bind("<Escape>", self._cancel)

    if title:
        self.modalPane.title(title)

    if message:
        Label(self.modalPane, text=message).pack(padx=5, pady=5)

    listFrame = Frame(self.modalPane)
    listFrame.pack(side=TOP, padx=5, pady=5)

    scrollBar = Scrollbar(listFrame)
    scrollBar.pack(side=RIGHT, fill=Y)

    # get the largest value of the 'list' to set the width
    widthOfList = 0
    for k in list:
        if len(str(k)) > widthOfList:
            widthOfList = len(str(k))

    # now pad some space to back of the widthOfList
    widthOfList = widthOfList + 2

    self.listBox = Listbox(listFrame, selectmode=SINGLE,\
                   width=widthOfList)

    self.listBox.pack(side=LEFT, fill=Y)
    scrollBar.config(command=self.listBox.yview)

    self.listBox.config(yscrollcommand=scrollBar.set)
    self.list.sort()

    for item in self.list:
        self.listBox.insert(END, item)

    buttonFrame = Frame(self.modalPane)
    buttonFrame.pack(side=BOTTOM)

    chooseButton = Button(buttonFrame, text="Choose",\
                   command=self._choose)
    chooseButton.pack()

    cancelButton = Button(buttonFrame, text="Cancel",\
                   command=self._cancel)
    cancelButton.pack(side=RIGHT)

    def _choose(self, event=None):
        try:
            firstIndex = self.listBox.curselection()[0]
            self.value = self.list[int(firstIndex)]
        except IndexError:
            self.value = None
        self.modalPane.destroy()

    def _cancel(self, event=None):
        self.modalPane.destroy()

    def returnValue(self):
        self.master.wait_window(self.modalPane)
        return self.value

if __name__ == '__main__':
    import random
    root = Tk()

    returnValue = True
    list = [random.randint(1,100) for x in range(50)]
    while returnValue:
        returnValue = ListBoxChoice(root, "Number Picking",\
                     "Pick one of these crazy random numbers",\
                     list).returnValue()
        print returnValue

现在此示例说明要执行以下操作:
results = ListBoxChoice(root, list=listOfItems).returnValue()

我想做的是提供一个值列表,用户可以从中选择一个值。在使用所选值的结果之前,该窗口应关闭。这是代码:

from tkinter import Tk, Label
form ListBoxChoice import ListBoxChoice
...
eventList = ["20190120","20190127","20190203"]
root = Tk()
root.withdraw() # This causes the ListBoxChoice object not to appear
selectValue = ListBoxChoice(root, title="Event",\
              message="Pick Event", list=eventList).returnValue()
root.wait_window() # Modal Pane/window closes but not the root
print("selectValue:", selectValue)

root窗口位于modalPaneToplevel)的后面。在调用过程继续之前,我必须关闭该窗口。所以这里有一个障碍。

我尝试在上方放置sleep(1.01)命令,但没有影响。 做出选择后,如何关闭ListBoxChoiceprint的{​​{1}}语句之前?因为那时我要使用结果来绘制数据。

如果我不使用selectValue,则只有在绘图关闭(过程结束)时,root.wait_winow()框也会关闭。

建议?

1 个答案:

答案 0 :(得分:0)

稍作更新

这是listboxchoice.py类的一个版本,我认为您可以按照自己的方式工作。我已经稍稍更新了上一个答案,因此该类现在在名为wait_window()的单独模块中定义。测试时,这并没有改变我可以看到的任何内容,换句话说,它仍然可以正常工作,但是我想更紧密地模拟您说的使用评论的方式。

它仍然使用mainloop(),因为这样做是必需的,以便tkinter的强制事件处理循环有运行的机会(因为root.withdraw()并未在任何地方被调用)。 Dialog Windows文章中有一些很好的背景资料,介绍了可能会有用的编程更细小的对话框。添加的test_lbc.py调用消除了由于不存在而无法关闭它的问题。很好,因为无论如何都不需要显示空窗口。

import random try: import Tkinter as tk # Python 2 except ModuleNotFoundError: import tkinter as tk # Python 3 from listboxchoice import ListBoxChoice root = tk.Tk() root.withdraw() # Hide root window. values = [random.randint(1, 100) for _ in range(50)] choice = None while choice is None: choice = ListBoxChoice(root, "Number Picking", "Pick one of these crazy random numbers", values).returnValue() print('choice: {}'.format(choice))

listboxchoice.py

""" ListBoxChoice widget to display a list of values and allow user to choose one of them. """ try: import Tkinter as tk # Python 2 except ModuleNotFoundError: import tkinter as tk # Python 3 class ListBoxChoice(object): def __init__(self, master=None, title=None, message=None, values=None): self.master = master self.value = None if values is None: # Avoid use of mutable default argument value. raise RuntimeError('No values argument provided.') self.values = values[:] # Create copy. self.modalPane = tk.Toplevel(self.master, takefocus=True) self.modalPane.bind("<Return>", self._choose) self.modalPane.bind("<Escape>", self._cancel) if title: self.modalPane.title(title) if message: tk.Label(self.modalPane, text=message).pack(padx=5, pady=5) listFrame = tk.Frame(self.modalPane) listFrame.pack(side=tk.TOP, padx=5, pady=5) scrollBar = tk.Scrollbar(listFrame) scrollBar.pack(side=tk.RIGHT, fill=tk.Y) # Get length the largest value in 'values'. widthOfList = max(len(str(value)) for value in values) widthOfList += 2 # Add some padding. self.listBox = tk.Listbox(listFrame, selectmode=tk.SINGLE, width=widthOfList) self.listBox.pack(side=tk.LEFT, fill=tk.Y) scrollBar.config(command=self.listBox.yview) self.listBox.config(yscrollcommand=scrollBar.set) self.values.sort() for item in self.values: self.listBox.insert(tk.END, item) buttonFrame = tk.Frame(self.modalPane) buttonFrame.pack(side=tk.BOTTOM) chooseButton = tk.Button(buttonFrame, text="Choose", command=self._choose) chooseButton.pack() cancelButton = tk.Button(buttonFrame, text="Cancel", command=self._cancel) cancelButton.pack(side=tk.RIGHT) def _choose(self, event=None): try: firstIndex = self.listBox.curselection()[0] self.value = self.values[int(firstIndex)] except IndexError: self.value = None self.modalPane.destroy() def _cancel(self, event=None): self.modalPane.destroy() def returnValue(self): self.master.wait_window(self.modalPane) return self.value

<trix-editor
    ref="trix"
    @keyup="listenForUser"
></trix-editor>