¿Por qué no puedo acceder a Screen.ids?

ACTUALIZAR:

La respuesta de Ryan P proporcionó la solución. Sin embargo, tomé esa solución y la cambié un poco, lanzando todos los datos que no se estaban inicializando correctamente en el método on_enter de la pantalla RootWidget. Esto ha funcionado muy bien.

Mi clase RootWidget estaba subclasificando Widget hasta el día de hoy, y no tuve problemas para acceder a sus identificadores para obtener el valor de “grilla”. Sin embargo, simplemente lo cambié a la subclase Pantalla, y ahora dice que los identificadores están vacíos por alguna razón … La pantalla tiene una identificación y todo eso, pero por alguna razón, no está registrando que asigné un GridLayout al Id ” grid ” en el archivo kv. puede alguien decirme por que?

El rastreo:

[INFO ] [Logger ] Record log in /home/yerman/.kivy/logs/kivy_14-11-13_201.txt [INFO ] Kivy v1.9.0-dev [INFO ] [Python ] v2.7.6 (default, Mar 22 2014, 22:59:56) [GCC 4.8.2] [INFO ] [Factory ] 172 symbols loaded [INFO ] [Image ] Providers: img_tex, img_dds, img_pygame, img_pil, img_gif (img_sdl2, img_ffpyplayer ignored) [INFO ] [Window ] Provider: pygame(['window_egl_rpi'] ignored) [WARNING] [WinPygame ] Video: failed (multisamples=2) [WARNING] [WinPygame ] trying without antialiasing [INFO ] [GL ] OpenGL version  [INFO ] [GL ] OpenGL vendor  [INFO ] [GL ] OpenGL renderer  [INFO ] [GL ] OpenGL parsed version: 2, 1 [INFO ] [GL ] Shading version  [INFO ] [GL ] Texture max size  [INFO ] [GL ] Texture max units  [INFO ] [Window ] virtual keyboard not allowed, single mode, not docked [INFO ] [Text ] Provider: pygame(['text_sdl2'] ignored) {} #<<< note the emtpy ids I printed out Traceback (most recent call last): File "main.py", line 169, in  MineSweeperApp().run() File "/usr/lib/python2.7/dist-packages/kivy/app.py", line 799, in run root = self.build() File "main.py", line 163, in build return Manager() File "/usr/lib/python2.7/dist-packages/kivy/uix/screenmanager.py", line 844, in __init__ super(ScreenManager, self).__init__(**kwargs) File "/usr/lib/python2.7/dist-packages/kivy/uix/floatlayout.py", line 66, in __init__ super(FloatLayout, self).__init__(**kwargs) File "/usr/lib/python2.7/dist-packages/kivy/uix/layout.py", line 66, in __init__ super(Layout, self).__init__(**kwargs) File "/usr/lib/python2.7/dist-packages/kivy/uix/widget.py", line 269, in __init__ Builder.apply(self) File "/usr/lib/python2.7/dist-packages/kivy/lang.py", line 1837, in apply self._apply_rule(widget, rule, rule) File "/usr/lib/python2.7/dist-packages/kivy/lang.py", line 1942, in _apply_rule child = cls(__no_builder=True) File "main.py", line 43, in __init__ self.grid = self.ids["grid"] KeyError: 'grid' 

archivo kv:

 #:kivy 1.8.0 : GridLayout: id: grid size: root.size cols: root.sides : background_color: 1, 1, 1, 1 background_disabled_down: "kivy_white_bg.png" on_press: self.parent.parent.sweep(self) : background_color: 1, 1, 1, 1 background_disabled_down: "kivy_white_bg.png" on_press: self.parent.parent.sweep(self) : anchor_x: 'center' anchor_y: 'center' BoxLayout: size: root.size orientation: 'vertical' padding_bottom: '20dp' Label: font_size: '20dp' text: root.text BoxLayout: size_hint: 1, .3 spacing: 10 padding: 10 Button: size_hint: .4, 1 font_size: '20dp' text: "yes" on_press: app.stop(); app.run() Button: size_hint: .4, 1 font_size: '20dp' text: "no" on_press: root.quit() : GridLayout: rows: 2 Button: text: "8x8" on_press: root.manager.current = 'game_screen' Button: text: "16x16" on_press: root.manager.current = 'game_screen' Button: text: "30x16" on_press: root.manager.current = 'game_screen' Button: text: "custom" on_press: root.manager.current = 'game_screen' : id: _manager menu: menu game: game current: menu_screen Menu: id: menu manager: _manager name: 'menu_screen' RootWidget: id: game manager: _manager name: 'game_screen' 

