我正在尝试用kivy编写minesweeper,并希望从Cell类中访问GameBoard类中的单元列表。我在扫雷器窗口中单击一个单元,这会产生错误。我是新手,但是我认为Ids是我要这样做的方式。
错误提示 AttributeError:“超级”对象没有属性“ getattr ”
我正在使用Python 3.7.3
我查看了有关使用ID或类似错误的所有问题,但是我没有遇到问题的答案,或者没有将它们识别为答案。
我尝试使用root,不使用root,将id作为字符串,不将id作为字符串以及许多其他小的更改来尝试修复它。
这是我正在使用的代码(.py):
import time
import random
import kivy
from kivy.app import App
from kivy.uix.button import Label
from kivy.uix.button import Button
from kivy.uix.gridlayout import GridLayout
from kivy.core.window import Window
class Cell(Button):
def __init__(self, text, loc, board, **kwargs):
super(Cell, self).__init__(**kwargs)
self.size = (25,25)
self.board = board
self.loc = loc
self.text = text
self.val = 0
self.bind(on_touch_up = self.onPress)
self.visible = False
self.app = App.get_running_app()
def onPress(self, instance, touch):
if self.collide_point(*touch.pos):
if self.visible == False:
self.visible = True
if touch.button == 'right':
if self.text == '!':
self.text = '?'
else:
self.text = '!'
elif touch.button == 'left':
self.text = self.val
if self.val == 'X':
None
elif self.val == '0':
self.revealNeighbors(self.loc[0],self.loc[1])
else:
None
def revealNeighbors(self,y,x):
for i in range(-1,2):
for j in range(-1,2):
if (0 <= (self.loc[0] + i) < self.board[0]) and (0 <= (self.loc[1] + j) < self.board[1]):
print(self)
if self.app.root.ids.myboard.cells[i][j].visible != True:
self.app.ids.myboard.cells[i][j].visible = True
self.app.ids.myboard.cells[i][j].text = self.app.ids.myboard.cells[i][j].val
if self.app.ids.myboard.cells[i][j].val == '0':
self.app.root.ids.myboard.cells[i][j].revealNeighbors(self.app.ids.myboard.cells[i][j],i,j)
None
class GameBoard(GridLayout):
def __init__(self, **kwargs):
id: myboard
name: "Board"
super(GameBoard, self).__init__(**kwargs)
self.row_force_default = True
self.row_default_height = 30
self.col_force_default = True
self.col_default_width = 30
self.cols = 30
self.rows = 16
Window.size = (self.cols * self.col_default_width, self.rows * self.row_default_height)
self.cells = list()
mines = 0
minelst = list()
self.score = 0
for i in range(self.rows):
temp = list()
for j in range(self.cols):
newCell = Cell(text = '0',loc = [i,j], board = [self.rows,self.cols])
temp.append(newCell)
self.add_widget(temp[-1])
self.cells.append(temp)
for k in range(mines):
randX = random.randint(0,self.cols - 1)
randY = random.randint(0,self.rows - 1)
while self.cells[randY][randX].text == 'X':
randX = random.randint(0,self.cols - 1)
randY = random.randint(0,self.rows - 1)
self.cells[randY][randX].text = 'X'
temp = list()
temp.append(randY)
temp.append(randX)
minelst.append(temp)
minelst.sort()
for mine in minelst:
if mine[0] == 0: # first row
if mine[1] == 0: # top-left corner
if self.cells[0][1].text != 'X':
self.cells[0][1].text = str(int(self.cells[0][1].text) + 1)
if self.cells[1][0].text != 'X':
self.cells[1][0].text = str(int(self.cells[1][0].text) + 1)
if self.cells[1][1].text != 'X':
self.cells[1][1].text = str(int(self.cells[1][1].text) + 1)
elif mine[1] == (self.cols -1): # top-right corner
if self.cells[0][self.cols -2].text != 'X':
self.cells[0][self.cols -2].text = str(int(self.cells[0][self.cols -2].text) + 1)
if self.cells[1][self.cols -1].text != 'X':
self.cells[1][self.cols -1].text = str(int(self.cells[1][self.cols -1].text) + 1)
if self.cells[1][self.cols -2].text != 'X':
self.cells[1][self.cols -2].text = str(int(self.cells[1][self.cols -2].text) + 1)
else:
if self.cells[0][mine[1]-1].text != 'X':
self.cells[0][mine[1]-1].text = str(int(self.cells[0][mine[1]-1].text) + 1)
if self.cells[0][mine[1]+1].text != 'X':
self.cells[0][mine[1]+1].text = str(int(self.cells[0][mine[1]+1].text) + 1)
for i in range(3):
if self.cells[1][(mine[1]-1)+i].text != 'X':
self.cells[1][(mine[1]-1)+i].text = str(int(self.cells[1][(mine[1]-1)+i].text) + 1)
elif mine[0] == (self.rows -1): # bottom row
if mine[1] == 0: # bottom-left corner
if self.cells[self.rows -1][1].text != 'X':
self.cells[self.rows -1][1].text = str(int(self.cells[self.rows -1][1].text) + 1)
if self.cells[self.rows -2][0].text != 'X':
self.cells[self.rows -2][0].text = str(int(self.cells[self.rows -2][0].text) + 1)
if self.cells[self.rows -2][1].text != 'X':
self.cells[self.rows -2][1].text = str(int(self.cells[self.rows -2][1].text) + 1)
elif mine[1] == (self.cols -1): # bottom-right corner
if self.cells[self.rows -1][self.cols -2].text != 'X':
self.cells[self.rows -1][self.cols -2].text = str(int(self.cells[self.rows -1][self.cols -2].text) + 1)
if self.cells[self.rows -2][self.cols -1].text != 'X':
self.cells[self.rows -2][self.cols -1].text = str(int(self.cells[self.rows -2][self.cols -1].text) + 1)
if self.cells[self.rows -2][self.cols -2].text != 'X':
self.cells[self.rows -2][self.cols -2].text = str(int(self.cells[self.rows -2][self.cols -2].text) + 1)
else:
if self.cells[self.rows -1][mine[1]-1].text != 'X':
self.cells[self.rows -1][mine[1]-1].text = str(int(self.cells[self.rows -1][mine[1]-1].text) + 1)
if self.cells[self.rows -1][mine[1]+1].text != 'X':
self.cells[self.rows -1][mine[1]+1].text = str(int(self.cells[self.rows -1][mine[1]+1].text) + 1)
for i in range(3):
if self.cells[self.rows -2][(mine[1]-1)+i].text != 'X':
self.cells[self.rows -2][(mine[1]-1)+i].text = str(int(self.cells[self.rows -2][(mine[1]-1)+i].text) + 1)
elif mine[1] == 0: # left column w/o corners
if self.cells[mine[0]-1][0].text != 'X':
self.cells[mine[0]-1][0].text = str(int(self.cells[mine[0]-1][0].text) + 1)
if self.cells[mine[0]+1][0].text != 'X':
self.cells[mine[0]+1][0].text = str(int(self.cells[mine[0]+1][0].text) + 1)
for i in range(3):
if self.cells[(mine[0]-1)+i][1].text != 'X':
self.cells[(mine[0]-1)+i][1].text = str(int(self.cells[(mine[0]-1)+i][1].text)+1)
elif mine[1] == (self.cols -1): # right column w/o corners
if self.cells[mine[0]-1][self.cols -1].text != 'X':
self.cells[mine[0]-1][self.cols -1].text = str(int(self.cells[mine[0]-1][self.cols -1].text) + 1)
if self.cells[mine[0]+1][self.cols -1].text != 'X':
self.cells[mine[0]+1][self.cols -1].text = str(int(self.cells[mine[0]+1][self.cols -1].text) + 1)
for i in range(3):
if self.cells[(mine[0]-1)+i][self.cols -2].text != 'X':
self.cells[(mine[0]-1)+i][self.cols -2].text = str(int(self.cells[(mine[0]-1)+i][self.cols -2].text)+1)
else: # interior mines
for i in range(3):
if self.cells[mine[0]-1][(mine[1]-1)+i].text != 'X':
self.cells[mine[0]-1][(mine[1]-1)+i].text = str(int(self.cells[mine[0]-1][(mine[1]-1)+i].text)+1)
if self.cells[mine[0]+1][(mine[1]-1)+i].text != 'X':
self.cells[mine[0]+1][(mine[1]-1)+i].text = str(int(self.cells[mine[0]+1][(mine[1]-1)+i].text)+1)
if self.cells[mine[0]][mine[1]-1].text != 'X':
self.cells[mine[0]][mine[1]-1].text = str(int(self.cells[mine[0]][mine[1]-1].text)+1)
if self.cells[mine[0]][mine[1]+1].text != 'X':
self.cells[mine[0]][mine[1]+1].text = str(int(self.cells[mine[0]][mine[1]+1].text)+1)
for i in range(self.rows):
for j in range(self.cols):
self.cells[i][j].val = self.cells[i][j].text
self.cells[i][j].text = '?'
class MineSweeper(App):
def build(self):
self.root = GameBoard()
return self.root
mineSweeper = MineSweeper()
mineSweeper.run()
当我尝试访问ID时,会得到以下追溯:
Traceback (most recent call last):
File "kivy/properties.pyx", line 860, in kivy.properties.ObservableDict.__getattr__
KeyError: 'myboard'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "MineSweeper.py", line 183, in <module>
mineSweeper.run()
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/kivy/app.py", line 855, in run
runTouchApp()
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/kivy/base.py", line 504, in runTouchApp
EventLoop.window.mainloop()
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/kivy/core/window/window_sdl2.py", line 747, in mainloop
self._mainloop()
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/kivy/core/window/window_sdl2.py", line 479, in _mainloop
EventLoop.idle()
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/kivy/base.py", line 342, in idle
self.dispatch_input()
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/kivy/base.py", line 327, in dispatch_input
post_dispatch_input(*pop(0))
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/kivy/base.py", line 233, in post_dispatch_input
listener.dispatch('on_motion', etype, me)
File "kivy/_event.pyx", line 707, in kivy._event.EventDispatcher.dispatch
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/kivy/core/window/__init__.py", line 1406, in on_motion
self.dispatch('on_touch_up', me)
File "kivy/_event.pyx", line 707, in kivy._event.EventDispatcher.dispatch
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/kivy/core/window/__init__.py", line 1442, in on_touch_up
if w.dispatch('on_touch_up', touch):
File "kivy/_event.pyx", line 707, in kivy._event.EventDispatcher.dispatch
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/kivy/uix/widget.py", line 571, in on_touch_up
if child.dispatch('on_touch_up', touch):
File "kivy/_event.pyx", line 703, in kivy._event.EventDispatcher.dispatch
File "kivy/_event.pyx", line 1214, in kivy._event.EventObservers.dispatch
File "kivy/_event.pyx", line 1138, in kivy._event.EventObservers._dispatch
File "MineSweeper.py", line 37, in onPress
self.revealNeighbors(self.loc[0],self.loc[1])
File "MineSweeper.py", line 46, in revealNeighbors
if self.app.root.ids.myboard.cells[i][j].visible != True:
File "kivy/properties.pyx", line 863, in kivy.properties.ObservableDict.__getattr__
AttributeError: 'super' object has no attribute '__getattr__'
答案 0 :(得分:0)
Traceback (most recent call last):
File "kivy/properties.pyx", line 860, in kivy.properties.ObservableDict.__getattr__
KeyError: 'myboard'
发生KeyError
是因为在字典类型属性myboard
中找不到self.ids
。
由于您的Kivy应用未使用kv文件,因此self.ids
为空。
当解析您的kv文件时,kivy会收集所有标有的小部件 id,并将其放在此 self.ids 字典类型属性中。
您的Kivy应用程序中存在一些问题。
解决方案是使用ids
在Python脚本中创建自己的self.ids.myboard = self
class GameBoard(GridLayout):
def __init__(self, **kwargs):
super(GameBoard, self).__init__(**kwargs)
self.ids.myboard = self # create self.ids.myboard
...
应用修订1后,应用崩溃,并显示以下AttributeError。
self.app.ids.myboard.cells[i][j].visible = True
AttributeError: 'MineSweeper' object has no attribute 'ids'
该应用程序类没有属性ids
。 ids
仅存在于根对象中。
解决方法是使用App.get_running_app()
获取应用程序的实例,并使用root.ids.myboard
获取myboard
的引用并将其保存到本地属性。
def revealNeighbors(self, y, x):
...
myboard = App.get_running_app().root.ids.myboard
if myboard.cells[i][j].visible != True:
myboard.cells[i][j].visible = True
myboard.cells[i][j].text = myboard.cells[i][j].val
if myboard.cells[i][j].val == '0':
myboard.cells[i][j].revealNeighbors(myboard.cells[i][j], i, j)
...
应用修订1和2之后,应用崩溃,并出现以下TypeError。
myboard.cells[i][j].revealNeighbors(myboard.cells[i][j], i, j)
TypeError: revealNeighbors() takes 3 positional arguments but 4 were given
解决方法是通过i
和j
。
def revealNeighbors(self, y, x):
...
myboard = App.get_running_app().root.ids.myboard
if myboard.cells[i][j].visible != True:
myboard.cells[i][j].visible = True
myboard.cells[i][j].text = myboard.cells[i][j].val
if myboard.cells[i][j].val == '0':
myboard.cells[i][j].revealNeighbors(i, j)
...