【问题标题】:Tkinter - Withdrawing previous window as opposed to destroying it causing issues in current windowTkinter - 撤回前一个窗口而不是破坏它导致当前窗口出现问题
【发布时间】:2021-04-16 12:40:16
【问题描述】:

我有一个使用登录窗口初始化的应用程序 - 一旦验证了用户和密码,它就会打开主菜单窗口(该窗口的代码如下)。以前,如果用户没有选择从主菜单注销以返回登录。但现在我插入了一个注销按钮,它应该杀死当前窗口打开以前的登录窗口。

问题是以前我不必保留登录窗口的状态,因为我从未计划返回那里,但现在我确实希望选择返回那里 - 所以我需要保留状态 - 因此我需要使用root.withdraw() 而不是root.destroy(),这似乎是我问题的根源(没有双关语)

如果我直接在我的 IDE 上执行 main_menu_window() 函数 - 它可以 100% 工作,但是如果我在下面的代码中从 LoginWindow(“父级”)调用它,我会收到如下详细信息的错误:

def main_menu_window(_parent, _user):

    def open_user_man(event=None):
        user_man_window(main_win)
        main_menu_window(_user)

    def open_prof_man(event=None):
        prof_man_window(main_win, _user)
        main_menu_window(_user)

    def open_mon_leagues(event=None):
        mon_leagues_window(main_win)
        main_menu_window(_user)

    def back_to_login():
        main_win.destroy()
        # if _parent is not None:
        #     _parent.deiconify()

    # Hide Login Window
    if _parent is not None:
        _parent.withdraw()

    # Window Setup
    main_win = tk.Tk()
    main_win.title("11Sixteen Database Management Controller - Main menu")
    main_win.geometry("%dx%d+0+0" % (main_win.winfo_screenwidth(), main_win.winfo_screenheight()))

    # Object setup
    user_man = ImagedButtonWithText(main_win,
                                    'C:\\Users\\rferreira\\GitHub\\11Sixteen\\DatabaseManagentController\\GlobalResources\\Images_Icons\\user_man_icon.png',
                                    "LargeGroove", "User Management")
    prof_man = ImagedButtonWithText(main_win,
                                    'C:\\Users\\rferreira\\GitHub\\11Sixteen\\DatabaseManagentController\\GlobalResources\\Images_Icons\\profile_man_icon.png',
                                    "LargeGroove", "Profile Management")
    mon_leas = ImagedButtonWithText(main_win,
                                    'C:\\Users\\rferreira\\GitHub\\11Sixteen\\DatabaseManagentController\\GlobalResources\\Images_Icons\\monitor_leagues_icon.png',
                                    "LargeGroove", "Monitored Leagues")
    back_to_mm_btn = ColourSchemedButton(main_win, "PaleGreen", "Logout", width=18)

    # Object binding
    user_man.btn.config(command=open_user_man)
    prof_man.btn.config(command=open_prof_man)
    mon_leas.btn.config(command=open_mon_leagues)
    back_to_mm_btn.config(command=back_to_login)

    # Object placement
    back_to_mm_btn.grid(row=0, column=0, columnspan=2, padx=30, pady=20, sticky="nw")
    user_man.frame.grid(row=1, column=0, padx=30, pady=20)
    prof_man.frame.grid(row=1, column=1, padx=30, pady=20)
    mon_leas.frame.grid(row=1, column=2, padx=30, pady=20)

    main_win.mainloop()


if __name__ == "__main__":
    user = User()
    main_menu_window(None, user)

我得到的错误如下:

