首页 > 解决方案 > 不同的 Tkinter 画布,带有图像背景,使用快速白色闪光切换

问题描述

我正在尝试使用 tkinter GUI 制作游戏。我的目标是为不同的菜单/屏幕制作不同的画布,以相同或不同的图像作为背景。但是我注意到,当我在不同的菜单(画布)之间切换时,切换过程中会出现快速的白色闪烁,这是不受欢迎的。据我所知,这是因为当我“pack_forget”前一个画布并打包新画布时,这两个事件之间存在细微差别但我希望切换平滑,因为这样的闪烁在一个游戏。我在下面附上了一个代码。代码有点长。实际上,我试图尽可能地减少它。所以下面的代码是检查问题所需的最少代码。

这是你应该做的:

  1. 运行程序并单击“新游戏”。
  2. 然后单击窗口底部显示的“返回”箭头。
  3. 如果您没有注意到闪烁(或者您可能会说“快速白色闪光”),请继续重复步骤 1 和 2。

画布背景的图像附在此处: 画布背景图像

from tkinter import *
from PIL import Image, ImageTk
from functools import partial

class DiceGame(Tk):
    def __init__(self):
        super(DiceGame, self).__init__()

        self.title("Dice Cricket")
        self.geometry('980x660+200-60')
        self.state('zoomed')

        self.font1 = ('Algerian', 95, 'bold')
        self.font2 = ('Comic Sans MS', 50, 'bold')
        self.font3 = ('Comic Sans MS', 40, 'bold')
        self.font4 = ('Comic Sans MS', 30, 'bold')
        self.font5 = ('Comic Sans MS', 25, 'bold')
        self.bgcolor = '#366649'

        self.background1 = PhotoImage(file = 'dicepic9.png')
        self.back_image = PhotoImage(file = "back arrow.png").subsample(7,7)
        self.MainMenu()
        self.Actice_Window = "MainMenu"

    def gameTitle(self, root):
        title_Label = Label(root,
                        text = "Dice Cricket",
                        font = self.font1,
                        bg = self.bgcolor,
                        fg = 'yellow')
        title_Label.grid(row = 0, column = 1, pady = 15, ipadx = 100)
    
    def backbutton(self, root):
        self.back_Label = Label(root,
                            text = "Back",
                            font = self.font5,
                            fg = "Yellow",
                            bg = self.bgcolor,
                            image = self.back_image,
                            compound = LEFT)

        return self.back_Label

    def MainMenu(self):
        self.MainMenu_Canvas = Canvas(self, bg = self.bgcolor, highlightthickness = 0)
        self.MainMenu_Canvas.pack(fill = BOTH, expand = True)
        self.MainMenu_Canvas.create_image(2, 2, anchor = NW, image = self.background1)
    
        self.gameTitle(self.MainMenu_Canvas)

        self.MainMenu_Frame = Frame(self.MainMenu_Canvas)
        self.MainMenu_Frame.grid(row = 1, column = 1, pady = 10, ipadx = 20)

        self.MainMenu_Label = Label(self.MainMenu_Frame,
                        text = "Main Menu",
                        font = self.font2,
                        bg = self.bgcolor,
                        fg = 'orange')
        self.MainMenu_Label.pack(fill = X, pady = (0,0))

        self.Options_Frame = Frame(self.MainMenu_Frame, bg = 'gray10', bd = 4, relief = GROOVE)
        self.Options_Frame.pack(fill = X, ipady = 5, ipadx = 60)
        label1 = Label(self.Options_Frame, text = "New Game", font = self.font4, fg = "light green", bg = "gray10")
        label1.pack()
        label1.bind('<Button-1>', self.NewGame_Menu)

    def NewGame_Menu(self, event):
        self.Actice_Window = "NewGame Menu"
        self.MainMenu_Canvas.pack_forget()

        self.NewGameMenu_Canvas = Canvas(self, bg = self.bgcolor, highlightthickness = 0)
        self.NewGameMenu_Canvas.pack(fill = BOTH, expand = True)
        self.NewGameMenu_Canvas.create_image(0, 0, anchor = NW, image = self.background1)

        self.gameTitle(self.NewGameMenu_Canvas)

        self.NewGame_Frame = Frame(self.NewGameMenu_Canvas, bg = self.bgcolor)
        self.NewGame_Frame.grid(row = 1, column = 1, pady = 10)

        self.selection_Label = Label(self.NewGame_Frame, text = "Select Game Type", font = self.font3, fg = "Silver", bg = self.bgcolor)
        self.selection_Label.pack()

        self.Matchtype_Frame = Frame(self.NewGame_Frame, bg = 'gray10', bd = 4, relief = GROOVE)
        self.Matchtype_Frame.pack(ipadx = 60, ipady = 10, pady = 15)

        label2 = Label(self.Matchtype_Frame, text = "Quick Match", font = self.font4, fg = "light green", bg = "gray10")
        label2.pack()
    
        self.back1 = self.backbutton(self.NewGameMenu_Canvas)
        self.back1.grid(row = 2, column = 1, sticky = W, padx = 190, pady = 10)
        self.back1.bind('<Button-1>', self.Go_Back)

    def Go_Back(self, event):
        if self.Actice_Window == "NewGame Menu":
           self.NewGameMenu_Canvas.pack_forget()
           self.MainMenu_Canvas.pack(fill = BOTH, expand = True)

