Kivy: Radio button correct implementation - python

My App has 3 screens to navigate through with the 'ActionBar'. I have named each screen in kv file, one is 'track' the other 'pess'. These are the two I need help with.
I created a radiobutton widget in my 'pess' screen class (pictures below) So I could add email address.
In my 'track' screen class I have all the data I'd like to send over email but I think I'm over complicating things. I want to link the active radiobutton from my 'pess' screen to my 'track' screen def send function...
my Main.py looks like this
class ScreenGenerator(ScreenManager):
pass
class PessQuestions(Screen):
email = {}
path = ''
def loadEmails(self, *args):
self.path = App.get_running_app().user_data_dir + '/'
try:
with open(self.path + 'email.json', 'r') as data:
self.email = json.load(data)
except FileNotFoundError:
pass
def saveEmails(self, *args):
print(self.ids.name.text, type(self.ids.name.text))
print(self.ids.address.text, type(self.ids.address.text))
self.email[self.ids.name.text] = self.ids.address.text
self.path = App.get_running_app().user_data_dir + '/'
with open(self.path + 'email.json', 'w') as email_address_json:
json.dump(self.email, email_address_json)
print('saveEmails')
self.ids.address.text = ''
self.ids.name.text = ''
self.ids.info.clear_widgets()
self.on_pre_enter() # refresh screen
def delete_email(self, check):
address = check.ids.who_name.text
del self.email[address]
self.ids.info.remove_widget(check)
self.saveEmails()
##########################################################
########### PRE ENTER ####################################
def on_pre_enter(self):
self.ids.info.clear_widgets()
self.loadEmails()
try:
for name, mail in self.email.items():
self.ids.info.add_widget(Checkboxes(name=name, mail=mail, email=self.email))
except ValueError:
print('VALUE ERROR: Label.text accept only "str"')
self.ids.pess_date.text = strftime('[b]%A[/b], %B %Y') # time and date
##########################################################
########### PRE LEAVE ####################################
def on_pre_leave(self):
self.ids.info.clear_widgets()
self.saveEmails()
class Checkboxes(BoxLayout):
def __init__(self, name='', mail='', email='', **kwargs):
super().__init__(**kwargs)
self.ids.who_name.text = name
self.ids.who_email.text = mail
def on_checkbox_Active(self, checkboxInstance, isActive):
address = ''
if isActive:
'''
Email is used for recipient
'''
name = self.ids.who_name.text
email = self.ids.who_email.text
print('Email Set!')
return email
else:
'''
Nothing happens, email is not used
'''
##########################################################
######## TRACKERS WINDOWS ################################
##########################################################
class Trackers(Screen):
email = {'davi': 'example#gmail.com'}
storage = {}
pess_storage = {}
path = ''
def on_pre_enter(self):
self.path = App.get_running_app().user_data_dir + '/'
self.loadData()
for tracker, num in self.storage.items():
self.ids.track.add_widget(Tracker(text=tracker, number=num))
def on_pre_leave(self):
self.ids.track.clear_widgets()
self.saveData()
def saveData(self, *args):
with open(self.path + 'data.json', 'w') as data:
json.dump(self.storage, data)
def loadData(self, *args):
try:
with open(self.path + 'data.json', 'r') as data:
self.storage = json.load(data)
print(self.storage)
except FileNotFoundError:
pass
def savePESS(self, PESS):
self.pess_storage['physical'] = PESS.ids.phy_text.text
self.pess_storage['emotional'] = PESS.ids.emo_text.text
self.pess_storage['spiritual'] = PESS.ids.spi_text.text
self.pess_storage['sexual'] = PESS.ids.sex_text.text
self.pess_storage['comment'] = PESS.ids.comment.text
def save_text(self, tracker, text_input, *args):
tracker.ids.label.text = text_input.text
self.storage[text_input.text] = '0'
self.saveData()
self.loadData()
print('testing')
def send(self, PESS):
self.path = App.get_running_app().user_data_dir + '/'
with open(self.path + 'bat', 'r') as bat:
login = bat.read()
davi = self.email['davi']
mail = PESS.ids.who_email.text
#kevin = self.email['kevin'] # instead of this I'd like to have this variable linked to
gmail = GMail(davi, login)
day = strftime("%a, %b %d, %Y")
tracker_message = 'PESS\n'
subject_message = f"Subject: PESS {day}"
for pess, txt in self.pess_storage.items():
tracker_message += f"\t{pess.title()}: {txt}\n"
for tracker, numbers in self.storage.items():
tracker_message += f"\n{numbers} ---> {tracker}\n"
message = f"{subject_message}\n\n{tracker_message}"
msg = Message(f'PESS | {day}', to=mail, text=message)
gmail.send(msg)
self.sent_confirmation(f'{self.ids.who_name.text}: {mail}')
def sent_confirmation(self, recipient):
box = BoxLayout(orientation='vertical', padding=40, spacing=5)
pop = Popup(title='Email Sent', content=box, size_hint=(None,None), size=(self.width, self.width/2))
info = Label(text=f'Congrats, {recipient} has recieved an email.')
box.add_widget(info)
pop.open()
self.saveData()
class Tracker(BoxLayout):
def __init__(self, text='', number='', **kwargs):
super().__init__(**kwargs)
self.ids.label.text = text
self.ids.count_add.text = number
class Pess(App):
def build(self):
Config.set('graphics', 'width', '600')
Config.set('graphics', 'height', '800')
from kivy.core.window import Window
Window.clearcolor = get_color_from_hex('#262829')
return ScreenGenerator()
if __name__ == '__main__':
Pess().run()
kv file
#: import rgba kivy.utils.get_color_from_hex
#: import CheckBox kivy.uix.checkbox
<Label>:
font_size: '17dp'
<MenuButton#ButtonBehavior+Label>:
canvas.before:
Color:
rgba: 0.1, 0.5, 0.7, 1
Ellipse:
pos: self.pos
size: self.height, self.height
Ellipse:
pos: self.x + self.width - self.height, self.y
size: self.height, self.height
Rectangle:
pos: self.x + self.height / 2, self.y
size: self.width - self.height, self.height
<RoundButton#ButtonBehavior+Label>:
canvas.before:
Color:
rgba: 0.8, 0.3, 0.1, 1
Ellipse:
pos: self.width / 2.265, self.y + 130
size: self.height - self.height / 1.5, self.height / 3
<MenuButton2#ButtonBehavior+Label>:
canvas.before:
Color:
rgba: 0.8, 0.3, 0.1, 1
Ellipse:
pos: self.pos
size: self.height, self.height
Ellipse:
pos: self.x + self.width - self.height, self.y
size: self.height, self.height
Rectangle:
pos: self.x + self.height / 2, self.y
size: self.width - self.height, self.height
<FloatButton#ButtonBehavior+FloatLayout>:
id: float_root
size_hint: (None, None)
text: '[b]+[/b]'
font_size: '48dp'
btn_size: (140,140)
size: (140,140)
bg_color: (0.8, 0.3, 0.1, 1)
pos_hint: {'x': 5.4, 'y': .17}
Button:
text: float_root.text
font_size: '14dp'
#allow_stretch: True
markup: True
size_hint: (None, None)
size: float_root.btn_size
pos_hint: float_root.pos_hint
background_normal: ''
background_color: (0,1,0,0)
canvas.before:
Color:
rgba: float_root.bg_color
Ellipse:
pos: self.pos
size: self.size
<TrackerButton#Button>:
background_color: 0,0,0,0
<ScreenGenerator>:
Menu:
name: 'menu'
Trackers:
name: 'track'
PessQuestions:
name: 'pess'
<Menu>:
BoxLayout:
orientation: 'vertical'
padding: 20
spacing: 30
Image:
source: 'book.png'
allow_strech: True
Label:
canvas.before:
Color:
rgba: (1,1,1,.7)
Rectangle:
size: self.size
pos: self.pos
size_hint_y: None
height: 1
MenuButton:
text: 'Enter Trackers'
height: dp(60)
size_hint_y: None
background_image: ''
background_color: rgba('#637075')
on_release: app.root.current = 'track'
MenuButton:
text: 'Enter PESS'
height: dp(60)
size_hint_y: None
background_image: ''
background_color: rgba('#637075')
on_release: app.root.current = 'pess'
Label:
canvas.before:
Color:
rgba: (1,1,1,.7)
Rectangle:
size: self.size
pos: self.pos
size_hint_y: None
height: 1
Label:
id: time
text: ''
markup: True
<PessQuestions>:
BoxLayout:
orientation: 'vertical'
pos_hint: {'top': 1}
ActionBar:
height: self.minimum_height + dp(50)
size_hint_y: None
background_image: ''
background_color: rgba('#ffffff') # rgba('#0B3242')
ActionView:
ActionPrevious:
title: '[b]PESS[/b]'
font_size: '17dp'
color: rgba('#AFB7BA')
markup: True
on_release: app.root.current = 'track'
ActionButton:
text: 'SEND'
color: rgba('#AFB7BA')
on_release: app.root.get_screen('track').send(root) # if .send() function is on another class outside of 'class PessQuestions' use the .get_screen() to locate the right screen class
#on_release: app.root.send()
ActionButton:
text: 'TRACKER'
color: rgba('#AFB7BA')
on_release: app.root.current = 'track'
ActionButton:
text: 'HOME'
color: rgba('#AFB7BA')
on_release: app.root.current = 'menu'
BoxLayout:
orientation: 'vertical'
padding: dp(10)
spacing: dp(12)
pos_hint: {'top': 1}
TextInput:
id: phy_text
hint_text: 'Physical'
size_hint_y: None
height: self.minimum_height + dp(7)
multiline: False
TextInput:
id: emo_text
hint_text: 'Emotional'
size_hint_y: None
height: self.minimum_height + dp(7)
multiline: False
TextInput:
id: spi_text
hint_text: 'Spiritual'
size_hint_y: None
height: self.minimum_height + dp(7)
multiline: False
TextInput:
id: sex_text
hint_text: 'Sexual'
size_hint_y: None
height: self.minimum_height + dp(7)
multiline: False
TextInput:
id: comment
hint_text: 'Leave a comment'
size_hint_y: None
height: self.minimum_height + dp(100)
MenuButton:
id: save_pess
text: 'Save PESS'
height: dp(60)
size_hint_y: None
background_image: ''
on_press: self.text = 'SAVED!'
on_release: app.root.get_screen('track').savePESS(root)
MenuButton2:
text: 'Clear PESS'
height: dp(60)
size_hint_y: None
background_image: ''
on_press: root.ids.save_pess.text = 'Save PESS'
on_release: root.resetPESS()
MenuButton:
text: 'Send Report'
color: rgba('#AFB7BA')
height: dp(60)
size_hint_y: None
background_image: ''
on_release: app.root.get_screen('track').send(root) # if .send() function is on another class outside of 'class PessQuestions' use the .get_screen() to locate the right screen class
#on_release: app.root.send()
Label:
canvas.before:
Color:
rgba: (1,1,1,.7)
Rectangle:
size: self.size
pos: self.pos
size_hint_y: None
height: 1
Label:
text: '[b]Physical, Emotional, Spiritual, Sexual[/b] | These principles when lived with a full purpose of heart will invite the Holy Ghost into your lives.'
markup: True
text_size: self.width, None
size_hint: 1, None
height: self.texture_size[1]
Label:
id: pess_date
text: ''
markup: True
Label:
canvas.before:
Color:
rgba: (1,1,1,.7)
Rectangle:
size: self.size
pos: self.pos
size_hint_y: None
height: 1
# Label & Checkbox creation | for selecting email address
Label:
text: "EMAIL"
text_size: self.width, None
size_hint: 1, None
height: self.texture_size[1]
ScrollView:
BoxLayout:
id: info
orientation: 'vertical'
padding: dp(5)
spacing: dp(7)
#size_hint_y: None
#height: self.minimum_height + dp(50)
TextInput:
id: name
hint_text: 'Name'
size_hint_y: None
height: self.minimum_height + dp(7)
multiline: False
TextInput:
id: address
hint_text: 'Email Address'
size_hint_y: None
height: self.minimum_height + dp(7)
multiline: False
MenuButton:
id: save_email
text: 'Save Email'
height: dp(60)
size_hint_y: None
background_image: ''
on_release: root.saveEmails()
<Checkboxes>:
CheckBox:
group: 'emails'
color: .294, .761, .623
on_active: root.on_checkbox_Active(self, self.active)
#on_active: app.root.get_screen('pess').on_checkbox_Active(self, self.active)
size_hint_x: .50
Label:
id: who_name
text: ''
text_size: self.width, None
halign: 'left'
Label:
id: who_email
text: ''
text_size: self.width, None
halign: 'left'
Button:
text: '[b]X[/b]'
markup: True
size_hint_x: None
width: dp(20)
on_release: app.root.get_screen('pess').delete_email(root)
<Trackers>:
BoxLayout:
orientation: 'vertical'
ActionBar:
height: self.minimum_height + dp(50)
size_hint_y: None
background_image: ''
background_color: rgba('#ffffff') #rgba('#0B3242')
ActionView:
ActionPrevious:
title: '[b]TRACKERS[/b]'
font_size: '17dp'
color: rgba('#AFB7BA')
markup: True
on_release: app.root.current = 'pess'
ActionButton:
text: 'RESET'
color: rgba('#AFB7BA')
on_release: root.reset_pop()
ActionButton:
text: 'PESS'
color: rgba('#AFB7BA')
on_release: app.root.current = 'pess'
ActionButton:
text: 'HOME'
color: rgba('#AFB7BA')
on_release: app.root.current = 'menu'
ScrollView:
BoxLayout:
id: track
orientation: 'vertical'
padding: dp(10)
spacing: dp(15)
size_hint_y: None
height: self.minimum_height
BoxLayout:
size_hint_y: None
height: dp(100)
Button:
text: '+'
font_size: '56dp'
size_hint_y: None
background_image: ''
background_color: (0,0,0,0)
on_release: root.addWidget()
#BoxLayout:
#FloatButton:
# pos_hint_x: None
# pos_hint_y: None
# on_release: root.addWidget()
<Tracker>:
count_add: count_add
name: name
size_hint_y: None
height: 130
canvas.before:
Color:
rgba: 0.1, 0.5, 0.7, 1
Rectangle:
pos: self.pos[0] + self.height/2, self.pos[1]
size: self.size[0] - self.height, self.height
Ellipse:
pos: self.pos[0], self.pos[1]
size: self.height, self.height
Ellipse:
pos: self.pos[0] + self.width - self.height, self.pos[1]
size: self.height, self.height
TrackerButton:
text: '[b]X[/b]'
markup: True
size_hint_x: None
width: 120
on_release: app.root.get_screen('track').delete_storage(root)
Label:
id: name
canvas.before:
Color:
rgba: (1,1,1,.7)
Rectangle:
size: self.size
pos: self.pos
size_hint_x: None
width: 1
TrackerButton:
id: label
font_size: '16dp'
on_release: app.root.get_screen('track').change_name(root)
TrackerButton:
id: count_add
font_size: '16dp'
text: '0'
size_hint_x: None
width: 120
on_release: app.root.get_screen('track').add_num(root)
Label:
canvas.before:
Color:
rgba: (1,1,1,.7)
Rectangle:
size: self.size
pos: self.pos
size_hint_x: None
width: 1
TrackerButton:
text: '[b]-[/b]'
font_size: '24dp'
markup: True
size_hint_x: None
width: 120
on_release: app.root.get_screen('track').subtract_num(root)
I had my code running really well, but all of the email sending information was hardcoded. I wanted to give the user options to input an email address and send it to that address.
I added the class Checkboxes which get's created every time I add a name and email address and hit the "Save Email" It's grouped so they are radio buttons.
I can't seem to connect the email address to my send function on the class Trackers... I hope all of this makes some sense. I might be overly complicating things for myself. I could use some help please. Thank you.

