我决定试用Python,到目前为止它很有趣。然而,虽然搞乱tkinter我遇到了一个问题,我几个小时都无法解决。我读了一些东西,尝试了不同的东西,但没有任何作用。 到目前为止我已经得到了代码,我认为该程序运行良好。除了我无法循环并因此自动更新的事实。
所以我的问题是: 如何以infite循环方式调用带有tkinters循环选项的函数?
简单的生活游戏: 我基本上写了两节课。存储和处理单个单元的矩阵 以及通过一些游戏逻辑和基本用户输入利用矩阵类的游戏本身。
首先是游戏类,因为我的循环问题是:
from tkinter import *
from ButtonMatrix import *
class Conway:
def __init__(self, master, size = 20, cell_size = 2):
self.is_running = True
self.matrix = ButtonMatrix(master,size,cell_size)
self.matrix.randomize()
self.matrix.count_neighbours()
self.master = master
# playbutton sets boolean for running the program in a loop
self.playbutton = Button(master, text = str(self.is_running), command = self.stop)
self.playbutton.grid(row = 0 , column = size +1 )
#Test button to trigger the next generation manually. Works as itended.
self.next = Button(master, text="next", command = self.play)
self.next.grid(row = 1, column = size +1)
def play(self): # Calculates and sets the next generation. Intended to be used in a loop
if self.is_running:
self.apply_ruleset()
self.matrix.count_neighbours()
self.apply_colors()
def apply_ruleset(self):
#The ruleset of conways game of life. I wish i knew how to adress each element
#without using these two ugly loops all the time
size = len(self.matrix.cells)
for x in range (size):
for y in range (size):
if self.cell(x,y).is_alive():
if self.cell(x,y).neighbours < 2 or self.cell(x,y).neighbours > 3:
self.cell(x,y).toggle()
if not self.cell(x,y).is_alive() and self.cell(x,y).neighbours == 3:
self.cell(x,y).toggle()
def apply_colors(self): #Some flashy colors just for fun
size = len(self.matrix.cells)
for x in range (size):
for y in range (size):
if self.cell(x,y).is_alive():
if self.cell(x,y).neighbours < 2 or self.cell(x,y).neighbours > 3:
self.cell(x,y).button.configure(bg = "chartreuse3")
if not self.cell(x,y).is_alive() and self.cell(x,y).neighbours == 3:
self.cell(x,y).button.configure(bg = "lightgreen")
def cell(self,x,y):
return self.matrix.cell(x,y)
def start (self): #start and stop set the boolean for the loop. They work and switch the state properly
self.is_running = True
self.playbutton.configure(text=str(self.is_running), command =self.stop)
def stop (self):
self.is_running = False
self.playbutton.configure(text=str(self.is_running), command =self.start)
#Test program. I can't make the loop work. Manual update via next button works however
root = Tk()
conway = Conway(root)
root.after(1000, conway.play())
root.mainloop()
The Matrix(仅限感兴趣的读者):
from tkinter import *
from random import randint
class Cell:
def __init__(self,master, cell_size = 1):
self.alive = False
self.neighbours = 0
# initializes a squares shaped button that fills the grid cell
self.frame = Frame(master, width= cell_size*16, height = cell_size*16)
self.button = Button(self.frame, text = self.neighbours, command = self.toggle, bg ="lightgray")
self.frame.grid_propagate(False)
self.frame.columnconfigure(0, weight=1)
self.frame.rowconfigure(0,weight=1)
self.button.grid(sticky="wens")
def is_alive(self):
return self.alive
def add_neighbour(self):
self.neighbours += 1
def toggle (self):
if self.is_alive() :
self.alive = False
self.button.configure( bg = "lightgray")
else:
self.alive = True
self.button.configure( bg = "green2")
class ButtonMatrix:
def __init__(self, master, size = 3, cell_size = 3):
self.master = master
self.size = size
self.cell_size = cell_size
self.cells = []
for x in range (self.size):
row = []
self.cells.append(row)
self.set_cells()
def cell(self, x, y):
return self.cells[x][y]
def set_cells(self):
for x in range (self.size):
for y in range (self.size):
self.cells[x] += [Cell(self.master, self.cell_size)]
self.cell(x,y).frame.grid(row=x,column=y)
def count_neighbours(self): # Checks 8 sourounding neighbours for their stats and sets a neighbour counter
for x in range(self.size):
for y in range(self.size):
self.cell(x,y).neighbours = 0
if y < self.size-1:
if self.cell(x,y+1).is_alive(): self.cell(x,y).add_neighbour() # Right
if x > 0 and self.cell(x-1,y+1).is_alive(): self.cell(x,y).add_neighbour() #Top Right
if x < self.size-1 and self.cell(x+1,y+1).is_alive(): self.cell(x,y).add_neighbour() #Bottom Right
if x > 0 and self.cell(x-1,y).is_alive(): self.cell(x,y).add_neighbour()# Top
if x < self.size-1 and self.cell(x+1,y).is_alive():self.cell(x,y).add_neighbour() #Bottom
if y > 0:
if self.cell(x,y-1).is_alive(): self.cell(x,y).add_neighbour() # Left
if x > 0 and self.cell(x-1,y-1).is_alive(): self.cell(x,y).add_neighbour() #Top Left
if x < self.size-1 and self.cell(x+1,y-1).is_alive(): self.cell(x,y).add_neighbour() #Bottom Left
self.cell(x,y).button.configure(text = self.cell(x,y).neighbours)
def randomize (self):
for x in range(self.size):
for y in range(self.size):
if self.cell(x,y).is_alive(): self.cell(x,y).toggle()
rando = randint(0,2)
if rando == 1: self.cell(x,y).toggle()
答案 0 :(得分:2)
您的代码存在两个问题:
root.after(1000, conway.play())
首先,你没有告诉Tkinter在1秒后拨打conway.play
,你现在正在调用conway.play()
,返回None
,然后告诉Tkinter调用{{ 1秒后1}}你想传递这个功能,而不是叫它:
None
同时,root.after(1000, conway.play)
并不意味着“每个 1000ms调用此函数”,这意味着“在1000ms之后调用此函数一次,然后再不再调用”。解决这个问题的简单方法就是让函数再次在另一个1000毫秒内再次调用:
after
the docs for after
中解释了这一点:
此方法注册将在给定的毫秒数后调用的回调函数。 Tkinter只保证不会在此之前调用回调;如果系统繁忙,实际延迟可能会更长。
每次调用此方法时,只会调用一次回调。要继续调用回调,您需要在其内部重新注册回调:
def play(self): # Calculates and sets the next generation. Itended to use in a loop
if self.is_running:
self.apply_ruleset()
self.matrix.count_neighbours()
self.apply_colors()
self.master.after(1000, self.play)
(我假设没有人会关心你的时间是否稍微漂移,所以一小时后你可能会有3549步或3627而不是3600 +/- 1。如果这是一个问题。你必须得到一点更复杂。)