Обработка нескольких экземпляров окон через меню в Tkinter

У меня есть меню с пунктами, через которые я хочу открывать отдельные окна:

from tkinter import *
from PIL import ImageTk, Image

def show_text():
    top = Toplevel()
    top.title("Text")
    top.geometry("200x100")
    my_label = Label(top, text = "Text")
    my_label.pack()

def show_image():
    global my_image
    top = Toplevel()
    top.title("Graph")
    my_image = ImageTk.PhotoImage(Image.open("my_image.png"))
    my_label = Label(top, image = my_image)
    my_label.pack()

root = Tk()
root.title("Main window")
root.geometry("300x200")

my_menu = Menu(root)
root.config(menu=my_menu)

item_menu = Menu(my_menu)
my_menu.add_cascade(label = "Info", menu=item_menu)
item_menu.add_command(label = "Text", command=show_text)
item_menu.add_command(label = "Graph", command=show_image)

root.mainloop()

Проблема в том, что когда я снова выбираю элемент из меню, я получаю другой экземпляр окна:

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

Мои вопросы:

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

  2. Если я не хочу разрешать несколько экземпляров одного и того же окна, как мне закрыть старый экземпляр окна при создании нового (выберите пункт меню еще раз)?

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

P.S. Вместо my_image.png в коде вы можете использовать любое подходящее изображение на вашем компьютере.

🤔 А знаете ли вы, что...
С Python можно создавать ботов для социальных сетей и мессенджеров.


52
2

Ответы:

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

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

Для вопроса 2: используйте Grab_set(), чтобы предотвратить открытие нового окна.

Пожалуйста, задавайте вопросы только по одному.

Добавьте в строку 17 my_label.image = my_image. для эталонного изображения.

my_label.image = my_image

Скриншот:


Решено

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

Ваш код делает это. Изображение предыдущих окон не исчезает.

Вопрос 2: Если я не хочу разрешать несколько экземпляров одного и того же окна, как мне закрыть старый экземпляр окна при создании нового (выберите пункт меню еще раз)?

Дайте разные имена двум окнам верхнего уровня, например text_top и image_top. В соответствующих оконных функциях верхнего уровня добавьте условный оператор следующим образом. Также сделайте Widown верхнего уровня глобальным (добавьте соответствующее глобальное объявление после импорта tkinter, о котором я здесь не упоминал)

def show_text():
    global text_top 
    
    if text_top.winfo_exists():
        text_top.destroy()
        
    text_top = Toplevel(root)
    # Rest of the function

def show_image():
    global image_top
    
    if image_top.winfo_exists():
        image_top.destroy()
    image_top = Toplevel(root)
    # Rest of the function

Вопрос 3: Возможно, более разумным решением было бы отключить пункт меню после его выбора и снова включить после закрытия соответствующего окна. Как это можно сделать?

См. следующий код. изменения, представленные в виде комментариев внутри кода

from tkinter import *
from PIL import ImageTk, Image

def show_text():

    # A function to enable text_widget while closing the toplevel window
    def enable_text_menu():
        item_menu.entryconfig(0, state = NORMAL) # 0 is index
        top.destroy()
    
    top = Toplevel()
    top.title("Text")
    top.geometry("200x100")
    
    # to disable the menu item- syntax: item_menu.entryconfig(index, state=DISABLED)
    item_menu.entryconfig(0, state = DISABLED)
    my_label = Label(top, text = "Text")
    my_label.pack()
    
    # the following line triggers the function enable_text_menu on closing Toplevel
    top.protocol("WM_DELETE_WINDOW", enable_text_menu)

def show_image():

    # A function to enable graph_widget while closing the toplevel window
    def enable_image_menu():
        item_menu.entryconfig(1, state=NORMAL) # 1 is index
        top.destroy()
        
    global my_image
    top = Toplevel()
    top.title("Graph")
    
    # to disable the menu item- syntax: item_menu.entryconfig(index, state=DISABLED)
    item_menu.entryconfig(1, state=DISABLED)
    my_image = ImageTk.PhotoImage(Image.open("my_image.png"))
    my_label = Label(top, image = my_image)
    my_label.pack()
    
    # the following line triggers the function enable_image_menu on closing Toplevel
    top.protocol("WM_DELETE_WINDOW", enable_image_menu)

root = Tk()
root.title("Main window")
root.geometry("300x200")

my_menu = Menu(root)
root.config(menu=my_menu)

# In the following line, 'tearoff=0' for not including the dashed line on the top
item_menu = Menu(my_menu, tearoff=0)
my_menu.add_cascade(label = "Info", menu=item_menu)
item_menu.add_command(label = "Text", command=show_text)
item_menu.add_command(label = "Graph", command=show_image)


root.mainloop()