Just came across this question and since I am short on time I wont be able to help you completely. If you ever want to access widgets inside and outside of your class screens you need to have a shared parent for the both of them. In your main py file you can have something like this defined.
class MainInterface(BoxLayout):
def __init__(self, **kwargs):
super(MainInterface, self).__init__(**kwargs)
class WindowManager(ScreenManager):
pass
class HomeWindow(Screen):
...
class TrackerWindow(Screen):
...
sm = WindowManager()
screens = [HomeWindow(name="Home"), TrackerWindow(name="TrackerWindow")]
for screen in screens:
sm.add_widget(screen)
class MyMainApp(App):
def build(self):
root = MainInterface()
return root
The way you use your kv file from now on will be different from what you are used to. Your kv file can look something like this. I'll be using different example uses for one button to save time for myself.
<MainInterface>:
WindowManager:
id: screenmanager
HomeWindow:
id: homewindow
...
Button:
pos_hint:{"x":0,"top":1}
size_hint: 0.125, 0.1
text: "Some Stuff"
font_size: (root.width**1 + root.height**1) / 10**2
on_release:
root.ids['trackerwindow'].send(YourData)
root.ids['homewindow'].access_user_inputs(self.parent.user_inputs)
root.ids['screenmanager'].transition.direction = "left"
root.ids['screenmanager'].current="TrackerWindow"
TrackerWindow:
id: trackerwindow
...
notice how on the homescreen button to get information from its own screen you can't just use root.access_user_inputs(root.user_inputs) you created a parent tree so you use self.parent if you want to access a function from your windowmanager you would do a similar set up but use self.parent.parent. I hope this helps and if you have questions please ask and I'll be able to further help you later.

