不同的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()

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

以下是基于您的修改代码:

  • 创建一次画布
  • 在画布上使用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()