У меня есть приложение на основе TKinter, которое пытается управлять настройками для игры. У пользователей может быть несколько версий этой игры, и в этом случае мне нужно спросить у пользователя, какую установку они хотят управлять при запуске. Эта часть работает достаточно хорошо сама по себе; открывается диалоговое окно выбора после того, как основное окно построено и выполняется модально.Скрытие окна корня Tkinter при показе модального окна
Однако из-за различий между версиями игр было бы полезно, если бы я мог немного адаптировать интерфейс для этих случаев. Это, однако, означает, что я не могу построить главное окно, пока не узнаю, с какой установкой я работаю, поэтому он будет пустым, пока пользователь не сделает выбор.
Я хотел бы скрыть окно корня во время показа этого диалогового окна, но вызов withdraw
в корневом окне просто заставляет модальное диалоговое окно не отображаться - Python просто заканчивается зависанием без использования ЦП, и я могу «Определите, как обойти проблему, не прибегая к немодальному окну (и значительно отличающемуся потоку управления, которого я бы хотел избежать).
Пример кода экспонирование проблему и общую структуру кода (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()
Пожалуйста, объясните: какая разница - если вы скрываете окно root - диалог является модальным или нет? Результаты кажутся одинаковыми? – NorthCat
@NorthCat Применяя диалог модальный, вызывающий класс будет ждать, пока диалог будет закрыт, прежде чем перейти к следующей строке кода. Если я использую регулярное окно, он продолжит выполнение метода, и диалоговое окно должно будет вызвать событие в вызывающем классе после его завершения. Это также означает, что диалог вдруг должен действительно знать что-то о вызывающем классе. Я очень хотел бы избежать этого, так как я считаю, что он полезен для общей структуры и удобочитаемости кода. –