python-3.x - 不同的 Tkinter 画布,带有图像背景,使用快速白色闪光切换
问题描述
我正在尝试使用 tkinter GUI 制作游戏。我的目标是为不同的菜单/屏幕制作不同的画布,以相同或不同的图像作为背景。但是我注意到,当我在不同的菜单(画布)之间切换时,切换过程中会出现快速的白色闪烁,这是不受欢迎的。据我所知,这是因为当我“pack_forget”前一个画布并打包新画布时,这两个事件之间存在细微差别但我希望切换平滑,因为这样的闪烁在一个游戏。我在下面附上了一个代码。代码有点长。实际上,我试图尽可能地减少它。所以下面的代码是检查问题所需的最少代码。
这是你应该做的:
- 运行程序并单击“新游戏”。
- 然后单击窗口底部显示的“返回”箭头。
- 如果您没有注意到闪烁(或者您可能会说“快速白色闪光”),请继续重复步骤 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()
推荐阅读
- php - 未找到 laravel 模型中的搜索问题
- node.js - 无法从 http.js 文件配置 bodyParser 限制,因此得到 413 http 错误
- java - Java XML DOM:为什么 Java XML Attr.isId() 在应该返回 true 时返回 false
- gem5 - 如何在 gem 5 中运行我自己的程序?假设我想对 1 千个数字进行排序,因为我想制作程序然后想运行?
- javascript - JavaScript/jQuery 2 下拉菜单在页面加载时具有相同的选择选项
- java - 在格式化代码时保持语句彼此相邻
- python - 每次我获取 Facebook Python3 的源代码时,我是如何得到这个解码错误的
- spring - 使 application.properties 保持最新
- python - Python:全局影响字典而不是单个类字典
- laravel - 在 Laravel 中添加自定义验证时,类 Closure 的对象无法转换为字符串