我有一个基于TKinter的应用程序,它试图管理游戏的设置。用户可能安装了该游戏的多个版本,在这种情况下,我需要询问用户他们要在启动时管理哪个安装。该部分本身就可以很好地工作。构建主窗口后,将弹出选择对话框,并以模态方式运行。
但是,由于游戏版本之间的差异,如果我可以针对这些情况略微调整界面,将很有用。但是,这意味着我无法真正构建主窗口,直到我知道我正在进行的安装为止,因此在用户做出选择之前它将是空白的。
我想在显示该对话框时隐藏根窗口,但是withdraw
在根窗口上调用只会导致也不显示模式对话框-Python最终挂起而没有CPU使用率,而且我不知道如何解决该问题而不必诉诸非模态窗口(以及我想避免的控制流程明显不同)。
展示问题和常规代码结构的示例代码(Python 2.7):
from Tkinter import *
from ttk import *
class TkGui(object):
def __init__(self):
self.root = root = Tk()
self.root.withdraw()
selector = FolderSelection(self.root, ('foo', 'bar'))
self.root.deiconify()
print(selector.result)
class ChildWindow(object): #Base class
def __init__(self, parent, title):
top = self.top = Toplevel(parent)
self.parent = parent
top.title(title)
f = Frame(top)
self.create_controls(f)
f.pack(fill=BOTH, expand=Y)
def create_controls(self, container):
pass
def make_modal(self, on_cancel):
self.top.transient(self.parent)
self.top.wait_visibility() # Python will hang here...
self.top.grab_set()
self.top.focus_set()
self.top.protocol("WM_DELETE_WINDOW", on_cancel)
self.top.wait_window(self.top) # ...or here, if wait_visibility is removed
class FolderSelection(ChildWindow):
def __init__(self, parent, folders):
self.parent = parent
self.listvar = Variable(parent)
self.folderlist = None
super(FolderSelection, self).__init__(parent, 'Select folder')
self.result = ''
self.listvar.set(folders)
self.make_modal(self.cancel)
def create_controls(self, container):
f = Frame(container)
Label(
f, text='Please select the folder '
'you would like to use.').grid(column=0, row=0)
self.folderlist = Listbox(
f, listvariable=self.listvar, activestyle='dotbox')
self.folderlist.grid(column=0, row=1, sticky="nsew")
Button(
f, text='OK', command=self.ok
).grid(column=0, row=2, sticky="s")
self.folderlist.bind("<Double-1>", lambda e: self.ok())
f.pack(fill=BOTH, expand=Y)
def ok(self):
if len(self.folderlist.curselection()) != 0:
self.result = self.folderlist.get(self.folderlist.curselection()[0])
self.top.protocol('WM_DELETE_WINDOW', None)
self.top.destroy()
def cancel(self):
self.top.destroy()
TkGui()
看来,在您的情况下,模态窗口没有差异。实际上,您只需要使用该wait_window()
方法。根据文档:
在许多情况下,以同步方式处理对话框更为实用。创建对话框,显示它,等待用户关闭对话框,然后继续执行您的应用程序。正是我们需要的wait_window方法;它会进入一个本地事件循环,直到给定的窗口被销毁(通过destroy方法或显式地通过窗口管理器)后才会返回。
考虑以下非模态窗口示例:
from Tkinter import *
root = Tk()
def go():
wdw = Toplevel()
wdw.geometry('+400+400')
e = Entry(wdw)
e.pack()
e.focus_set()
#wdw.transient(root)
#wdw.grab_set()
root.wait_window(wdw)
print 'done!'
Button(root, text='Go', command=go).pack()
Button(root, text='Quit', command=root.destroy).pack()
root.mainloop()
当您单击Go
按钮时,将出现非模态对话框,但是代码将停止执行,并且done!
仅在关闭对话框窗口后才会显示字符串。
如果这是您想要的行为,那么这是修改后的形式的示例(我__init__
在TkGui和make_modal
method中进行了修改,还添加了mainloop()
):
from Tkinter import *
from ttk import *
class TkGui(object):
def __init__(self):
self.root = root = Tk()
self.root.withdraw()
selector = FolderSelection(self.root, ('foo', 'bar'))
self.root.deiconify()
print(selector.result)
class ChildWindow(object): #Base class
def __init__(self, parent, title):
top = self.top = Toplevel(parent)
self.parent = parent
top.title(title)
f = Frame(top)
self.create_controls(f)
f.pack(fill=BOTH, expand=Y)
def create_controls(self, container):
pass
def make_modal(self, on_cancel):
#self.top.transient(self.parent)
#self.top.wait_visibility() # Python will hang here...
#self.top.grab_set()
self.top.focus_set()
self.top.protocol("WM_DELETE_WINDOW", on_cancel)
self.top.wait_window(self.top) # ...or here, if wait_visibility is removed
class FolderSelection(ChildWindow):
def __init__(self, parent, folders):
self.parent = parent
self.listvar = Variable(parent)
self.folderlist = None
super(FolderSelection, self).__init__(parent, 'Select folder')
self.result = ''
self.listvar.set(folders)
self.make_modal(self.cancel)
def create_controls(self, container):
f = Frame(container)
Label(
f, text='Please select the folder '
'you would like to use.').grid(column=0, row=0)
self.folderlist = Listbox(
f, listvariable=self.listvar, activestyle='dotbox')
self.folderlist.grid(column=0, row=1, sticky="nsew")
Button(
f, text='OK', command=self.ok
).grid(column=0, row=2, sticky="s")
self.folderlist.bind("<Double-1>", lambda e: self.ok())
f.pack(fill=BOTH, expand=Y)
def ok(self):
if len(self.folderlist.curselection()) != 0:
self.result = self.folderlist.get(self.folderlist.curselection()[0])
self.top.protocol('WM_DELETE_WINDOW', None)
self.top.destroy()
def cancel(self):
self.top.destroy()
TkGui()
mainloop()
代码停止在线selector = FolderSelection(self.root, ('foo', 'bar'))
,然后在关闭对话框后继续执行。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句