Tkinter Canvas清除失效:Mancala游戏特殊规则场景异常
Mancala游戏Tkinter实现的视觉更新异常问题
问题现象
- 游戏中Pit类的
clear_counters方法通过self.canv.delete("all")清除Canvas上的棋子,普通操作时正常生效。 - 触发特殊规则时出现异常:当玩家最后一颗棋子落在己方空坑,需取对面坑的棋子存入银行,此时
clear_counters方法已执行(通过打印语句可确认),但对应Canvas未被清除,银行计数正确但对面坑的棋子视觉未消失。
复现步骤
依次选择列6、2、7、8,再选择列6,即可触发该特殊规则场景。
完整游戏代码
import tkinter as tk from tkinter import messagebox as m import random as r import math as ma WOODEN="#DEB887" PALE_COLOURS={"PALE_BLUE":"#CDF5F6", "PALE_YELLOW":"#EFF9DA", "PALE_RED":"#F9D8D6", "PALE_GREEN":"#DDF0C7", "PALE_PINK":"#D6CDEA", "PALE_ORANGE":"#FFCD9B"} PALE_GREY="#C3C3C3" YELLOW="#FFFF00" BLACK="#000000" class Game(tk.Tk): def __init__(self): super().__init__() self.geometry("920x210") self.configure(bg=WOODEN) self.resizable(False, False) self.title("Mancala") self.layout_info={"0":"P2","1":"P1"} self.turn="P2" self.P1pots={"Bank":Bank(self,"P1"),"Pits":[Pit(self,"P1",i) for i in range(1,9)]} self.P2pots={"Bank":Bank(self,"P2"),"Pits":[Pit(self,"P2",i) for i in range (1,9)]} self.distribute_counters() self.switch_turns() self.mainloop() def check_end(self): self.player1total=0 self.player2total=0 for item in self.P1pots["Pits"]: self.player1total+=len(item.counters) for item in self.P2pots["Pits"]: self.player2total+=len(item.counters) self.player1empty=self.player1total == 0 self.player2empty=self.player2total == 0 end = (self.player1empty) or (self.player2empty) if end: self.finish() def move_counters(self,sequence): global colours for x in range(len(colours)): for item in self.winfo_children(): if item.grid_info()["row"] == sequence[x][0] and item.grid_info()["column"] == sequence[x][1]: last=item item.increment_counters() intermediate=self.layout_info[str(last.grid_info()["row"])] print(last.grid_info()) print(last.counters) print(intermediate,self.turn) if len(last.counters) == 1 and intermediate == self.turn: if self.turn == "P1": self.P2pots["Pits"][last.grid_info()["column"]-1].clear_counters() self.P1pots["Bank"].increment_counters(len(colours)) else: self.P1pots["Pits"][last.grid_info()["column"]-1].clear_counters() self.P2pots["Bank"].increment_counters(len(colours)) elif last.grid_info()["column"] == 0 or last.grid_info()["column"] == 9: self.switch_turns() def finish(self): self.player1finaltotal=len(self.P1pots["Bank"].counters) self.player2finaltotal=len(self.P2pots["Bank"].counters) if self.player1empty: self.player2finaltotal+=self.player2total for item in self.P2pots["Pits"]: amount=len(item.counters) if amount != 0: item.clear_counters() self.P2pots["Bank"].increment_counters(amount) if self.player2empty: self.player1finaltotal+=self.player2total for item in self.P1pots["Pits"]: amount=len(item.counters) if amount != 0: item.clear_counters() self.P1pots["Bank"].increment_counters(amount) v=False if self.player1finaltotal > self.player2finaltotal: winner="Player 1" elif self.player2finaltotal > self.player1finaltotal: winner="Player 2" else: v=True m.showinfo("Endgame","It is a draw!") if not v: m.showinfo("Endgame",winner+" has won!") again=m.askyesno("Endgame","Do you want to play again?") if again: self.reset() else: self.destroy() quit() def reset(self): self.turn="P2" self.P1pots={"Bank":Bank(self,"P1"),"Pits":[Pit(self,"P1",i) for i in range(1,9)]} self.P2pots={"Bank":Bank(self,"P2"),"Pits":[Pit(self,"P2",i) for i in range (1,9)]} self.distribute_counters() self.switch_turns() def switch_turns(self): self.check_end() if self.turn == "P1": self.turn = "P2" for item in self.P2pots["Pits"]: if len(item.counters) != 0: item.add_events() for item in self.P1pots["Pits"]: item.remove_events() else: self.turn = "P1" for item in self.P1pots["Pits"]: if len(item.counters) != 0: item.add_events() for item in self.P2pots["Pits"]: item.remove_events() def distribute_counters(self): for item in self.P1pots["Pits"]: item.add_counters() for item in self.P2pots["Pits"]: item.add_counters() class Cell(tk.Frame): def __init__(self,master,height,BG): super().__init__(master=master,width=80,height=height,bg=BG,borderwidth=0) self.amount=0 self.counters=[] self.start_canvas() self.redraw() def start_canvas(self): self.canv=tk.Canvas(self,width=80,height=80,bg=WOODEN,bd=0,highlightthickness=0) def redraw(self): self.canv.grid(row=0,column=0,sticky="NESW") class Bank(Cell): def __init__(self,master,player): super().__init__(master,148,WOODEN) self.player=player self.counters=[] self.enlarge_canvas() self.add_pot() if player == "P1": self.grid(row=0,column=9,rowspan=2,pady=(7,10),padx=(10,15)) else: self.grid(row=0,column=0,rowspan=2,pady=(10,7),padx=(15,10),sticky="NESW") def increment_counters(self,num=1): global colours for x in range(num): coord=(0,0) while self.invalid(coord): coord=(r.randint(10,70),r.randint(10,170)) colour=colours.pop() self.counters.append(colour) c=(coord[0]-10,coord[1]-10,coord[0]+10,coord[1]+10) self.canv.create_oval(c,fill=colour,outline=BLACK) def invalid(self,coords): if coords[1] > 140: return ma.sqrt((coords[0]-40)**2+(coords[1]-140)**2) >= 30 elif coords[1] < 40: return ma.sqrt((coords[0]-40)**2+(coords[1]-40)**2) >= 30 else: return False def enlarge_canvas(self): self.canv.configure(height=180) def add_pot(self): self.p1=self.canv.create_arc((2,2,78,78),start=0,extent=180) self.p2=self.canv.create_arc((2,102,78,178),start=180,extent=180) self.p3=self.canv.create_line(2,40,78,40,fill=WOODEN) self.p4=self.canv.create_line(2,140,78,140,fill=WOODEN) self.p5=self.canv.create_line(2,40,2,140) self.p6=self.canv.create_line(78,40,78,140) class Pit(Cell): def __init__(self,master,player,index): super().__init__(master,80,WOODEN) self.amount=6 self.master=master self.counters=[] self.add_pot() if player == "P1": self.grid(row=1,column=index,pady=(7,12),padx=4,sticky="NESW") else: self.grid(row=0,column=9-index,pady=(12,7),padx=4,sticky="NESW") def increment_counters(self): global colours colour=colours.pop() if len(self.counters) == 6: self.canv.create_oval((30,30,50,50),outline=BLACK,fill=colour) else: dist=r.uniform(0,30) angle=r.uniform(0,2*ma.pi) y=dist*ma.sin(angle) x=dist*ma.cos(angle) coords=(x+50,y+50,x+30,y+30) self.canv.create_oval(coords,outline=BLACK,fill=colour) self.counters.append(colour) def chosen(self,event): self.clear_counters() self.determine_sequence() self.master.switch_turns() def determine_sequence(self): if self.grid_info()["row"] == 0: orderlist=[(0,x) for x in range(self.grid_info()["column"]-1,0,-1)]+[(0,0)]+[(1,x) for x in range(1,9)] orderlist+=orderlist+orderlist+orderlist self.master.move_counters(orderlist) else: orderlist=[(1,x) for x in range(self.grid_info()["column"]+1,9)]+[(0,9)]+[(0,x) for x in range(8,0,-1)] orderlist+=orderlist+orderlist+orderlist self.master.move_counters(orderlist) def clear_counters(self): global colours colours=self.counters print("A") self.canv.delete("all") print("B") self.p1=self.canv.create_oval(1,1,79,79) self.counters=[] def add_events(self): self.canv.bind("<Enter>",lambda e: self.canv.itemconfig(self.p1,outline=YELLOW)) self.canv.bind("<Leave>",lambda e: self.canv.itemconfig(self.p1,outline=BLACK)) self.canv.bind("<Button-1>",self.chosen) def remove_events(self): self.canv.unbind("<Enter>") self.canv.unbind("<Leave>") self.canv.unbind("<Button-1>") def add_pot(self): self.p1=self.canv.create_oval(1,1,79,79) def add_counters(self): coords=[(43,7,63,27),(18,7,38,27),(43,53,63,73),(18,53,38,73),(4,30,24,50),(76,50,56,30)] for z in range(6): colour=PALE_COLOURS[list(PALE_COLOURS)[z]] self.counters.append(colour) self.canv.create_oval(coords[z],outline=BLACK,fill=colour) if __name__ == "__main__": window = Game()
内容的提问来源于stack exchange,提问作者Shaken not Stirred
相关产品推荐
相关产品推荐