Related

Kivy recycleview spacing issue when on android

So I have managed to get widgets of varying height into a recycleview and items can be added, this looked perfect on my PC but was very wrong when running on android. I re-built the app with buildozer to make sure it wasn't something to do with that, I put together the demo program seen below and ran it on both platforms, and experienced the same result. I have used the kivy inspector and not been able to see any values that are not what I didn't manually program. And unless I have missed one I have used dp(X) or 'Xdp' whenever needed.
Any help or tips will be apreciated, thank you :)
main.py
from random import randint
from kivy.app import App
from kivy.uix.label import Label
from kivy.clock import Clock
from kivy.graphics import Color, Rectangle
from kivy.uix.recycleview import RecycleView
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import StringProperty, ListProperty, NumericProperty
class NewPostGrid(BoxLayout):
votes_ = StringProperty()
message_id_ = StringProperty()
text_ = StringProperty()
group_ = StringProperty()
_size = ListProperty()
class SizeLabel(Label):
pass
class RV(RecycleView):
distance_to_top = NumericProperty()
scrollable_distance = NumericProperty()
def __init__(self, **kwargs):
super().__init__(**kwargs)
App.get_running_app().rv_data_list = []
def generate_post(self): # This is only to test posts with different line height
e = ['Test post ID: ', str(App.get_running_app().message_id_num)]
for i in range(randint(1, 8)): e.append('\n')
e.append('end of post')
return "".join(e)
def add(self):
l = len(App.get_running_app().rv_data_list)
text = self.generate_post()
sl = SizeLabel(text=text)
sl.texture_update()
print(sl.text)
App.get_running_app().rv_data_list.extend([{'message_id_': str(App.get_running_app().message_id_num),
'text_': text,
'_size': sl.texture_size,
'group_': str(App.get_running_app().message_id_num),
'votes_': str(20)}])
App.get_running_app().message_id_num = App.get_running_app().message_id_num + 1
def on_scrollable_distance(self, *args):
if self.scroll_y > 0:
self.scroll_y = (self.scrollable_distance - self.distance_to_top) / self.scrollable_distance
def on_scroll_y(self, *args):
self.distance_to_top = (1 - self.scroll_y) * self.scrollable_distance
#def adjust_vote_state(self, id_):
# for d in self.data:
# if d['text_'] == id_.text_:
# d['state'] == id_.ids.button_up.state
# id_.state = id_.ids.button_up.state
class DemoApp(App):
# One post format = {'message_id':0, 'text':'post_test_here','_size':[0,0], '_group':str(0), '_score':20}
# Text fromat string = [font=Nunito-Bold.ttf][color=161616]Someone:[/color][/font]\n
message_id_num = 0
rv_data_list = ListProperty()
pending_data = ListProperty()
def build(self):
#Clock.schedule_interval(self.add_log, .01)
Clock.schedule_interval(self.flush_pending_data, .250)
def up_vote(self, button, mode): # Not part of the problem
if button.state == 'down':
if mode == 'all':
print("+1 upvote for message index:" + str(button.parent.parent.message_id) + ' in all posts')
else:
print("+1 upvote for message index:" + str(button.parent.parent.message_id) + ' in top posts')
def down_vote(self, button, mode): # Not part of the problem
if button.state == 'down':
if mode == 'all':
print("-1 upvote for message index:" + str(button.parent.parent.message_id) + ' in all posts')
else:
print("-1 upvote for message index:" + str(button.parent.parent.message_id) + ' in top posts')
def flush_pending_data(self, *args):
if self.pending_data:
pending_data, self.pending_data = self.pending_data, []
self.rv_data_list.extend(pending_data)
def generate_post(self): # This is only to test posts with different line height
e = ['Test post ID: ', str(self.message_id_num)]
for i in range(randint(1, 8)): e.append('\n')
e.append('end of post')
return "".join(e)
def add_log(self, dt):
for i in range(10):
text = self.generate_post()
sl = SizeLabel(text=text)
sl.texture_update()
self.pending_data.append({'message_id_': str(self.message_id_num),
'text_': text,
'_size': sl.texture_size,
'group_': str(self.message_id_num),
'votes_': str(20)})
self.message_id_num = self.message_id_num + 1
if __name__ == '__main__':
DemoApp().run()
demo.kv
<SizeLabel>:
padding: "10dp", "12dp"
size_hint: 0.9, None
height: self.texture_size[1]
font_size: "12dp"
text_size: self.width, None
color: 0,0,0,1
multiline: True
markup: True
<NewPostGrid>:
spacing: "6dp"
message_id: root.message_id_
BoxLayout:
id: voting_menu
orientation: "vertical"
spacing: "2dp"
size_hint: .2, None
height: label.height
ToggleButton:
id: button_up
on_state: app.up_vote(self, 'all')
group: root.group_
#state: root.vote_state_up
text: "UP"
color: (1,1,1,1) if self.state=='normal' else (.8,0,0,1)
font_size: "10dp"
size_hint: 1, .3
background_color: .2, .2, .2, 0
#on_release: app.root.ids.rv.adjust_vote_state(root)
canvas.before:
Color:
rgba: (.1,.1,.1,1)
RoundedRectangle:
pos: self.pos
size: self.size
radius: [6,]
canvas:
Color:
rgba: (.2,.2,.2,1)
Line:
width: 1.4
rounded_rectangle:(self.x,self.y,self.width,self.height, 5)
Label:
id: vote_count
text: root.votes_
size_hint: 1, .4
multiline: False
ToggleButton:
id: button_down
on_state: app.down_vote(self, 'all')
group: root.group_
#state: root.vote_state_down
text: "DOWN"
color: (1,1,1,1) if self.state=='normal' else (.8,0,0,1)
font_size: "10dp"
size_hint: 1, .3
background_color: .2, .2, .2, 0
canvas.before:
Color:
rgba: (.1,.1,.1,1)
RoundedRectangle:
pos: self.pos
size: self.size
radius: [6,]
canvas:
Color:
rgba: (.2,.2,.2,1)
Line:
width: 1.4
rounded_rectangle:(self.x,self.y,self.width,self.height, 5)
Label:
id: label
text: root.text_
padding: "10dp", "12dp"
size_hint: .9, None
height: self.texture_size[1]
font_size: "12dp"
text_size: self.width, None
color: 0,0,0,1
multiline: True
markup: True
#on_texture_size: root.update_message_size(root.message_id, self.texture_size)
pos: self.x, self.y
canvas.before:
Color:
rgba: (0.8, 0.8, 0.8, 1)
RoundedRectangle:
size: self.texture_size
radius: [5, 5, 5, 5]
pos: self.x, self.y
canvas:
Color:
rgba:0.8,0,0,1
Line:
width: 1.4
rounded_rectangle:(self.x,self.y,self.width,self.height, 5)
BoxLayout:
orientation: 'vertical'
BoxLayout:
size_hint: 1, .1
orientation: 'horizontal'
Button:
text: 'Add widget to RV list'
on_release: rv.add()
ToggleButton:
id: active
text: 'active'
on_state: app.add_log(self)
RV:
id: rv
viewclass: 'NewPostGrid' # The view class is TwoButtons, defined above.
data: app.rv_data_list # the data is a list of dicts defined below in the RV class.
scroll_type: ['bars', 'content']
#on_scroll_y: app.fill_data(self, box)
scrollable_distance: box.height - self.height
bar_width: dp(2)
RecycleBoxLayout:
id: box
# This layout is used to hold the Recycle widgets
# default_size: None, dp(48) # This sets the height of the BoxLayout that holds a TwoButtons instance.
key_size: '_size'
default_size_hint: 1, None
size_hint_y: None
spacing: '16dp'
height: self.minimum_height # To scroll you need to set the layout height.
orientation: 'vertical'
padding: ['10dp', '20dp']
Image of app running on windows
Video of app running on android
Video of full app running (The code for the recycleview is identical)