C:\Users\rferreira\AppData\Local\Programs\Python\Python39\python.exe C:/Users/rferreira/GitHub/11Sixteen/DatabaseManagentController/Login/LoginWindow.py
Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Users\rferreira\AppData\Local\Programs\Python\Python39\lib\tkinter\__init__.py", line 1892, in __call__
    return self.func(*args)
  File "C:\Users\rferreira\GitHub\11Sixteen\DatabaseManagentController\Login\LoginWindow.py", line 19, in login_process
    validate_login(login_win, email_entry, password_entry, message_label)
  File "C:\Users\rferreira\GitHub\11Sixteen\DatabaseManagentController\Login\LoginValidation.py", line 54, in validate_login
    login_attempt()
  File "C:\Users\rferreira\GitHub\11Sixteen\DatabaseManagentController\Login\LoginValidation.py", line 42, in login_attempt
    MwW.main_menu_window(parent, user)
  File "C:\Users\rferreira\GitHub\11Sixteen\DatabaseManagentController\MainMenu\MainMenuWindow.py", line 41, in main_menu_window
    user_man = ImagedButtonWithText(main_win,
  File "C:\Users\rferreira\GitHub\11Sixteen\DatabaseManagentController\GlobalResources\GuiObjectsFactories.py", line 45, in __init__
    self.btn = LargeGroove(self.frame, image=image)
  File "C:\Users\rferreira\GitHub\11Sixteen\DatabaseManagentController\GlobalResources\GUIObjectsComponents.py", line 20, in __init__
    super().__init__(master=parent, width=130, height=130, relief="groove", **kw)
  File "C:\Users\rferreira\AppData\Local\Programs\Python\Python39\lib\tkinter\__init__.py", line 2650, in __init__
    Widget.__init__(self, master, 'button', cnf, kw)
  File "C:\Users\rferreira\AppData\Local\Programs\Python\Python39\lib\tkinter\__init__.py", line 2572, in __init__
    self.tk.call(
_tkinter.TclError: image "pyimage4" doesn't exist

我希望能提供有关如何消除此错误的任何帮助或想法。如果您需要更多详细信息或进一步的代码提取,请告诉我。

为了更好的上下文,下面是对触发错误的对象的进一步代码提取

class ImagedButtonWithText(tk.Frame):
    def __init__(self, parent, image_path, btn_type, text, **kw):
        self.frame = tk.Frame(parent)

        # Set up button
        image = PhotoImageComp(image_path)
        if btn_type == "MicroGroove":
            self.btn = MicroGroove(self.frame, image=image)
        if btn_type == "LargeGroove":
            self.btn = LargeGroove(self.frame, image=image)
        self.btn.image = image
        self.btn.grid(row=0, column=0)

        # Set up text
        self.label = tk.Label(self.frame, text=text)
        self.label.grid(row=1, column=0)

# --------------------- Buttons ---------------------------
class MicroGroove(tk.Button):
    def __init__(self, parent, **kw):
        super().__init__(master=parent, width=30, height=20, relief="groove", **kw)

class LargeGroove(tk.Button):
    def __init__(self, parent, **kw):
        super().__init__(master=parent, width=130, height=130, relief="groove", **kw)

【问题讨论】:

  • 试试notebook 把东西放在后台,改变包含框架的可见性? self.nb = ttk.Notebook(master) self.nb.add(page, state='hidden') 其中page 是您添加到笔记本的框架。
  • 另外,不是直接调用框架中的对象,这是有问题的,正如您所指出的,当您删除它们时,您可以查找特定类型和名称的所有对象,然后关联它们具有特定的期望效果。 for i in page.winfo_children(): if i.winfo_class() == "Button": return i.get('value') 再次,其中page 是一个框架。
  • 只是建议,但我上面的任何一个 cmets 都可以解决您遇到的问题。改变可见性而不是删除的问题在于它仍然存在于内存中,如果您正在创建一个复杂的 gui,这可能会很快陷入困境。第二种解决方案不是简单的物流问题。
  • image = PhotoImageComp(image_path)更改为image = PhotoImageComp(image_path, master=parent)
  • @RubenFerreira 很好,我会在 1 小时内写出正确的答案。基本上是为了缩短它:tkinter 总是假设主窗口是第一个窗口

标签: python tkinter


【解决方案1】:

Tkinter 从不强迫你传递主参数。你通常这样做:

self.label = tk.Label(self.frame, text=text)

self.frame 是标签的主人。同样,您应该在创建 PhotoImages 时传入 master 参数,如下所示:

image = PhotoImage(image_path, master=parent)

仅当您有超过 1 个 Tk() 实例时才需要这样做,但我建议始终传递它。

如果你不传入它,tkinter 会假定主服务器是你创建的Tk() 的第一个实例。这是一个问题,因为Tk() 的不同实例不能相互通信(大部分时间),所以根据Tk() 的第二个实例,PhotoImage 实际上并不存在。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多