dice = DiceGame()
dice.mainloop()

标签: python-3.xtkintercanvas

解决方案


这是因为您在切换画布时删除并重新创建了画布。

以下是根据您的修改后的代码:

  • 创建一次画布
  • 在画布上使用place()而不是pack()
  • 创建一个类方法以将画布提升到前面
from tkinter import *
from PIL import Image, ImageTk
from functools import partial

class DiceGame(Tk):
    def __init__(self):
        super(DiceGame, self).__init__()

        self.title("Dice Cricket")
        self.geometry('980x660+200-60')
        self.state('zoomed')

        self.font1 = ('Algerian', 95, 'bold')
        self.font2 = ('Comic Sans MS', 50, 'bold')
        self.font3 = ('Comic Sans MS', 40, 'bold')
        self.font4 = ('Comic Sans MS', 30, 'bold')
        self.font5 = ('Comic Sans MS', 25, 'bold')
        self.font6 = ('Comic Sans MS', 15, 'bold')
        self.bgcolor = '#366649'

        self.background1 = PhotoImage(file = 'dicepic9.png')
        self.back_image = PhotoImage(file = "back arrow.png").subsample(7,7)

        self.MainMenu_Canvas = self.NewGameMenu_Canvas = None  ###
        self.MainMenu()

    def gameTitle(self, root):
        title_Label = Label(root,
                        text = "Dice Cricket",
                        font = self.font1,
                        bg = self.bgcolor,
                        fg = 'yellow')
        title_Label.grid(row = 0, column = 1, pady = 15, ipadx = 100)

    def createLabels(self, frame, LabelList, Labeltexts):
        for i in range(len(Labeltexts)):
            label = Label(frame, text = Labeltexts[i], font = self.font4, fg = 'light green', bg = 'gray10')
            label.pack(fill = X)
            LabelList.append(label)
    
        LabelList[0].pack_configure(pady = (10,0))
        self.selection(LabelList)

    def selection(self, LabelList):
        for label in LabelList:
            label.bind("<Enter>", partial(self.color_config, label, "maroon", "pink"))
            label.bind("<Leave>", partial(self.color_config, label, "light green", "grey10"))

    def color_config(self, widget, color1, color2, event):
        widget.configure(foreground = color1, bg = color2)

    def backbutton(self, root):
        self.back_Label = Label(root,
                            text = "Back",
                            font = self.font5,
                            fg = "Yellow",
                            bg = self.bgcolor,
                            image = self.back_image,
                            compound = LEFT)

        return self.back_Label

    ### raise a canvas to the front
    def raise_canvas(self, canvas):
        canvas.tk.call("raise", canvas)

    def MainMenu(self):
        self.Actice_Window = "MainMenu"  ### moved from __init__()
        if self.MainMenu_Canvas is None:
            self.MainMenu_Canvas = Canvas(self, bg = self.bgcolor, highlightthickness = 0)
            ###self.MainMenu_Canvas.pack(fill = BOTH, expand = True)
            self.MainMenu_Canvas.place(relwidth=1, relheight=1) ###
            self.MainMenu_Canvas.create_image(0, 0, anchor = NW, image = self.background1)
        
            self.gameTitle(self.MainMenu_Canvas)

            self.MainMenu_Frame = Frame(self.MainMenu_Canvas)
            self.MainMenu_Frame.grid(row = 1, column = 1, pady = 10, ipadx = 20)

            self.MainMenu_Label = Label(self.MainMenu_Frame,
                            text = "Main Menu",
                            font = self.font2,
                            bg = self.bgcolor,
                            fg = 'orange')
            self.MainMenu_Label.pack(fill = X, pady = (0,0))

            self.Options_Frame = Frame(self.MainMenu_Frame, bg = 'gray10', bd = 4, relief = GROOVE)
            self.Options_Frame.pack(fill = X, ipady = 5, ipadx = 60)

            mainLabels = []
            Labeltexts = ["New Game", "Load Game", "Hall of Fame", "Options", "Credits", "Exit Game"]
            self.createLabels(self.Options_Frame, mainLabels, Labeltexts)

            mainLabels[0].bind('<Button-1>', self.NewGame_Menu)

        self.raise_canvas(self.MainMenu_Canvas) ###


    def NewGame_Menu(self, event):
        self.Actice_Window = "NewGame Menu"
        ###self.MainMenu_Canvas.pack_forget()
        if self.NewGameMenu_Canvas is None:
            self.NewGameMenu_Canvas = Canvas(self, bg = self.bgcolor, highlightthickness = 0)
            ###self.NewGameMenu_Canvas.pack(fill = BOTH, expand = True)
            self.NewGameMenu_Canvas.place(relwidth=1, relheight=1) ###
            self.NewGameMenu_Canvas.create_image(0, 0, anchor = NW, image = self.background1)

            self.gameTitle(self.NewGameMenu_Canvas)

            self.NewGame_Frame = Frame(self.NewGameMenu_Canvas, bg = self.bgcolor)
            self.NewGame_Frame.grid(row = 1, column = 1, pady = 10)

            self.selection_Label = Label(self.NewGame_Frame, text = "Select Game Type", font = self.font3, fg = "Silver", bg = self.bgcolor)
            self.selection_Label.pack()

            self.Matchtype_Frame = Frame(self.NewGame_Frame, bg = 'gray10', bd = 4, relief = GROOVE)
            self.Matchtype_Frame.pack(ipadx = 60, ipady = 10, pady = 15)

            newGameLabels = []
            newGameLabelsText = ["Quick Match", "Bilateral Series", "Tournament", "Practice"]
            self.createLabels(self.Matchtype_Frame, newGameLabels, newGameLabelsText)
        
            self.back1 = self.backbutton(self.NewGameMenu_Canvas)
            self.back1.grid(row = 2, column = 1, sticky = W, padx = 190, pady = 10)
            self.back1.bind('<Button-1>', self.Go_Back)

        self.raise_canvas(self.NewGameMenu_Canvas) ###

    def Go_Back(self, event):
        if self.Actice_Window == "NewGame Menu":
           ###self.NewGameMenu_Canvas.pack_forget()
           ###self.MainMenu_Canvas.pack(fill = BOTH, expand = True)
           self.raise_canvas(self.MainMenu_Canvas) ###

dice = DiceGame()
dice.mainloop()

推荐阅读