How to get a kivy variable added to Screen from add widget()

So im trying to get a variable added to screen and the id fro that is in a widget Im going to add,
so if for example I have this:
from kivy.app import App
from kivy.lang import Builder
from kivy.properties import StringProperty
kv = """
Screen:
cal:cal
side: side
GridLayout:
rows: 1
cols:2
spacing:0
GridLayout:
rows: 5
cols:1
Button:
text: "Cube"
# on_press: app.mode = self.text
on_press: app.setMode(self)
Button:
text: "Cuboid"
on_press: app.setMode(self)
Button:
text: "Cylinder"
on_press: app.setMode(self)
Button:
text: "Cone"
on_press: app.setMode(self)
Button:
text: "Sphere"
on_press: app.setMode(self)
FloatLayout:
Label:
text: "The Volume and surface area of a {}:".format(app.mode)
pos_hint: {"x":0.1, "y":0.8}
text_size: self.size
FloatLayout:
id:cal
Label:
text:"Side:"
pos_hint: {"x":1.1, "y":0.7}
text_size: self.size
Label:
text:"Volume:"
pos_hint: {"x":1.1, "y":0.65}
text_size: self.size
Label:
text:"Surface Area:"
pos_hint: {"x":1.1, "y":0.6}
text_size: self.size
TextInput:
size_hint: (.4, None)
height: 26
multiline: False
pos_hint: {"x":1.24, "y":0.7}
id: side
text: app.sideText
on_text_validate: app.Cube_on_side_change(self)
Label:
text: app.volume
pos_hint: {"x":1.27, "y":0.65}
text_size: self.size
Label:
text: app.surface_area
pos_hint: {"x":1.355, "y":0.6}
text_size: self.size
"""
cube = """
FloatLayout:
Label:
text:"Side:"
pos_hint: {"x":1.1, "y":0.7}
text_size: self.size
Label:
text:"Volume:"
pos_hint: {"x":1.1, "y":0.65}
text_size: self.size
Label:
text:"Surface Area:"
pos_hint: {"x":1.1, "y":0.6}
text_size: self.size
TextInput:
size_hint: (.4, None)
height: 26
multiline: False
pos_hint: {"x":1.24, "y":0.7}
id: side
text: app.sideText
on_text_validate: app.Cube_on_side_change(self)
Label:
text: app.volume
pos_hint: {"x":1.27, "y":0.65}
text_size: self.size
Label:
text: app.surface_area
pos_hint: {"x":1.355, "y":0.6}
text_size: self.size"""
cuboid = """
FloatLayout:
id:main
Label:
text:"Length:"
pos_hint: {"x":1.1, "y":0.7}
text_size: self.size
Label:
text:"Breadth:"
pos_hint: {"x":1.1, "y":0.65}
text_size: self.size
Label:
text:"Height:"
pos_hint: {"x":1.1, "y":0.6}
text_size: self.size
TextInput:
size_hint: (.4, None)
height: 26
multiline: False
pos_hint: {"x":1.24, "y":0.7}
id: length
text: app.sideText
on_text_validate: app.Cuboid_on_side_change(self)
TextInput:
size_hint: (.4, None)
height: 26
multiline: False
pos_hint: {"x":1.24, "y":0.65}
id: breadth
text: app.sideText
on_text_validate: app.Cube_on_side_change(self)
TextInput:
size_hint: (.4, None)
height: 26
multiline: False
pos_hint: {"x":1.24, "y":0.6}
id: height
text: app.sideText
on_text_validate: app.Cuboid_on_side_change()
Label:
text: "Volume:"
pos_hint: {"x":1.1, "y":0.55}
text_size: self.size
Label:
text: "Surface Area:"
pos_hint: {"x":1.1, "y":0.5}
text_size: self.size
Label:
text: app.volume
pos_hint: {"x":1.27, "y":0.55}
text_size: self.size
Label:
text: app.surface_area
pos_hint: {"x":1.355, "y":0.5}
text_size: self.size"""
cone = """
FloatLayout:
Label:
text:"Radius:"
pos_hint: {"x":1.1, "y":0.7}
text_size: self.size
Label:
text:"Height:"
pos_hint: {"x":1.1, "y":0.65}
text_size: self.size
TextInput:
size_hint: (.4, None)
height: 26
multiline: False
pos_hint: {"x":1.24, "y":0.7}
id: Radius
text: app.sideText
on_text_validate: app.Cuboid_on_side_change(self)
TextInput:
size_hint: (.4, None)
height: 26
multiline: False
pos_hint: {"x":1.24, "y":0.65}
id: height
text: app.sideText
on_text_validate: app.Cube_on_side_change(self)
Label:
text: "Volume:"
pos_hint: {"x":1.1, "y":0.6}
text_size: self.size
Label:
text: "Surface Area:"
pos_hint: {"x":1.1, "y":0.55}
text_size: self.size
Label:
text: app.volume
pos_hint: {"x":1.27, "y":0.6}
text_size: self.size
Label:
text: app.surface_area
pos_hint: {"x":1.355, "y":0.55}
text_size: self.size
"""
screens = {
"Cube": cube,
"Cuboid": cuboid,
"Cone": cone
}
class MyApp(App):
sideText = StringProperty("")
surface_area = StringProperty("0 cm²")
volume = StringProperty("0 cm³")
mode = StringProperty("Cube")
def build(self):
self.screen = Builder.load_string(kv)
return self.screen
def setMode(self, btn):
self.volume = "0 cm³"
self.surface_area = "0 cm³"
self.mode = btn.text
self.screen.cal.clear_widgets()
self.screen.cal.add_widget(Builder.load_string(screens[self.mode]))
def Cube_on_side_change(self, instance):
try:
value = float(instance.text)
num = True
except ValueError:
# failed to convert
num = False
print("Numbers only idiot.")
def cubeCalc(val):
return {
"volume": val * val * val,
"surface_area": (val * val) * 6
}
if num:
result = cubeCalc(value)
self.volume = "{:.2f} cm³".format(result["volume"])
self.surface_area = "{:.2f} cm²".format(result["surface_area"])
def Cuboid_on_side_change(self):
height = self.screen.cal.ids.main.height.text
try:
value = float(height)
num = True
except ValueError:
# failed to convert
num = False
print("Numbers only idiot.")
def cubeCalc(val):
return {
"volume": val * val * val,
"surface_area": (val * val) * 6
}
if num:
result = cubeCalc(value)
self.volume = "{:.2f} cm³".format(result["volume"])
self.surface_area = "{:.2f} cm²".format(result["surface_area"])
if __name__ == "__main__":
MyApp().run()
on_text_validate of the TextInput with id:height in the string cuboid, I want to get the text from the text input with something like: self.screen.main.height.text, however, to do that I would have to add main:main and height:height to Screen. How would I do this?
I suggest refactoring your code. Rather than re-inventing the capabilities of ScreenManager, just use ScreenManager. In your kv string, replace the FloatLayout with:
ScreenManager:
CubeScreen:
CuboidScreen:
ConeScreen:
and use your additional kv strings (like cube) as the basis for additional rules in your kv string. Something like:
<CubeScreen>:
Label:
text: "The Volume and surface area of a Cube:"
pos_hint: {"x":0.1, "y":0.8}
text_size: self.size
FloatLayout:
Label:
text:"Side:"
pos_hint: {"x":0.1, "y":0.7}
text_size: self.size
.
.
.
And define each Screen class in your py, like:
class CubeScreen(Screen):
def get_cube_area(self):
.
.
.
And in each of the new classes (like CubeScreen) you can define methods for calculating area, volume, etc, and you can access the TextInputs easily using their ids. And your on_text_validate in each Screen can just call the appropriate method from that Screen (like on_text_validate: root.get_cube_area()).

