You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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()

关键修改点说明

  1. 拆分选择逻辑:把演员和电影的选择逻辑拆成start_actor_selection和start_movie_selection方法,只有在显示对应窗口时才执行,避免初始化时阻塞UI。
  2. 保存图片引用:将图片对象设为实例属性(self.loadimage_yes等),防止被垃圾回收导致图片消失。
  3. 清空旧控件:每次开始新的选择前,清空窗口内的旧控件,避免重复创建导致界面混乱。
  4. 递归处理循环:用递归的方式实现多次选择的逻辑,保证用户每次操作后界面都能正确更新。

备注:内容来源于stack exchange,提问作者Lijpe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.20 11:22:58