modalPane 关闭后无法关闭 tkinter root window
Can't close tkinter root window after modalPane closed
我克隆了一个名为 ListBoxChoice
的 class,在网上找到(添加了一些需要的功能)如下:
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()
.
我想做的是提供一个值列表,用户可以从中选择一个值。在我使用所选值的结果之前,window 应该关闭。这是代码:
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)
A root
window 放在 modalPane
(Toplevel
) 后面。在调用过程继续之前,我必须关闭 window。所以有一个块。
我试过在上面添加 sleep(1.01)
命令,但没有效果。
做出选择后如何关闭 ListBoxChoice
在我的 print
陈述 selectValue
之前?因为那时我想用结果来绘制数据。
如果我不使用 root.wait_winow()
,只有当图关闭(过程结束)时 ListBoxChoice
框也会关闭。
建议?
稍作更新
这是 ListBoxChoice
class 的一个版本,我认为它可以按照您想要的方式工作。我稍微更新了我之前的回答,所以 class 现在定义在一个名为 listboxchoice.py
的单独模块中。这并没有改变我在测试时看到的任何东西——换句话说,它似乎仍然有效——但我想更接近地模拟你所说的你使用它的方式评论。
它仍然使用 wait_window()
因为这样做 需要 给 tkinter 的强制事件处理循环 运行 机会(因为 mainloop()
未在任何地方调用)。在文章 Dialog Windows 中有一些很好的背景知识 material,关于对 tkiner 对话框进行编程,您可能会发现它很有用。添加的 root.withdraw()
调用消除了无法关闭它的问题,因为它不存在。这很好,因为无论如何都不需要显示空 window。
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
我克隆了一个名为 ListBoxChoice
的 class,在网上找到(添加了一些需要的功能)如下:
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()
.
我想做的是提供一个值列表,用户可以从中选择一个值。在我使用所选值的结果之前,window 应该关闭。这是代码:
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)
A root
window 放在 modalPane
(Toplevel
) 后面。在调用过程继续之前,我必须关闭 window。所以有一个块。
我试过在上面添加 sleep(1.01)
命令,但没有效果。
做出选择后如何关闭 ListBoxChoice
在我的 print
陈述 selectValue
之前?因为那时我想用结果来绘制数据。
如果我不使用 root.wait_winow()
,只有当图关闭(过程结束)时 ListBoxChoice
框也会关闭。
建议?
稍作更新
这是 ListBoxChoice
class 的一个版本,我认为它可以按照您想要的方式工作。我稍微更新了我之前的回答,所以 class 现在定义在一个名为 listboxchoice.py
的单独模块中。这并没有改变我在测试时看到的任何东西——换句话说,它似乎仍然有效——但我想更接近地模拟你所说的你使用它的方式评论。
它仍然使用 wait_window()
因为这样做 需要 给 tkinter 的强制事件处理循环 运行 机会(因为 mainloop()
未在任何地方调用)。在文章 Dialog Windows 中有一些很好的背景知识 material,关于对 tkiner 对话框进行编程,您可能会发现它很有用。添加的 root.withdraw()
调用消除了无法关闭它的问题,因为它不存在。这很好,因为无论如何都不需要显示空 window。
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