main.py:

 #!/usr/bin/env python from random import sample import sys import kivy kivy.require('1.8.0') from kivy.app import App from kivy.core.window import Window from kivy.uix.widget import Widget from kivy.uix.button import Button from kivy.properties import NumericProperty, ListProperty, StringProperty, ObjectProperty from kivy.uix.gridlayout import GridLayout from kivy.uix.modalview import ModalView from kivy.uix.screenmanager import ScreenManager, Screen from kivy.clock import Clock class Blank(Button): index = ListProperty([0, 0]) count = NumericProperty(0) def __init__(self, **kwargs): super(Blank, self).__init__(**kwargs) class Mine(Button): index = ListProperty([0, 0]) count = NumericProperty(0) # not really necessary def __init__(self, **kwargs): super(Mine, self).__init__(**kwargs) class RootWidget(Screen): sides = NumericProperty(10) mine_count = NumericProperty(20) def __init__(self, **kwargs): super(RootWidget, self).__init__(**kwargs) self.grid = self.ids["grid"] # generate random mine indices mines = sample(xrange(self.sides**2), self.mine_count) x, y = -1, 0 for i in xrange(self.sides**2): if x == self.sides - 1: x = 0 y += 1 else: x += 1 if i not in mines: b = Blank(index=[x, y]) else: b = Mine(index=[x, y]) self.grid.add_widget(b) # record mine, blank and safe blank indices self.all_btns = [c.index for c in self.grid.children] self.mines = [c.index for c in self.grid.children if isinstance(c, Mine)] self.blanks = [c.index for c in self.grid.children if isinstance(c, Blank)] # a safe blank has no adjacent mines self.safe_blanks = [c.index for c in self.grid.children if self.is_safe(c)] # give each btn an 'adjacent mines count' for x, y in self.all_btns: btn = self.get_child_by_index([x, y]) for index in self.field(x, y): if index in self.mines: btn.count += 1 def field(self, x, y): """ the minefield surrounding a btn """ field = [[x-1, y], [x+1, y], [x, y+1], [x, y-1], [x+1, y+1], [x-1, y-1], [x+1, y-1], [x-1, y+1]] get = self.get_child_by_index return [i for i in field if i in self.all_btns and get(i).disabled == False] def sweep(self, instance): instance.disabled = True if instance.index in self.mines: print "Boom!" # It's a mine! You lose instance.text = "Boom!" self.game_over() pressed = sum(1 for c in self.grid.children if c.disabled == True) print pressed if self.sides**2 - pressed == self.mine_count: self.game_over(win=True) if instance.count > 0: instance.text = str(instance.count) instance.disabled = True return else: x, y = instance.index for index in self.field(x, y): if index not in self.mines: blank = self.get_child_by_index(index) blank.disable = True if blank.count > 0: blank.text = str(blank.count) self.sweep(blank) def is_safe(self, btn): x, y = btn.index for index in self.field(x, y): if index in self.mines: return False return True def get_child_by_index(self, index): for child in self.grid.children: if child.index == index: return child def game_over(self, q=False, win=False): if q == True: sys.exit() if win == True: result = "Win" elif win == False: result = "lost" view = TryAgain( size_hint = (None, None), width = self.width/2, height = self.height/2, center = self.center, text = "You {}! Try Again?".format(result)) view.open() class TryAgain(ModalView): text = StringProperty('') def quit(self): sys.exit() class Menu(Screen): pass class Manager(ScreenManager): menu = ObjectProperty(None) game = ObjectProperty(None) class MineSweeperApp(App): def build(self): return Manager() if __name__ == "__main__": MineSweeperApp().run() 

Las reglas de kv no se aplican hasta que el Widget original haya terminado de crear instancias. En este caso, su widget de Manager es el widget inicial; a su vez, crea otros widgets, incluido RootWidget . ¡Esto significa que en su RootWidget.__init__ los ids todavía no están RootWidget.__init__ ! Serán tan pronto como el Manager termine de crear instancias, por lo que el mejor enfoque es retrasar el rest de su inicialización, de este modo:

 class RootWidget(Screen): def __init__(self, **kwargs): super(RootWidget, self).__init__(**kwargs) Clock.schedule_once(self._finish_init) def _finish_init(self, dt): self.grid = self.ids.grid # etc