预加载 windows 以避免帧加载期间的 Tkinter 视觉故障

Preloading windows to avoid Tkinter visual glitches during frame load

在我进入我的 GUI 中的新页面后的最初约 1 秒内,在 window 到达正确的布局之前我立即看到许多视觉故障(before/after下面的屏幕截图)。

更新:

下面的代码将给出所需的错误。我觉得在调用 show_frame 函数时初始帧正在与下一帧合并,并且假设在预加载 (hiding/loading) 下一帧之前必须手动将初始帧从视图中隐藏起来。非常感谢您对此提供的任何帮助 - 并感谢到目前为止所有看过的人。

import tkinter as Tk
from tkinter import font as tkfont
from tkinter import filedialog, ttk #browse directories; widget support   

class Manifold(Tk.Tk):
    def __init__(self, *args, **kwargs):
        Tk.Tk.__init__(self, *args, **kwargs)
    #custom font options:
        self.title1_font = tkfont.Font(family='Helvetica',size=13) #normal type
#customized ttk GUI theme:
        GUItheme = ttk.Style()
        GUItheme.theme_use('alt')

        container = Tk.Frame(self) 
        container.pack(side="top", fill="both", expand=True)
        container.grid_rowconfigure(0, weight=1)
        container.grid_columnconfigure(0, weight=1)

        self.frames = {}
        for F,geometry,title,options,wait in zip((StartPage,PageOne),
                                    ("532x279","528x270"),
                                    ("","Experimental Data"),
                                    ((False,False),(True,False)),
                                    (100,100)):
            page_name = F.__name__
            frame = F(container, self)
            self.frames[page_name] = (frame,geometry,title,options,wait) #puts all pages in stacked order
            frame.grid(row=0, column=0, sticky="nsew")
        self.show_frame("StartPage")

    def show_frame(self, page_name): #show a frame for the given page name
        frame, geometry, title, options, wait = self.frames[page_name]
        self.geometry(geometry) #changes between window sizes
        self.title(title) #changes titles of windows
        self.resizable(*options) #changes ability of user to resize each window
        self.withdraw()
        frame.tkraise() #raises window to top
        self.after(wait,self.deiconify) #preload page before viewing
        self.update_idletasks()

class StartPage(Tk.Frame):
    def __init__(self, parent, controller):
        Tk.Frame.__init__(self, parent)
        self.controller = controller
        self.configure(background='black') #set window background color

    #page one button:
        button1 = ttk.Button(self, text="Page 1",
                         command=lambda: controller.show_frame("PageOne"))
        button1.grid(row=0,column=0,sticky='W')

class PageOne(Tk.Frame):
    def __init__(self, parent, controller):
        Tk.Frame.__init__(self, parent)
        self.controller = controller
        self.configure(background='gray15') #set window background color
        self.grid_columnconfigure(0,weight=1000) #for resizing window horizontally

    #average volume filename:
        self.label1 = Tk.Label(self, text="Average Volume Filename:",fg="gray90",bg="gray25",font=controller.title1_font)
        self.label1.grid(row=0,column=0,ipadx=10,ipady=0,sticky='W')
        self.label1.config(height=1)
        self.entry1 = Tk.Entry(self,textvariable=Tk.StringVar(),highlightbackground="black",width=50)
        self.entry1.grid(row=1,column=0,sticky="WE")
        self.entry1.insert(0," .mrc, .spi")

        self.entry1.configure(state="disabled") #prevent typing
        self.browse1 = ttk.Button(self,text="Browse",
                             command=self.browse_button1)
        self.browse1.grid(row=1,column=1,sticky='W')

    #gathers volume input:
    def browse_button1(self): 
        self.entry1.configure(state="normal") #unlocks typing for program
        self.label1.config(fg="gray90",bg='gray25') #standard colors, or reset on additional wrong input
        content_initial = self.entry1.get()

if __name__ == "__main__":
    app = Manifold()
    app.mainloop()

第一页:

过渡:

第二页:

隐藏 is/are 故障的 ToplevelTk 个实例,直到 after 一定时间过去:

try:                        # In order to be able to import tkinter for
    import tkinter as tk    # either in python 2 or in python 3
except:
    import Tkinter as tk


def hide(*toplevel_or_tk_instance_s_):
    for each in toplevel_or_tk_instance_s_:
        each.withdraw()


def show(*toplevel_or_tk_instance_s_):
    for each in toplevel_or_tk_instance_s_:
        each.iconify()
        each.deiconify()


if __name__ == '__main__':
    root = tk.Tk()
    my_toplevel1 = tk.Toplevel(root, bg='red')
    my_toplevel2 = tk.Toplevel(root, bg='green')
    hide(root, my_toplevel1, my_toplevel2)
    root.after(1000, show, root)
    root.after(2000, show, my_toplevel1)
    root.after(3000, show, my_toplevel2)
    root.mainloop()

删除所有更新调用,直到您准备好让您的 UI 可见,并且不要使用 after(0, ...) 因为零意味着代码将 运行 在 tkinter 之前有机会处理任何其他事件,包括重绘屏幕部分的请求。

好的,我知道了。使用我上面的代码(在我最初问题的 Update 部分),我做了两处更改。第一个就在主 Class 结构下:

class Manifold(Tk.Tk):
    def __init__(self, *args, **kwargs):
        Tk.Tk.__init__(self, *args, **kwargs)
    #preload windows (avoids watching widgets load in real time):
        self.withdraw() #hide window
        self.after(0,self.deiconify) #unhide window asap

第二个在 show_frame 循环中,前面的 wait 元组(在以 for F, geometry, 等开头的块中设置为 (10,10,10,10):

    def show_frame(self, page_name): #show a frame for the given page name
        frame, geometry, title, scaling, wait = self.frames[page_name]
        self.quit() #seems to be important in exiting out of previous window entirely
        self.geometry(geometry) #changes between window sizes
        self.title(title) #changes titles of windows
        self.resizable(*scaling) #changes ability of user to resize each window
        self.withdraw()
        frame.tkraise() #raises window to top
        self.after(wait,self.deiconify) #preload page before viewing
        self.update_idletasks()

如果其他人最终 运行 遇到这样的事情,我希望这对您有所帮助!