I can't make references and search for IDs in a specific window, using the screenmanager, Python / Kivy

I am developing an application in Python and with the kivy library. In the past version of the App, it had only one window, and the code worked well, however, I need to implement multi-windows, and the problem is that I can't reference the ids inside the windows I created.
main.py
from kivy.app import App
from kivy.core.window import Window
from kivy.uix.popup import Popup
from kivy.uix.label import Label
from kivy.properties import ObjectProperty, ListProperty
from kivy.uix.image import Image
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.lang import Builder
from kivy.uix.widget import Widget
#-----------------------------------------------------------------------------------------------------------------------
Window.softinput_mode = 'below_target'
Window.clearcolor = [1, 1, 0.9, 0.9]
class FirstWindow(Screen):
pass
class SecondWindow(Screen):
pass
class ThirdWindow(Screen):
pass
class WindowManager(ScreenManager):
pass
class CustomPopup(Popup):
pass
class MainApp(App):
texture = ObjectProperty()
def open_popup(self):
the_popup = CustomPopup()
the_popup.open()
def build(self):
self.title = 'Myapp'
self.texture = Image(source = 'wave.png').texture
# self.first_window.ids.x.text
# self.screen_manager = ScreenManager()
# self.FirstWindow = FirstWindow()
# screen = Screen(name = 'first')
# screen.add_widget(self.FirstWindow)
# self.screen_manager.add_widget(screen)
# primeiro = self.screen_manager.get_screen("first")
def calcular(self, *args):
#>>>>> The problem happens here, I believe that the code can no longer get the data from the ids because
they are no longer in root. and I don't know how to reference them. The problem didn't happen before
because the kivy code had only one window <<<<<<<<<<<
s_x = self.root.ids.x.text
s_y = self.root.ids.y.text
s_z = self.root.ids.z.text
s_rpa = self.root.ids.rpa.text
s_rt = self.root.ids.rt.text
s_rpi = self.root.ids.rpi.text
s_t = self.root.ids.t.text
s_ii = self.root.ids.ii.text
s_ie = self.root.ids.ie.text
s_ac = self.root.ids.ac.text
#-----------------------------------------------------------------------------------------------------------------------
# Conditionals and variables:
if (s_x == ''):
s_x = 6
if (s_y == ''):
s_y = 6
if (s_z == ''):
s_z = 3
if (s_ie == ''):
s_ie = 20000
if (s_ii == ''):
s_ii = 300
if (s_t == ''):
s_t = 0.88
if (s_rpi == ''):
s_rpi = 0.3
if (s_rt == ''):
s_rt = 0.7
if (s_rpa == ''):
s_rpa = 0.5
if (s_ac == ''):
s_ac = 90
x = float(s_x)
y = float(s_y)
z = float(s_z)
rpi = float(s_rpi)
rt = float(s_rt)
rpa = float(s_rpa)
t = float(s_t)
ac = float(s_ac)
ii = float(s_ii)
ie = float(s_ie)
#-----------------------------------------------------------------------------------------------------------------------
# Equacions:
apa = 2*((x*z)+(y*z))
api = x * y
at = x * y
a = apa + api + at
r = ((rpa * apa) + (rpi * api) + (rt * at)) / a
fld = (ii/ie)*100
w = (fld*a*(1-(r ** 2))) / (t*ac)
w = round(w, 2)
w = str(w)
w = w.replace(".", ",")
w = w +" m²"
print(w)
#-----------------------------------------------------------------------------------------------------------------------
# >>>>>>>>The problem with ids also happens here <<<<<<<<<<
# Button calculate:
if (( t<=0 or t>1 ) or ( rpa<=0 or rpa>=1 ) or ( rpi<=0 or rpi >=1 ) or ( rt<=0 or rt>=1 ) or (ac<=0 or ac>180)):
the_popup = Popup(title='Erro', content=Label(id='_result', text='Valor fornecido invalido.'),size_hint=(.5, .2), separator_color=[1, 1, 0.6, 0.8])
the_popup.open()
else:
self.root.ids.resultado.text = w
self.root.ids.resultado.opacity = 1
if (ac > 90):
self.root.ids.tipojanela.text = 'Janela azimutal'
self.root.ids.tipojanela.opacity = 1
else:
self.root.ids.tipojanela.opacity = 0
#-----------------------------------------------------------------------------------------------------------------------
def exit(self):
App.get_running_app().stop()
aplicativo = MainApp()
aplicativo.run()
main.kv
<Button>:
background_down: ''
<CustomPopup>:
size_hint: 1,.7
auto_dismiss: False
title: 'Ajuda'
separator_color: 1,1,0.6,0.8
FloatLayout:
id: primeiro_float
Label:
text: '- O valor para a transmitância deve ser maior que 0 e menor ou igual a 1 \n - Os valores para as refletâncias devem estar entre 0 e 1 \n - O ângulo de céu visível deve ser maior que 0° e menor ou igual a 180°"'
font_size: 25
text_size: self.size
halign: 'center'
valign: 'middle'
size: primeiro_float.size
pos: primeiro_float.pos
Button:
size_hint: None, None
width: self.texture_size[0] - dp(10)
height: self.texture_size[0] - dp(10)
pos_hint: {'center_x': .5, 'y': .05}
halign:'right'
valign: 'top'
text: 'fechar'
color: 0,0,0,0
border: 0,0,0,0
background_normal: 'close.png'
background_down: 'close.png'
on_press: root.dismiss()
WindowManager:
FirstWindow:
SecondWindow:
ThirdWindow:
<FirstWindow>:
name: 'first'
id: first_window
FloatLayout:
canvas:
Rectangle:
pos: self.pos
size: self.size
texture: app.texture
GridLayout:
cols:1
ActionBar:
background_color: 1,1,1,1
background_image: ''
ActionView:
use_separator: True
ActionPrevious:
background_image:''
background_down: ''
background_normal: ''
background_color: ''
source: ''
app_icon: 'fld.png'
previous_image: ''
color: 0,0,0,1
ActionGroup:
background_normal: 'list1.png'
background_down: 'list2.png'
source:''
mode: 'spinner'
size_hint: None, None
width: '50sp'
height: '50sp'
border: 0,0,0,0
ActionButton:
background_color: 0.3,1,0.6,1
source:''
text: 'Ajuda'
on_press: app.open_popup()
id:ajuda
ActionButton:
background_color: 0.3,1,0.6,1
background_normal: ''
text: 'Sair'
id:sair
on_release: app.exit()
Label:
canvas.before:
Color:
rgba: 1,1,0.6,0.8
Rectangle:
pos: self.pos
size: self.size
color: 0,0,0,1
size_hint_y: None
height: self.font_size + dp(10)
text: 'Ambiente'
halign: 'center'
valign: 'middle'
GridLayout:
size_hint: None, None
width: root.width
height: self.minimum_height
padding: 10, 10, 10, 10
spacing: dp(10)
cols:4
Label:
text: 'Comprimento (m)'
color: 0.5,0.5,0.5,1
text_size: self.size
font_size: '11sp'
halign: 'center'
valign: 'middle'
size_hint_y: None
height: self.font_size + dp(20)
TextInput:
text: '6'
id: x
cursor_color: 0,0,0,1
size_hint_y: None
height: self.font_size + dp(15)
input_filter:'float'
multiline: False
write_tab: False
on_text_validate: y.focus = True
Label:
text: 'Refletância do piso ]0;1['
color: 0.5,0.5,0.5,1
text_size: self.size
font_size: '11sp'
halign: 'center'
valign: 'middle'
size_hint_y: None
height: self.font_size + dp(20)
TextInput:
text: '0.3'
id: rpi
cursor_color: 0,0,0,1
input_filter:'float'
multiline: False
write_tab: False
on_text_validate: rt.focus = True
Label:
text: 'Largura (m)'
color: 0.5,0.5,0.5,1
text_size: self.size
font_size:'11sp'
halign: 'center'
valign: 'middle'
size_hint_y: None
height: self.font_size + dp(20)
TextInput:
text: '6'
id: y
cursor_color: 0,0,0,1
input_filter:'float'
multiline: False
write_tab: False
on_text_validate: z.focus = True
Label:
text: 'Refletância do teto ]0;1['
color: 0.5,0.5,0.5,1
text_size: self.size
font_size: '11sp'
halign: 'center'
valign: 'middle'
size_hint_y: None
height: self.font_size + dp(20)
TextInput:
text: '0.7'
id: rt
cursor_color: 0,0,0,1
multiline: False
input_filter:'float'
multiline: False
write_tab: False
on_text_validate: rpa.focus = True
Label:
text: 'Pé-direito (m)'
color: 0.5,0.5,0.5,1
text_size: self.size
font_size: '11sp'
halign: 'center'
valign: 'middle'
size_hint_y: None
height: self.font_size + dp(20)
TextInput:
text: '3'
id: z
cursor_color: 0,0,0,1
input_filter:'float'
multiline: False
write_tab: False
on_text_validate: rpi.focus = True
Label:
text: 'Refletância das paredes ]0;1['
color: 0.5,0.5,0.5,1
text_size: self.size
font_size: '11sp'
halign: 'center'
valign: 'middle'
size_hint_y: None
height: self.font_size + dp(20)
on_text_validate:
TextInput:
text: '0.5'
id: rpa
cursor_color: 0,0,0,1
input_filter:'float'
multiline: False
write_tab: False
on_text_validate: t.focus = True
Label:
canvas.before:
Color:
rgba: 1,1,0.6,0.8
Rectangle:
pos: self.pos
size: self.size
color: 0,0,0,1
size_hint_y: None
height: self.font_size + dp(10)
text: 'Abertura'
halign: 'center'
valign: 'middle'
GridLayout:
size_hint: None, None
width: root.width
height: self.minimum_height
padding: 10, 10, 10, 10
spacing: dp(10)
cols:2
Label:
text: 'Transmitância ]0;1]'
color: 0.5,0.5,0.5,1
text_size: self.size
font_size: '11sp'
halign: 'center'
valign: 'middle'
size_hint_y: None
height: self.font_size + dp(20)
TextInput:
text: '0.88'
id: t
cursor_color: 0,0,0,1
input_filter:'float'
multiline: False
write_tab: False
on_text_validate: ac.focus = True
Label:
canvas.before:
Color:
rgba: 1,1,0.6,0.8
Rectangle:
pos: self.pos
size: self.size
color: 0,0,0,1
size_hint_y: None
height: self.font_size + dp(10)
text: 'Obstrução'
halign: 'center'
valign: 'middle'
GridLayout:
size_hint: None, None
width: root.width
height: self.minimum_height
padding: 10, 10, 10, 10
spacing: dp(10)
cols:2
Label:
text: 'Ângulo de céu visível (°)'
color: 0.5,0.5,0.5,1
text_size: self.size
font_size: '11sp'
halign: 'center'
valign: 'middle'
size_hint_y: None
height: self.font_size + dp(20)
TextInput:
text: '90'
id: ac
cursor_color: 0,0,0,1
multiline: False
write_tab: False
input_filter:'float'
on_text_validate: ie.focus = True
Label:
canvas.before:
Color:
rgba: 1,1,0.6,0.8
Rectangle:
pos: self.pos
size: self.size
color: 0,0,0,1
size_hint_y: None
height: self.font_size + dp(10)
text: 'Iluminâncias'
halign: 'center'
valign: 'middle'
GridLayout:
size_hint: None, None
width: root.width
height: self.minimum_height
padding: 10, 10, 10, 10
spacing: dp(10)
cols:2
Label:
text: 'Iluminância externa difusa (lx)'
color: 0.5,0.5,0.5,1
text_size: self.size
font_size: '11sp'
halign: 'center'
valign: 'middle'
size_hint_y: None
height: self.font_size +dp(20)
TextInput:
text: '20000'
id: ie
cursor_color: 0,0,0,1
multiline: False
write_tab: False
input_filter: 'float'
on_text_validate: ii.focus = True
Label:
text: 'Iluminância interna média no Plano de Trabalho (lx)'
color: 0.5,0.5,0.5,1
text_size: self.size
font_size: '11sp'
halign: 'center'
valign: 'middle'
size_hint_y: None
height: self.font_size +dp(20)
TextInput:
text: '300'
id: ii
cursor_color: 0,0,0,1
multiline: False
write_tab: False
input_filter: 'float'
on_text_validate: bt.focus = True
FloatLayout:
Button:
pos_hint: {'center_x': .5, 'center_y': .6}
width: '220sp'
height: '45sp'
size_hint: None, None
color: 0,0,0,1
background_normal: 'calcu1.png'
background_down: 'calcu2.png'
#background_color: 1,1,0.9,0.9
border: 0,0,0,0
id: bt
text: u'Calcular a área da janela'
font_size: '17sp'
on_release: app.calcular()
FloatLayout:
Label:
text: 'v1.0.3 - Beta'
pos_hint: {'center_x': 0.85, 'center_y': .2}
color: 0,0,0,1
font_size: '14sp'
Button:
size_hint: None, None
width: '25sp'
height: '25sp'
pos_hint: {'center_x': .94, 'y': .4}
#halign:'right'
#valign: 'top'
border: 0,0,0,0
background_normal: 'int1.png'
background_down: 'int2.png'
on_release:
app.root.current = 'second'
root.manager.transition.direction = 'left'
Button:
size_hint: None, None
width: '25sp'
height: '25sp'
pos_hint: {'center_x': .94, 'y': .9}
#halign:'right'
#valign: 'top'
border: 0,0,0,0
background_normal: 'cont.png'
background_down: 'cont.png'
on_release:
app.root.current = 'third'
root.manager.transition.direction = 'left'
Label:
id: resultado
opacity: 0
pos_hint: {'center_x': .5, 'center_y': .9}
width: self.texture_size[0] + dp(20)
size_hint_x: None
size_hint_y: .4
text: ''
color: 0,0,0,1
canvas.before:
Color:
rgba: 1,1,0.6,0.8
RoundedRectangle:
radius:{(10.0,), (10.0,), (10.0,), (10.0,)}
size: self.size
pos: self.pos
Label:
id: tipojanela
opacity: 0
pos_hint: {'center_x': .5, 'center_y': .35}
width: self.texture_size[0] + dp(20)
size_hint_x: None
size_hint_y: .4
text: ''
color: 0,0,0,1
canvas.before:
Color:
rgba: 1,1,0.6,0.8
RoundedRectangle:
radius:{(10.0,), (10.0,), (10.0,), (10.0,)}
size: self.size
pos: self.pos
<SecondWindow>:
name: 'second'
id: second_window
BoxLayout:
orientation: 'vertical'
size: root.width, root.height
Label:
text: 'Segunda janela'
font_size: 32
Button:
text: 'Voltar pra primeira janela'
font_size: 32
on_release:
app.root.current = 'first'
root.manager.transition.direction = 'right'
<ThirdWindow>:
name: 'third'
id: second_window
BoxLayout:
orientation: 'vertical'
size: root.width, root.height
Label:
text: 'terceira janela'
font_size: 32
Button:
text: 'Voltar pra primeira janela'
font_size: 32
on_release:
app.root.current = 'first'
root.manager.transition.direction = 'right'
Error on:
on_release: app.calcular()
Error:
File "C:\Users\Gilson Carvalho\Desktop\TropWin 01-04-2021\Arriscando Tudo 2\main.py", line 63, in calcular
s_x = self.root.ids.x.text
File "kivy\properties.pyx", line 864, in kivy.properties.ObservableDict.__getattr__
AttributeError: 'super' object has no attribute '__getattr__'
Could anyone help me with this?
You are correct, the ids are no longer in self.root, because that is now the ScreenManager (WindowManager). The way to access those ids now is through the get_screen() method of ScreenManager. For example, replace:
s_x = self.root.ids.x.text
with:
s_x = self.root.get_screen('first').ids.x.text

