首页 > 解决方案 > OOP,我想在切换帧时取消任何功能

问题描述

因为我使用了 OOP,所以即使没有填充 set 容器,所有帧都已初始化并运行函数。这意味着如果我的游戏正在运行,即使窗口发生变化,它也会继续运行。我想这样做,以便如果显示新框架,所有功能/方法都停止为其他窗口运行。目前,如果游戏开始,倒计时将继续进行,无论显示什么(例如菜单屏幕)。

这是所有窗口继承并排序的类:

class TextTypers(tk.Tk):

def __init__(self, *args, **kwargs):  # Runs when our class is called and allows almost anything to be passed

    tk.Tk.__init__(self, *args, **kwargs)  # Initialise Tk
    window = tk.Frame(self)  # Creates the container the windows/frames will populate
    window.pack(fill="both", expand=True)

    self.frames = {}  # Creates a dictionary for the frames

    for F in (MenuScreen, GameScreen, InstructionsScreen):
        frame = F(window, self)  # Adds all frames to dictionary so they can be accessed later
        self.frames[F] = frame
        frame.grid(row=0, column=0, sticky="nswe")

    self.show_frame(MenuScreen)  # Shows the menu screen as this is initialised when the program is run

def show_frame(self, cont):
    frame = self.frames[cont]  # Grabs value of self.frames and puts in in frame
    frame.tkraise()  # Raises frame to the front

以下是游戏画面的相关 GUI:

class GameScreen(tk.Frame):
    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)  # Inherits from main class

        self.label = tk.ttk.Label(self, text="Type the words as quick as you can!",
                                  font=("arial", 35, "bold"), justify="center")
        self.label.grid(row=1, column=3, pady=10, padx=10)

        self.time_label = tk.ttk.Label(self, text="Time left: " + str(timer), font=("arial", 30, "bold"),
                                       justify="center")
        self.time_label.grid(row=3, column=3, columnspan=2, padx=10, pady=10)

        self.word_label = tk.ttk.Label(self, font=("arial", 25, "bold"), justify="center")
        self.word_label.grid(row=5, column=3, padx=10, pady=10)

        self.entry = tk.DoubleVar()
        self.entry.set("")
        self.entry = tk.ttk.Entry(self, textvariable=self.entry, font=("arial", 25, "bold"), state='disabled')
        self.entry.grid(row=6, column=3)

        self.start_button = tk.Button(self, text="Start!", font=("arial", 20, "bold"),
                                      command=self.game, width=10, height=2)
        self.start_button.grid(row=7, column=3, pady=10, padx=10)
        self.entry.bind('<Return>', self.check_word)

        self.home_button = tk.Button(self, text="Home", font=("arial", 20, "bold"),
                                     command=lambda: controller.show_frame(MenuScreen), width=10, height=2)
        self.home_button.grid(row=8, column=3, pady=10, padx=10)

    def game(self):
        global timer
        timer = 60
        self.entry.config(state="enabled")
        self.entry.delete("0", "end")
        self.start_button.config(text="Stop", command=lambda: self.stop())
        if timer == 60:  # Starts the timer and calls the words function
            self.countdown()
        self.words()

    def countdown(self):
        global timer

        if timer > 0:
            timer -= 1
            # Update the time left label
            self.time_label.config(text="Time left: " + str(timer))

            # Run the function again after 1 second
            self.time_label.after(1000, self.countdown)

    def words(self):
        global timer
        global word
        if timer > 0:
            self.entry.focus_set()  # Activate the entry box
            word = random.choice(word_list[0])
            self.word_label.config(text=word)
        if timer == 0:
            self.results(score)

    def check_word(self, event):
        global word, score, wrong

        entered_word = self.entry.get().lower().strip()
        if entered_word == word.lower().strip():
            score += 1
        else:
            wrong += 1
        self.words()
        self.entry.delete('0', 'end')

    def results(self, score):
        global top_score
        self.entry.config(state='disabled')
        if score > top_score:
            top_score = score
        else:
            top_score = top_score
        accuracy = score / (score + wrong) * 100
        self.word_label.config(
            text=f"In one minute you correctly typed {score} words.\n"
                 f"This is a WPM of {score}, your actual WPM is most likely higher.\n "
                 f"You got {score} words correct and {wrong} words wrong. \n"
                 f" That gives you an accuracy of {accuracy:.1f}%!\n"
                 f"Your top score is {top_score}!", font=("arial", 20, "bold"))
        self.start_button = tk.Button(self, text="Play again?", font=("arial", 20, "bold"), command=self.game)
        self.start_button.grid(row=7, column=3, pady=10, padx=10)
        return top_score

标签: pythonooptkinter

解决方案


您必须在以下位置保留对回调 id 的引用self.countdown()

self.current_callback_id = self.time_label.after(1000, self.countdown)

然后调用after_cancel(self.current_callback_id)换帧。

这可能需要在更改帧逻辑中使用一些机制。


推荐阅读