Tkinter多屏幕切换时Screen2显示空白的问题求助
Tkinter多屏幕切换时Screen2显示空白的问题求助
嘿,我仔细看了你的代码,发现几个导致Screen2显示空白的关键问题,咱们一个个来解决:
问题1:初始化阶段就阻塞了UI线程
你在App的__init__方法里直接写了演员选择和电影选择的while循环,这部分代码会在程序启动时立刻执行,而此时Screen1和Screen2都是被withdraw()隐藏的状态,加上wait_variable()会卡住主线程,导致后续的界面渲染完全出问题——Screen2的控件根本没机会正确初始化和显示。
问题2:PhotoImage被垃圾回收
你在循环里创建的loadimage_yes、loadimage_no都是局部变量,当循环迭代或者代码块结束后,Python的垃圾回收机制会把这些图片对象清理掉,导致按钮上的图片消失,看起来就像界面空白了。
问题3:控件创建时机错误
你在初始化阶段就尝试创建Screen2的标签和按钮,但此时Screen2处于隐藏状态,再加上线程被阻塞,这些控件根本没法正常渲染到界面上。
修改后的代码示例
我调整了代码结构,把选择逻辑拆分到对应的显示方法里,同时修复了图片引用的问题:
import random import tkinter as tk from tkinter import ttk from retrieve_data import movies from search import search_full_name, search_image class App: def __init__(self, root): self.root = root self.root.title("Whatch: What to watch?") self.root.geometry("1000x600") self.root.minsize(1000, 600) # 主界面控件 self.main_text = tk.Label(root, text="Whatch: What to watch?", font="Helvetica 40 bold") self.side_text = tk.Label(root, text="Ready to find a movie recommendation?", font="Helvetica 20") self.main_text.place(relx=0.5, rely=0.3, anchor="center") self.side_text.place(relx=0.5, rely=0.375, anchor="center") self.loadimage = tk.PhotoImage(file="gui/startbutton.png") self.startbutton = tk.Button(root, image=self.loadimage, command=self.show_screen1) self.startbutton["bg"] = "white" self.startbutton["border"] = "0" self.startbutton.place(relx=0.5, rely=0.6, anchor="center") # 初始化子窗口(暂不创建内部控件) self.screen1 = tk.Toplevel(root) self.screen1.geometry("1000x600") self.screen1.title("Your selection: Actors") self.screen1.withdraw() self.screen2 = tk.Toplevel(root) self.screen2.geometry("1000x600") self.screen2.title("Your selection: Movies") self.screen2.withdraw() self.actor_var = tk.IntVar() self.movie_var = tk.IntVar() self.liked_actors = [] self.liked_genres = [] # 保存图片引用,避免被垃圾回收 self.loadimage_yes = tk.PhotoImage(file="gui/yes.png") self.loadimage_no = tk.PhotoImage(file="gui/no.png") def show_screen1(self): self.root.withdraw() self.screen1.deiconify() self.start_actor_selection() def start_actor_selection(self): # 清空Screen1的旧控件 for widget in self.screen1.winfo_children(): widget.destroy() if len(self.liked_actors) < 3: # 随机获取演员 movie = random.choice(movies) while len(movie['cast']) == 0: movie = random.choice(movies) self.current_actor = random.choice(movie['cast']) actor_fn = search_full_name(self.current_actor) # 创建当前选择的控件 self.q = tk.Label(self.screen1, text=f"Do you like {actor_fn}", font="Helvetica 40 bold") self.q.pack() yesbutton = tk.Button(self.screen1, image=self.loadimage_yes, command=lambda: self.actor_var.set(1)) yesbutton["bg"] = "white" yesbutton["border"] = "0" yesbutton.place(relx=0.2, rely=0.6, anchor="center") nobutton = tk.Button(self.screen1, image=self.loadimage_no, command=lambda: self.actor_var.set(0)) nobutton["bg"] = "white" nobutton["border"] = "0" nobutton.place(relx=0.8, rely=0.6, anchor="center") # 等待用户选择后继续下一轮 self.screen1.wait_variable(self.actor_var) if self.actor_var.get() == 1: self.liked_actors.append(self.current_actor) self.start_actor_selection() else: # 演员选完,切换到Screen2 self.hide_screen1() def hide_screen1(self): self.screen1.withdraw() self.screen2.deiconify() self.start_movie_selection() def start_movie_selection(self): # 清空Screen2的旧控件 for widget in self.screen2.winfo_children(): widget.destroy() genre_count = len(self.liked_genres) if genre_count <= 5 and len(set(self.liked_genres)) < len(self.liked_genres): # 随机获取电影 movie = random.choice(movies) while len(movie['genre']) == 0: movie = random.choice(movies) # 创建当前选择的控件 self.q = tk.Label(self.screen2, text=f"Do you like {movie['title']}?", font="Helvetica 40 bold") self.q.pack() yesbutton = tk.Button(self.screen2, image=self.loadimage_yes, command=lambda: self.movie_var.set(1)) yesbutton["bg"] = "white" yesbutton["border"] = "0" yesbutton.place(relx=0.2, rely=0.6, anchor="center") nobutton = tk.Button(self.screen2, image=self.loadimage_no, command=lambda: self.movie_var.set(0)) nobutton["bg"] = "white" nobutton["border"] = "0" nobutton.place(relx=0.8, rely=0.6, anchor="center") # 等待用户选择后继续下一轮 self.screen2.wait_variable(self.movie_var) if self.movie_var.get() == 1: for genre in movie['genre']: self.liked_genres.append(genre) self.start_movie_selection() else: # 电影选完,回到主界面 self.hide_screen2() def hide_screen2(self): self.screen2.withdraw() self.root.deiconify() if __name__ == "__main__": root = tk.Tk() app = App(root) root.mainloop()
关键修改点说明
- 拆分选择逻辑:把演员和电影的选择逻辑拆成
start_actor_selection和start_movie_selection方法,只有在显示对应窗口时才执行,避免初始化时阻塞UI。 - 保存图片引用:将图片对象设为实例属性(
self.loadimage_yes等),防止被垃圾回收导致图片消失。 - 清空旧控件:每次开始新的选择前,清空窗口内的旧控件,避免重复创建导致界面混乱。
- 递归处理循环:用递归的方式实现多次选择的逻辑,保证用户每次操作后界面都能正确更新。
备注:内容来源于stack exchange,提问作者Lijpe
相关产品推荐
相关产品推荐

