Я продолжаю бороться с несколькими окнами в tkinter. Сейчас оно развивается в приложение, в котором каждое окно находится в отдельном файле.
Мне нужно открыть второе окно из первого, потому что так работает приложение.
Мне также нужно открыть второе окно независимо от первого, т. е. само по себе, чтобы я мог проводить модульное тестирование по мере его разработки.
Этот вопрос уничтожает предыдущее окно, когда открывается второе окно. Не то, что я хочу: Python tkinter с несколькими окнами
Мой предыдущий вопрос закрывает первое окно при открытии второго окна. Не то, что я хочу. Хотя в комментариях указывается на опечатку (без ()), в принятом ответе используются withdraw и deiconify, которые в конечном итоге будут полезны, но не являются решением этой проблемы. Python tkinter закрывает первое окно при открытии второго окна
Это наиболее близко, поскольку оно открывает второе окно из первого окна, но не касается как (i) открытия второго окна из отдельного файла, так и (ii) возможности независимого открытия второго окна: Python tkinter класс несколько окон
Вот ВТОРОЕ окно в файле Location.py, и оно прекрасно открывается независимо:
import tkinter as tk
from tkinter import ttk
class Location(tk.Frame):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
root.title("Location")
root.geometry('400x275')
# Frames
self.mainframe = ttk.Frame(self.master)
self.mainframe.grid(column = 0, row=0)
ttk.Label(self.mainframe, text = "Second Window").grid(column=1, row=1, sticky=(tk.W, tk.E))
if __name__ == "__main__":
root = tk.Tk()
Location(root)
root.mainloop()
Вот ПЕРВОЕ окно, которое тоже открывается нормально, проблема в том, что когда я нажимаю любую кнопку, чтобы вызвать файл, чтобы открыть второе окно:
import tkinter as tk
from tkinter import ttk
import Location
class Building_Info(tk.Frame):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Frames
self.infoframe = ttk.Frame(self.master, height=400, width=200, padding = "50 100 50 100", borderwidth=10)
self.infoframe['relief'] = 'raised'
self.infoframe.grid(column = 0, row=0, sticky=(tk.E, tk.N))
self.buttonframe = ttk.Frame(self.master, height=400, width=200, padding = "50 100 50 100", borderwidth=10)
self.buttonframe['relief'] = 'raised'
self.buttonframe.grid(column = 1, row=0, sticky=(tk.E, tk.N))
# BUTTONS
confirm_button = ttk.Button(self.infoframe, text = 'Stakeholders', command = self.open_location)
confirm_button.grid(column=0, row=2)
confirm_button = ttk.Button(self.buttonframe, text = 'Location', command = self.open_location)
confirm_button.grid(column=0, row=2)
for child in self.infoframe.winfo_children():
child.grid_configure(padx=5, pady=5)
for child in self.buttonframe.winfo_children():
child.grid_configure(padx=5, pady=5)
# METHODS
def open_location(self):
Location.Location()
if __name__ == "__main__":
root = tk.Tk()
root.title("Building Information")
root.geometry('600x400')
Building_Info(root)
root.mainloop()
Когда я пытаюсь передать Location.Location() или Location.Location(root) или Location.Location(self) или Location.Location(self.master), я получаю эту ошибку:
Traceback (most recent call last):
File "C:\Users\User\AppData\Local\Programs\Python\Python312\Lib\tkinter\__init__.py", line 1948, in __call__
return self.func(*args)
^^^^^^^^^^^^^^^^
File "c:\Users\User\Documents\Python\Tutorials\BuildingInfo_Stay_Open.py", line 32, in open_location
Location_Stay_Open.Location()
File "c:\Users\User\Documents\Python\Tutorials\Location_Stay_Open.py", line 9, in __init__
root.title("Location")
^^^^
NameError: name 'root' is not defined
Но когда я пытаюсь пройти Location.Location(self.root), меня спрашивают, имел ли я в виду root.
Traceback (most recent call last):
File "C:\Users\User\AppData\Local\Programs\Python\Python312\Lib\tkinter\__init__.py", line 1948, in __call__
return self.func(*args)
^^^^^^^^^^^^^^^^
File "c:\Users\User\Documents\Python\Tutorials\BuildingInfo_Stay_Open.py", line 32, in open_location
Location_Stay_Open.Location(self.root)
^^^^^^^^^
AttributeError: 'Building_Info' object has no attribute 'root'. Did you mean: '_root'?
Теперь, если я вернусь ко второму окну class Location(tk.Frame) и попробую class Location(tk.Tk), то второе окно не откроется самостоятельно и выдаст такую ошибку:
Traceback (most recent call last):
File "c:\Users\User\Documents\Python\Tutorials\Location_Stay_Open.py", line 29, in <module>
Location(root)
File "c:\Users\User\Documents\Python\Tutorials\Location_Stay_Open.py", line 7, in __init__
super().__init__(*args, **kwargs)
File "C:\Users\User\AppData\Local\Programs\Python\Python312\Lib\tkinter\__init__.py", line 2326, in __init__
self.tk = _tkinter.create(screenName, baseName, className, interactive, wantobjects, useTk, sync, use)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: create() argument 1 must be str or None, not Tk
При попытке class Location(tk.Toplevel) откроется два окна: одно с названием «Местоположение» и другое с названием «Тк. Закрытие одного окна закрывает оба окна. Мне нужно только одно из этих окон.
Что мне нужно сделать, чтобы второе окно (Местоположение) (i) открывалось независимо и (ii) открывалось из первого окна?






Обратите внимание, что когда Location.py выполняется напрямую, root внутри Location.__init__() относится к глобальному окну root, созданному в блоке if __name__ == "__main__".
Однако при импорте Location.py код в блоке if не будет выполнен, и поэтому root не определен, поскольку к окну root, созданному в основном скрипте, импортированный модуль не может получить прямой доступ.
Вам нужно добавить аргумент root в явность класса Location:
class Location(tk.Frame):
# added root argument
def __init__(self, root, *args, **kwargs):
super().__init__(root, *args, **kwargs)
...
А затем вам нужно создать Toplevel внутри Building_Info.open_location() и передать его Location:
class Building_Info(tk.Frame):
...
def open_location(self):
# create a toplevel window
win = tk.Toplevel()
# and pass it to Location class
Location.Location(win)