Почему не рекомендуется использовать несколько экземпляров Tk?

#python #tkinter

#python #tkinter #tcl #tk

Вопрос:

Рассмотрим приведенный ниже пример:

 import tkinter as tk

root = tk.Tk()
root.title("root")

other_window = tk.Tk()
other_window.title("other_window")

root.mainloop()
 

а также смотрите Приведенный Ниже пример, в котором создаются экземпляры Tk back-to-back, а не сразу, так что в любой момент времени существует ровно один Tk экземпляр:

 import tkinter as tk

def create_window(window_to_be_closed=None):
    if window_to_be_closed:
        window_to_be_closed.destroy()
    window = tk.Tk()
    tk.Button(window, text="Quit", command=lambda arg=window : create_window(arg)).pack()
    window.mainloop()

create_window()
 
  • Почему считается плохим иметь несколько экземпляров Tk ?
  • Считается ли второй фрагмент немного лучше или он страдает от тех же условий, что и первый код?

Ответ №1:

Почему считается плохим иметь несколько экземпляров Tk ?

Tkinter — это просто оболочка python вокруг встроенного интерпретатора Tcl, который импортирует библиотеку Tk. Когда вы создаете корневое окно, вы создаете экземпляр интерпретатора Tcl.

Каждый интерпретатор Tcl представляет собой изолированную изолированную среду. Объект в одной изолированной среде не может взаимодействовать с объектами в другой. Наиболее распространенным проявлением этого является то, что a StringVar , созданный в одном интерпретаторе, не виден в другом. То же самое касается виджетов — вы не можете создавать виджеты в одном интерпретаторе, который имеет родительский виджет в другом интерпретаторе. Изображения — это третий случай: изображения, созданные в одном, не могут быть использованы в другом.

С технической точки зрения нет причин, по которым вы не можете иметь два экземпляра Tk одновременно. Рекомендация против этого заключается в том, что редко возникает реальная необходимость в двух или более разных интерпретаторах Tcl, и это вызывает проблемы, которые трудно понять новичкам.

Считается ли второй фрагмент немного лучше или он страдает от тех же условий, что и первый код?

Невозможно сказать, лучше ли второй пример в вопросе или нет, не зная, чего вы пытаетесь достичь. Вероятно, это ничуть не лучше, поскольку, опять же, редко бывает время, когда вам действительно нужны два экземпляра.

Лучшее решение в 99,9% случаев — создать ровно один экземпляр Tk , который вы используете для жизни вашей программы. Если вам нужно второе или последующее окно, создайте экземпляры Toplevel . Проще говоря, именно так был разработан tkinter и базовый интерпретатор Tcl / Tk.

Комментарии:

1. Если у вас будет несколько экземпляров Tk about , их, вероятно, следует поместить в отдельные потоки, чтобы они получали свои собственные циклы обработки событий. Технически возможно объединить базовые виджеты из этих потоков в одно представление, но это очень продвинутая техника, и я не знаю, действительно ли она вообще доступна в Tkinter. Честно говоря, сохранение всей активности GUI в одном потоке на практике намного проще.

2. Извините за понижающий голос, неосторожный щелчок, теперь мой голос заблокирован.

3. Для любопытных людей о том, как использовать продвинутую технику объединения виджетов вместе: см. toplevel -use И toplevel -container .

Ответ №2:

Лучшая ссылка, которую я нашел до сих пор, — это раздел Application Windows в tkinterbook:

В простых примерах, которые мы использовали до сих пор, на экране есть только одно окно; корневое окно. Это автоматически создается при вызове конструктора Tk

и

Если вам нужно создать дополнительные окна, вы можете использовать виджет верхнего уровня. Это просто создает новое окно на экране, окно, которое выглядит и ведет себя почти так же, как исходное корневое окно

Я считаю, что Tk экземпляр создает Toplevel виджет, а также такие вещи, как mainloop , из которых должен быть только один.

Ответ №3:

Я не согласен с tkinter сообществом, препятствующим использованию нескольких tk.Tk окон. У вас может быть несколько tk.Tk окон. Использование нескольких экземпляров tk.Tk — единственный способ создать окна, которые действительно независимы друг от друга. Единственная ошибка, которую большинство людей допускают при создании нескольких tk.Tk окон, заключается в том, что они забывают передать master=... при создании PhotoImage s / StringVar s / IntVar s/ …

Например, посмотрите на этот код:

 import tkinter as tk

root = tk.Tk()
root2 = tk.Tk()

variable = tk.StringVar() # Add `master=root2` to fix the problem
entry = tk.Entry(root2, textvariable=variable)
entry.bind("<Return>", lambda e: print(repr(variable.get())))
entry.pack()

root.mainloop()
 

Приведенный выше код не работает. Если вы добавите master=root2 к tk.StringVar() , то он будет работать отлично. Это потому tkinter , что хранит первый экземпляр tk.Tk() in tk._default_root . Тогда, если вы не перейдете master=... , он будет считать, что вы хотели, чтобы окно tk._default_root было введено.


Еще одна вещь, которую люди ошибаются, это то, сколько раз следует .mainloop() вызывать. Он обрабатывает события из всех tk.Tk активных окон, поэтому вам нужен только один .mainloop() .

Для людей, которые не согласны, мне было бы интересно привести пример того, где реальная проблема вызвана несколькими tk.Tk окнами.

Ответ №4:

Tk() инициализирует скрытый интерпретатор tcl, чтобы код мог выполняться, поскольку Tkinter — это просто оболочка для tcl / tk. Он также автоматически создает новое окно. Toplevel() просто создает новое окно и не будет работать, если Tk() экземпляр не был создан, поскольку для этого требуется инициализирующий интерпретатор tcl Tk() . Вы не можете создавать какие-либо виджеты Tkinter без создания экземпляра Tk() , а Toplevel — это просто виджет. В вопросе вы используете Tk() для создания второго окна. Вместо этого вам следует создать другой файл, потому что многократная инициализация интерпретатора tcl может привести к путанице, как так хорошо объясняет @Bryan Oakley. Тогда вам следует сделать:

from os import startfile
startfile(nameOfTheOtherFile)

потому что, как Toplevel() и просто виджет, он закрывается при закрытии Tk() окна. Наличие другого окна в отдельном файле делает его менее запутанным.

Комментарии:

1. os.startfile() специфична ли ОС Windows, поэтому ваше решение не является универсальным. Кроме того, если другим файлом является Python script, он может работать неправильно, если у вас установлено более одной версии интерпретатора.