KivyMD 0.103.0 causing errors with 'NavigationDrawerSubheader'

I recently updated kivyMD from 0.102.1 to 0.103.0 and i'm getting the following error:
raise FactoryException('Unknown class <%s>' % name)
kivy.factory.FactoryException: Unknown class
But when go back to version 0.102.1 everything works just fine. I'll post the code below but I just wanted to know if I wanted to update to 0.103.0 what do I need to change? I've tried to do some research but unable to find something that will fix the problem.
.py
#imported from kivy framework
from kivy.app import App
from kivymd.app import MDApp
from kivy.app import App
from datetime import datetime
from datetime import timedelta
from kivy.clock import Clock
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.image import Image
import weatherGrab
from weatherGrab import weatherCheck
import os
#1st screen
class Login_Screen(Screen):
#Takes user input from the .KV file, converts it to string and verifies if its a saved login
def verify_credentials(self):
Username = self.ids.Username_userInput
Password = self.ids.Password_userInput
Username_string = Username.text
Password_string = Password.text
#Allows the variable to be used in another class and method
Login_Screen.verify_credentials.GGG = Username.text
#checks if user input is equal to temp database
if self.ids["Username_userInput"].text == "Username" and self.ids["Password_userInput"].text == "Password":
self.manager.current = "Homepage_Screen"
print("USER LOGIN DATA: " + Username_string +" "+Password_string)
weatherGrab.weatherCheck()
#print('CURRENT WEATHER - London','\n',weatherCheck.currentWeather,'\n' ,weatherCheck.temp)
#print('HERE',var1)
#x = dir(platform) prints all function from that lib
#after log in, sets user input to empty so the next user can login
def clean(self):
self.ids["Username_userInput"].text = ""
self.ids["Password_userInput"].text = ""
#saving user inputs to a text file (temp database)
def save_data(self):
Username = self.ids.Username_userInput
Password = self.ids.Password_userInput
Username_string = Username.text
Password_string = Password.text
TextDoc = open("UserLogin.txt", "a")
username = Username_string
password = Password_string
if username == '' and password == '':
pass
else:
TextDoc.write("\n"+username+","+password)
TextDoc.close()
#loads data from the file (debugging/testing)
def load_data(self):
f = open("UserLogin.txt", "r")
print("FROM TEXT FILE:"+ f.read())
#2nd screen
class Homepage_Screen(Screen):
#Event dispatcher to load data when user enters the second screen
def on_enter(self):
self.load_info()
self.weather()
def weather(self):
self.ids["temp"].text = weatherCheck.temp
self.ids["date"].text = weatherCheck.currentDate
#Text prints in termial for testing/debugging
def load_info(self):
print("PASSING USERNAME TO HOMEPAGE: "+Login_Screen.verify_credentials.GGG)
self.ids["USERNAME"].text = "Welcome"+" "+Login_Screen.verify_credentials.GGG
#Saves User input from the notes textinput
def save_notes(self):
UserNotes = self.ids.UserInput_notes
UserNote = UserNotes.text
TextDoc = open("UserLogin.txt", "a")
TextDoc.write("," + UserNote)
TextDoc.close()
#3rd screen
class Application_Screen(Screen):
pass
#4th screen
class Logout_Screen(Screen):
def newline(self):
TextDoc = open("UserLogin.txt", "a")
TextDoc.write("\n")
TextDoc.close()
def forcequit(self):
exit()
#class for all screens
class ScreenManagement(ScreenManager):
pass
class MainApp(MDApp):
def build(self):
#declaring time from python, and making it refresh every second
self.now = datetime.now()
Clock.schedule_interval(self.update_clock, 1)
def update_clock(self, *args):
self.now = self.now + timedelta(seconds=1)
#Allows for time to be shown on all screens
self.root.get_screen("Homepage_Screen").ids["CurrentTime"].text = self.now.strftime("%H:%M:%S")
self.root.get_screen("Logout_Screen").ids["CurrentTime"].text = self.now.strftime("%H:%M:%S")
self.root.get_screen("Login_Screen").ids["CurrentTime"].text = self.now.strftime("%H:%M:%S")
#print(self.now.strftime("%H:%M:%S"))
MainApp().run()
.kv
#:kivy 1.0
#:import hex kivy.utils.get_color_from_hex
#styles that will apply to all intences for each tag
<MDRaisedButton>:
font_size:18
<Label>:
color: 0,0,0,1
#declaring screen managers and printing them in this order
ScreenManagement:
Login_Screen:
name:"Login_Screen"
id: woow
Homepage_Screen:
name:"Homepage_Screen"
Application_Screen:
name:"Application_Screen"
Logout_Screen:
name:"Logout_Screen"
#style for login screen
<Login_Screen>:
#background color
FloatLayout:
spacing: 10
canvas.before:
Color:
rgba: hex('#eff3fa')
Rectangle:
size: self.size
pos: self.pos
#Navbar
MDToolbar:
id: fb
pos_hint: {'center_x': 0.5, 'top':1.0}
size_hint_y:None
height: 50
title: "Virtual Assistant"
md_bg_color: hex('#132843')
Label:
id: CurrentTime
font_size:18
size_hint_x: .1
color: (1,1,1,1)
#login container
#background color/positioning
BoxLayout:
spacing: 10
orientation: 'vertical'
padding: 50
canvas.before:
Color:
rgba: hex('#000')
Rectangle:
size: self.size
pos: self.pos
pos_hint: {'center_x': 0.5, 'center_y': 0.5}
size_hint: 0.33, None
size_hint_min_x: 200
height: self.minimum_height
#LOGIN CONTENT
#logo
Image:
source: 'Logo.png'
size_hint: None, None
size: 100, 100
pos_hint: {'center_x': 0.5, 'center_y': 0.0}
MDTextField:
id: Username_userInput
hint_text:"Username"
text:"Username"
line_color_normal: 0,0,0,1
MDTextField:
id: Password_userInput
hint_text:"Password"
text:"Password"
password: True
line_color_normal: 0,0,0,1
#color_mode:'accent'
Button:
text:"Login"
size_hint_y: None
height: 60
padding: 10,10
background_color: (2.08, 2.40, 1.92,1)
size_hint: 0.40, None
pos_hint: {'center_x': 0.5, 'center_y': 0.0}
on_press: root.verify_credentials() , root.save_data(), root.clean(), root.load_data()
#style for Homepage screen
<Homepage_Screen>:
#SIDEBAR BUTTONS
NavigationLayout:
id: nav_layout
MDNavigationDrawer:
drawer_logo:'Logo.png'
NavigationDrawerSubheader:
id: USERNAME
NavigationDrawerIconButton:
icon:"home"
text:"Homepage"
theme_text_color: 'Custom'
on_release:
screen_manager.current = "Homepage"
NavigationDrawerIconButton:
icon:'application'
text: "Application"
on_release:
screen_manager.current = "Application"
NavigationDrawerIconButton:
icon: 'dictionary'
text: "Dictionary"
on_release:
screen_manager.current = "Dictionary"
MDRectangleFlatIconButton:
icon:'logout'
text: "Logout"
#on_press: root.clean()
on_release: app.root.current = "Logout_Screen"
size_hint: 1, None
font_size:20
text_color: 0,0,0,1
#BACKGROUND
FloatLayout:
spacing: 10
canvas.before:
Color:
rgba: hex('#eff3fa')
Rectangle:
size: self.size
pos: self.pos
#NAVBAR
MDToolbar:
id: fb
pos_hint: {'center_x': 0.5, 'top':1.0}
size_hint_y:None
height: 50
title: "Virtual Assistant"
md_bg_color: hex('#132843')
left_action_items: [['menu', lambda x: root.ids.nav_layout.toggle_nav_drawer()]]
Label:
id: CurrentTime
size_hint_x: .1
font_size:18
color: (1,1,1,1)
#SIDEBAR SCREEN STYLE
ScreenManager:
id: screen_manager
#HOMEPAGE SCREEN STYLE
Screen:
name: "Homepage"
BoxLayout:
spacing: 10
orientation: 'vertical'
padding: 10
canvas.before:
Color:
rgba: (1,1,1,.8)
Rectangle:
size: self.size
pos: self.pos
pos_hint: {'center_x': 0.5, 'top': (root.height - fb.height)/root.height}
size_hint: 0.3, None
height: 35
GridLayout:
rows: 3
cols: 3
padding: 10
spacing: 15
#pos_hint: {"center_x":0.6, "center_y":0.0}
Label:
id:date
color: (0,0,0,1)
size_hint_x: 2
Label:
id:temp
color: (0,0,0,1)
size_hint_x: 2
Label:
text:'icon'
color: (0,0,0,1)
size_hint_x: 2
BoxLayout:
orientation: 'horizontal'
spacing: 10
padding: 10
canvas.before:
Color:
rgba: (1,1,1,1)
Rectangle:
size: self.size
pos: self.pos
size_hint: 0.8, None
height: 60
pos_hint: {'center_x': .5, 'center_y':.5}
TextInput:
height:60
size_hint: 5, None
focus: True
multiline: False
font_size: 25
padding_y:15
background_color: 1,1,1,0
foreground_color: 0,0,0,1
pos_hint:{'center_x':0, 'center_y':0.5}
MDRectangleFlatIconButton:
icon:'search-web'
height:45
text_color: 0,0,0,1
md_bg_color: hex("#D0F0C0")
pos_hint: {'center_x': 0.5, 'center_y': 0.5}
Label:
text:'Search'
font_size:18

