为什么 tkinter 画布有时会被清除,但不是全部

问题描述 投票:0回答:1

在我尝试制作的游戏中,其中一种方法可以运行,但有一行代码似乎没有执行。

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()

在游戏(称为Mancala)中,玩家轮流选择单元格,然后将计数器取出并放入其右侧或左侧的单元格中(取决于哪个玩家),放入他们的“银行”,然后放入其他玩家的底池。为此,将执行 Pit() 类中的clear_counters() 方法,该方法使用 self.canv.delete("all") 清除该单元格中的计数器,并将有关其颜色的信息存储在名为 Colours 的列表中。然后,这将用于在回合期间将它们放置在单元格中。 游戏中有一条规则,如果玩家选择了一个单元格,而该单元格的最后一个计数器被放置在自己一侧的空盒子中,则他们会取出与放置最后一个计数器的单元格相对的单元格中的计数器,并将它们放入自己的“银行”中。 '。发生这种情况时,再次调用 clear_counters() 方法,并使用 print("A") 和 print("B") 语句,我可以看到该方法正在运行,但画布似乎没有被清除在特殊规则场景中。 还有另一条规则,如果您最后放置的指示物在您的底池中,您可以再进行一次,但这并不相关,但可能很方便知道。 我很高兴我的解释可能很糟糕,但希望通过测试游戏,您可以看到它是如何工作的。 我正在使用 Replit Online IDE,因此如果您测试它,几何图形可能会有所不同。 此外,我知道您只应该提供问题的可重现示例,但基本上需要整个代码,因为游戏基本完成,并且 self.canv.delete("all") 行有时会运行,但其他时候不会运行。 为了澄清问题,可能的移动是从第 2 列到第 9 列,为了达到该场景,选择第 6、2、7、8 列,然后再次第 6 列应该将一个计数器移动到下一个空白区域。规则是上面底池中的指示物应被清除并放入玩家 1 的“银行”中。它们被正确地放入银行中,但底池没有被清除。

python tkinter tkinter-canvas
1个回答
0
投票

希望我正确理解了你的解释。当我按照你的指示到达场景时。单击第 6 列后,第二位玩家的第 4 列底池将被清除。

这让我觉得你需要反向访问罐子。

更改第 59 行和 62 行

self.P2pots["Pits"][last.grid_info()["column"]-1].clear_counters()

self.P2pots["Pits"][-last.grid_info()["column"]].clear_counters()
© www.soinside.com 2019 - 2024. All rights reserved.