Reputation: 23
I am trying to access from my .py file a button/label defined in .kv file by its ID and change its 'text' value. So I wrote in my build function:
#self.root.ids.button.text='newValue'
it says AttributeError: 'NoneType' object has no attribute 'ids'
I have tried many ways to access 'self.root' from other places in my class ,but none of them worked.
I wonder why I have no self.root in my class?
This is my kv file:
<MyRun>:
BoxLayout:
id:bx1
orientation: 'vertical'
spacing: 10
padding: [20]
canvas:
Color:
rgba: .6, .6, .6, .3
Rectangle:
size: root.size
source: 'pic\germanFlag.png'
ActionBar:
ActionView:
id: av
ActionPrevious:
with_previous: False
title: 'DeutschLerne'
Label:
id:qtitle
text: 'Percentage of Question Answered:{}%'.format(int(7))
font_size: '30sp'
size_hint_y: None
height: '48dp'
Label:
id:qbody
text: 'The answer is '+('{}'.format(str("Richtig!")) if 1>0 else '{}'.format(str("Falsch!")))
color: [.3, 1, .5, 1] if 1>0 else [1, .2, .3, 1]
font_size: '30sp'
size_hint_y: None
height: '48dp'
Widget:
canvas:
Color:
rgba: .6 , .6 , .6 , .3
Rectangle:
source: "pic\questionCanvas.png"
size: [self.width,self.height*3]
pos: [self.x,self.y-300]
BoxLayout:
id:bx2
spacing: 10
padding: [10, 200 , 10 , 0]
Button:
id:selA
text: 'A'
size_hint_y: None
size_hint_x: .5
on_release: app.answer(self.text)
on_release: app.disableButton(self)
Button:
id:selB
text: 'B'
size_hint_y: None
size_hint_x: .5
on_release: app.answer(self.text)
on_release: app.disableButton(self)
Button:
id:selC
text: 'C'
size_hint_y: None
size_hint_x: .5
on_release: app.answer(self.text)
on_release: app.disableButton(self)
Button:
id:selD
text: 'D'
size_hint_y: None
size_hint_x: .5
on_release: app.answer(self.text)
on_release: app.disableButton(self)
#on_release: app.go_screen(0)
ProgressBar:
id: pb
size_hint_x: 1
size_hint_y: None
height: '48dp'
value: (app.time * 20) % 100.
This is my main class, Desutsch.py
from time import time
from kivy.app import App
from os.path import dirname, join
from kivy.properties import NumericProperty, StringProperty, BooleanProperty,\
ListProperty,OptionProperty
from kivy.clock import Clock
from kivy.animation import Animation
from kivy.uix.screenmanager import Screen
from kivy.uix.gridlayout import GridLayout
from kivy.lang import Builder
from functools import partial
from kivy.uix.boxlayout import BoxLayout
from kivy.app import App
import random
NUM_OF_NOUN = 416 #constant . don't change its value
class MyRun(BoxLayout):
pass
class DeutschApp(App):
index = NumericProperty(-1)
challenges = NumericProperty(0)
time = NumericProperty(0)
wl = ListProperty([])
len = 0
ans = [] #.[0] => answer [1:3]
ansID=[] #.[0] => answer [1:3]
order=[] #random list(1~4)
def build(self):
Builder.load_file('Question.kv')
self.title = 'Destsch Lernen'
Clock.schedule_interval(self._update_clock, 1 / 60.)
self.screens = {}
self.available_screens = sorted([
'Menu','Question'])
len = self.loadWordList('default.txt')
self.question(len)
self.root.ids.selA.text='newValue'
return MyRun()
def go_screen(self, idx):
self.index = idx
self.root.ids.sm.switch_to(load_screen(idx), direction='left')
def load_screen(self, index):
if(0==index):
screen = Builder.load_file('Question.kv')
if(1==index):
screen = Builder.load_file('Menu.kv')
self.screens[index] = screen
return screen
#load question from local file
def loadWordList(self,WordList):
fd = open (WordList,'r')
fd.readline()
for line in fd:
#line.split("|"):id|german|translation|[sentence1^^sen2^^]|hisCount|dailyCount|percentage
line = line.rstrip("\n")
tmp = line.split('|')
tmp[3] = tmp[3].replace("[", "")
tmp[3] = tmp[3].replace("]", "")
sen = tmp[3].split('^^')
self.wl.append({'id': int(tmp[0]), 'german': tmp[1],'translation': tmp[2], 'sentences': sen, 'hisCount': int(tmp[4]), 'dailyCount': int(tmp[5]), 'percentage':int(tmp[-1]) })
#sentence encode not good
print tmp[0]
self.len = int(tmp[0]) #self.len = self.len+1
print self.len
self.question(self.len)
return self.len
def question(self,len):
x = random.randint(0,len)
ans = self.ans
ansID = self.ansID
#id0~416 =nouns #Nouns self.wl[x].get('german')
if x in range(0,NUM_OF_NOUN+1):
qType = 0 #0=def , 1=senten 2=pic qType= random.randint(0,2)
if (0==qType):
ans.append({'id':x , 'sel':self.wl[x].get('translation')})
ansID.append( int(x) )
for all in range(0,3):
y = random.randint(0,NUM_OF_NOUN+1)
while( (y in ansID) or (y not in range(0,NUM_OF_NOUN+1)) ):
y = random.randint(0,NUM_OF_NOUN+1)
ans.append({'id':y , 'sel':self.wl[y].get('translation')})
ansID.append( int(y) )
print ans
#elif:
#else:
#assign selections to buttons randomly
order = self.RandomSelList
print order
def RandomSelList(self):
a = random.sample(range(4), 4)
return a
def checkAnswer(self,ansList,choice):
right = 0
print "++"
print ansList
print choice
return right
def answer(self,choice):
#print self.order[0]
self.checkAnswer(self.ans,choice)
print 'answer(%s)'%choice
def Test(len):
print random.randint(0,len)
def _update_clock(self, dt):
self.time = time()
#modify screen
def selChange(self,button,sel):
print 'selChange()'
print self
print self.root
print super
#self.root.ids.button.text='sel'
def disableButton(self,button):
button.disabled = True
print super
#Clock.schedule_interval(Test(len), 1)
if __name__=='__main__':
DeutschApp().run()
I'm new here . Sorry for the ugly codes. I am still learning how to ask a good question.
Upvotes: 2
Views: 3103
Reputation: 29488
The root attribute is set to whatever you return from the build method, so it doesn't exist when you try to access it (or specifically, has the default value of None instead).
You don't need it though, since you have a reference to the widget anyway. You can change the end of the build method to
root = MyRun()
root.ids.selA.text='newValue'
return root
Upvotes: 3