Can not change the value of widget added by add_widget

-- 2017 12/23 14:00 ** I edited for can understand more clealy ** --
Hello everyone.
I wrote simple code, so please check it.
My purpose is change the value "text" and "cooooop" of Number that added with add_widget().
But can not change.
I think that it is caused by referring to cop of the parent widget.
But I do not know the truth.
How should i do?
Please help me!!
#python
from kivy.app import App
from kivy.uix.behaviors import ButtonBehavior
from kivy.uix.label import Label
from kivy.uix.gridlayout import GridLayout
from kivy.properties import ObjectProperty
class Number(Label):
pass
class Wrapper(GridLayout):
pass
class Adder(ButtonBehavior, Label):
rooting = ObjectProperty(None)
def on_release(self):
self.rooting.add_widget(Number(
rooting = self.rooting,
cooooop = self.rooting.cop,
text = self.rooting.cop,
))
class Changer(ButtonBehavior, Label):
rooting = ObjectProperty(None)
def on_release(self):
self.rooting.cop = 'Thank you'
class TestApp(App):
def build(self):
pass
TestApp().run()
#kvfile
<Number>:
font_size: sp(15)
halign: 'center'
markup: True
valign: 'top'
size_hint_y: None
text_size: self.width, sp(50)
height: sp(30)
multiline: False
<Adder>:
text: "Add"
font_size: sp(15)
halign: 'center'
markup: True
valign: 'middle'
size_hint_y: None
text_size: self.width, sp(50)
height: sp(30)
multiline: False
col: 1.000 ,0.5843 ,0.000, 1
on_release: self.col = 1.000 ,0.5843 ,0.000, 1
on_press: self.col = 1.000 ,0.5843 ,0.000, .5
canvas.before:
Color:
rgba: self.col
RoundedRectangle:
pos: self.pos
size: self.size
radius: [sp(12)]
<Changer>:
text: "Change"
font_size: sp(15)
halign: 'center'
markup: True
valign: 'middle'
size_hint_y: None
text_size: self.width, sp(50)
height: sp(30)
multiline: False
col: 0.000 ,0.4784 ,1.000, 1
on_release: self.col = 0.000 ,0.4784 ,1.000, 1
on_press: self.col = 0.000 ,0.4784 ,1.000, .5
canvas.before:
Color:
rgba: self.col
RoundedRectangle:
pos: self.pos
size: self.size
radius: [sp(12)]
Wrapper:
padding: 0, 300, 0, 0
pos_hint: {'top': 1, 'center_x': .5}
cols: 1
size_hint: .3, None
id: rooting
height: self.minimum_height
cop: 'Change me'
spacing: 0, 50
Adder:
rooting: rooting
Changer:
rooting: rooting
Label:
size_hint_y: None
height: sp(40)

Categories