Related
I tried to create a white popup window with rounded edges as the first image by using a canvas, but when I write canvas.after or canvas.before it comes behind or above the popup window content, so how I can make it looks like the first image?
.py file:
from kivy.app import App
from kivy.core.window import Window
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.widget import Widget
from kivy.lang import Builder
from kivy.core.text import LabelBase
from kivy.uix.popup import Popup
Window.size = [300,600]
class MyLayout(Widget):
pass
class Exercise(App):
def build(self):
#Window color
Window.clearcolor = (249/255.0, 249/255.0, 249/255.0, 0)
Builder.load_file("myfile.kv")
#Loading .kv file
return MyLayout()
if __name__ == "__main__":
Exercise().run()
.kv file:
#: import Factory kivy.factory.Factory
<MyPopup#Popup>
auto_dismiss: False
title: ""
separator_height: 0
size_hint: 0.8, 0.4
background_color: (0,0,0,0)
background_normal: ''
canvas.before:
Color:
rgba:(255/255,255/255,255/255,1)
RoundedRectangle:
pos: self.pos
size: self.size
radius: [40]
BoxLayout:
orientation: "vertical"
size: root.width, root.height
padding: 0, 10, 10, 10
border: 50
border_color: (1,1,1,1)
Label:
text: "Good job"
color: 0,0,0,1
font_size: 16
CloseButton:
text: "Close"
color: 0,0,0,1
size_hint: (None , None)
width: 105
height: 40
pos_hint: {'center_x':0.5}
on_release: root.dismiss()
<MyLayout>:
BoxLayout:
orientation: "vertical"
size: root.width, root.height
padding: 20,40
#spacing: 20
Label:
font_size: 20
text: 'Click the button'
color: 0, 0, 0, 1
MyButton:
font_size: 20
text: "Button"
color: (0,0,0,1)
size_hint: (None , None)
width: 250
height: 50
pos_hint: {'center_x':0.5}
on_release: Factory.MyPopup().open()
<CloseButton#Button>:
background_color: (0,0,0,0)
background_normal: ''
canvas.before:
Color:
rgba:(252/255,131/255,87/255,1)
RoundedRectangle:
pos: self.pos
size: self.size
radius: [20]
<MyButton#Button>
background_color: (0,0,0,0)
background_normal: ''
canvas.before:
Color:
rgba:(252/255,131/255,87/255,1)
RoundedRectangle:
pos: self.pos
size: self.size
radius: [25]
Remove the canvas.before from the first part of the Popup and add it to the BoxLayout. Adjust the size and position of the canvas.before to make it cover the default background.
Here is the modified Popup definition that will work.
<MyPopup#Popup>
auto_dismiss: False
title: ""
separator_height: 0
size_hint: 0.8, 0.4
BoxLayout:
orientation: "vertical"
size: root.width, root.height
padding: 0, 10, 10, 10
border: 50
border_color: (1,1,1,1)
canvas.before:
Color:
rgba: 1, 1, 1, 1
RoundedRectangle:
pos: self.x - 20, self.y - 20
size: self.width + 40, self.height + 60
radius: [40]
Label:
text: "Good job"
color: 0,0,0,1
font_size: 16
CloseButton:
text: "Close"
color: 0,0,0,1
size_hint: (None , None)
width: 105
height: 40
pos_hint: {'center_x':0.5}
on_release: root.dismiss()
recently I try to make that app with python and kivy. After tons of hours googling everything together i more or less have everything i want. Only one thing is missing:
I have several screens. At the beginning of the App I have a menu. After that i have lots of questions; all of them have the same text and buttons in the bottom of the screen. I managed to make that the following way:
<firstquestion>:
name: "firstquestion"
GridLayout:
cols: 1
size_hint_y: 1
GridLayout:
cols: 1
NeuLabelinBox:
text: "Here the Question"
GridLayout:
cols: 1
size_hint_y: 0.1
UnteresMenue:
Please notice "UnteresMenue" which refer another Class in the kv language. I think I somehow mixed 2 Screens together in one. The kv code of "UnteresMenue"
<UnteresMenue>:
name: "UnteresMenue"
#id: UnteresMenue
GridLayout:
cols: 1
NeuButton:
text: root.labeltext
Now for the python part:
class UnteresMenue(Screen):
labeltext = StringProperty("Answer")
That works fine. But now I want to change the text of the label in this "UnteresMenue", when I press a certain button at the beginning of the app (Start Questions). The label in the "Untermenue" should change to a certain text. So to do this:
text: "Exam"
self.manager.get_screen('UnteresMenue').labeltext = text
For all other classes this method works fine. But not for that certain class "UnteresMenue". Is it because it is implemented in the question and therefor kv does not recognize its properties?
For any small hints I would be more than grateful!
Here an "Mini" Example:
In the Main Menu you get to the "Exam" Section (Press Here in the example). While entering this Section (Prüfungsmodus) the property of the questions should change. "Press Here" again to get to the questions.
Normally it says in the Top of the questions "This should change" And THIS is supposed to change the label into "Zeit" while entering the Prüfungsmodus Screen (Class def on_enter, in the python file), but it doesn't...
Python File:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen, TransitionBase
from kivy.properties import ObjectProperty, NumericProperty
from kivy.uix.popup import Popup
from kivy.uix.label import Label
from kivy.core.text import LabelBase
from kivy.core.window import Window
from kivy.graphics import Color, InstructionGroup, Line, Rectangle
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.properties import ListProperty
from kivy.uix.textinput import TextInput
from kivy.uix.checkbox import CheckBox
from kivy.uix.widget import Widget
from kivy.config import Config
from kivy.properties import StringProperty
from kivy.clock import Clock
from functools import partial
from kivy.uix.image import Image
from kivy.garden.navigationdrawer import NavigationDrawer as ND
from kivy.uix.scatter import Scatter
import random
import time
Window.clearcolor = (0.2,0.2, 0.2,1)
Window.size = (480, 800)
#--------------------------------- Hauptmenü -------------------------------------------
class hauptmenue(Screen, Widget):
pass
class Pruefungsmodus(Screen):
labeltext2 = StringProperty("hi")
def on_enter(self):
text = "Zeit"
self.manager.get_screen('OberesMenue').labeltext = text #DAS Klappt nicht
def StartPruefung(self):
sm.current = "ersteFrage"
class UnteresMenue(Screen):
background_color_Kappa = ListProperty([0.2,0.2,0.2, 1])
class OberesMenue(Screen):
BildLabeltext = StringProperty("Bilder\Loesung_Bild_pressed.png")
BildLabeltext2 = StringProperty("Bilder\Loesung_Bild.png")
labeltext = StringProperty("This should change")
class ersteFrage(Screen):
pass
class WindowManager(ScreenManager):
pass
kv = Builder.load_file("my.kv")
sm = WindowManager()
sm.add_widget(hauptmenue(name="hauptmenue"))
sm.add_widget(Pruefungsmodus(name="Pruefungsmodus"))
sm.add_widget(OberesMenue(name="OberesMenue"))
sm.add_widget(UnteresMenue(name="UnteresMenue"))
sm.add_widget(ersteFrage(name="ersteFrage"))
sm.current = "hauptmenue"
class Vorbrereitung(App):
pruefung = ObjectProperty(None)
def build(self):
return sm
if __name__ == "__main__":
Vorbrereitung().run()
my.kv file :
#:include alleFragen.kv
<NeuLabel2#Label>:
halign: "center"
color:1,1,1,1 # <-----------
canvas.before:
Color:
rgba: 0.2,0.2, 0.2,1
Rectangle:
pos: self.pos
size: self.size
<NeuLabelinBox#Label>:
font_size: "22sp"
color:0,0,0,1 # <-----------
canvas.before:
Color:
rgba: 0.949019608, 0.949019608, 0.949019608, 1
Rectangle:
pos: self.pos
size: self.size
<NeuCheckBox#CheckBox>:
color: 0, 0, 0, 1
canvas.before:
Color:
rgba: 0.949019608, 0.949019608, 0.949019608, 1
Rectangle:
pos: self.pos
size: self.size
<NeuButton#Button>:
font_size: "22sp"
background_normal: ''
#background_normal: "background.png"
background_color: 0.92549,0.92549,0.92549, 1
color:0,0,0,1 # <-----------
canvas.before:
Color:
rgba: 0.2,0.2, 0.2,1
Rectangle:
pos: self.pos
size: self.size
<NeuButtonKappa#Button>:
font_size: "40sp"
background_normal: ''
background_color: 0.2,0.2,0.2, 1
color:1,1,1,1 # <-----------
canvas.before:
Color:
rgba: 0.2,0.2, 0.2,1
Rectangle:
pos: self.pos
size: self.size
#---------------------------------- Hauptmenue ---------------------------------------------------------------------------------
<hauptmenue>:
name: "Hauptmenue"
GridLayout:
cols:1
#spacing: 20
GridLayout:
cols:1
padding: 20
size_hint_y: 0.2
NeuLabel2:
size_hint_x: 0.6
text: ""
font_size: (root.width**2 + root.height**2) / 13**4
halign: 'center'
valign: 'middle'
GridLayout:
cols:2
padding: 30
spacing: 20
size_hint_y: 0.5
BoxLayout:
NeuButton:
text: ''
BoxLayout:
NeuButton:
text: 'PRESS HERE'
on_release:
app.root.current = "Pruefungsmodus"
BoxLayout:
NeuButton:
text: ""
halign: 'center'
valign: 'middle'
BoxLayout:
NeuButton:
text: ""
BoxLayout:
padding: 10
size_hint_y: 0.15
NeuButton:
text: ''
#---------------------------------- Pruefungsmodus ---------------------------------------------------------------------------------
<Pruefungsmodus>:
name: "Pruefungsmodus"
#background_color: 1, 1, 1, 1
id: pruefungsmudos
GridLayout:
cols:1
#spacing: 20
GridLayout:
cols:3
padding: 20
size_hint_y: 0.2
Image:
size_hint_x: 0.2
source:"Bilder\Logo.png"
NeuLabel2:
size_hint_x: 0.6
text: 'Pr\u00FCfungs\nmodus'
font_size: (root.width**2 + root.height**2) / 12**4
halign: 'center'
valign: 'middle'
Image:
size_hint_x: 0.2
source:"Bilder\Logo2.png"
GridLayout:
cols:1
padding: 30
spacing: 10
size_hint_y: 0.4
NeuLabelinBox:
id: text2
text: root.labeltext2
color: 0,0,0,1 # <-----------
canvas.before:
Color:
rgba: 0.949019608, 0.949019608, 0.949019608, 1
Rectangle:
pos: self.pos
size: self.size
GridLayout:
cols:2
padding: 30
size_hint_y: 0.2
BoxLayout:
padding: 30
spacing: 10
NeuButton:
size_hint_x: 0.5
text: "Press Here"
on_release:
app.root.current = "ersteFrage"
NeuButton:
size_hint_x: 0.5
text: ""
on_release:
app.root.current = "hauptmenue"
#---------------------------------- Erste Frage ---------------------------------------------------------------------------------
<ersteFrage>:
name: "ersteFrage"
GridLayout:
cols: 1
size_hint_y: 1
GridLayout:
cols: 1
size_hint_y: 0.08
OberesMenue:
GridLayout:
cols: 1
size_hint_y: 0.1
NeuLabel2:
font_size: "18sp"
text: "Wie lautet......."
GridLayout:
cols: 1
size_hint_y: 0.7
padding: 20
background_color: 0.92549,0.92549,0.92549, 1
rows: 2
BoxLayout:
orientation:'horizontal'
NeuLabelinBox:
text: "h+u=ZU"
NeuCheckBox:
NeuLabelinBox:
text: "h+u=ZU"
NeuCheckBox:
BoxLayout:
orientation:'horizontal'
NeuLabelinBox:
text: "h+u=ZU"
NeuCheckBox:
NeuLabelinBox:
text: "h+u=ZU"
NeuCheckBox:
GridLayout:
cols: 1
size_hint_y: 0.1
UnteresMenue:
and the outsourced Top and Button Menu:
alleFragen.kv
<OberesMenue>:
id: OberesMenueee
name: "OberesMenue"
GridLayout:
cols:1
GridLayout:
#size_hint_y: 0.05
spacing: 20
cols: 3
NeuButton:
text: ""
size_hint_x: 0.16
background_color: 1,1,1, 1
background_down: root.BildLabeltext
background_normal: root.BildLabeltext2
color:1,1,1,1 # <-----------
canvas.before:
Color:
rgba: 0.2,0.2, 0.2,1
Rectangle:
pos: self.pos
size: self.size
NeuLabel2:
size_hint_x: 0.8
text: root.labeltext
NeuButtonKappa:
size_hint_x: 0.1
text: "MENU"
background_down: "Bilder\HintergurndFarbe_app.png"
on_release:
app.root.current = "hauptmenue"
<UnteresMenue>:
name: "UnteresMenue"
id: UnteresMenuee
GridLayout:
cols: 5
spacing: 20
padding: 20
NeuButton:
text: "<=="
NeuButton:
text: "<"
NeuButtonKappa:
text: 'k'
#background_color: root.background_color_Kappa
background_down: "Bilder\HintergurndFarbe_app.png"
NeuButton:
text: ">"
NeuButton:
text: "==>"
The problem is that you have two different instances of the OberesMenue Screen.
There is one created in your python:
sm.add_widget(OberesMenue(name="OberesMenue"))
And you have another created in your kv:
<ersteFrage>:
name: "ersteFrage"
GridLayout:
cols: 1
size_hint_y: 1
GridLayout:
cols: 1
size_hint_y: 0.08
OberesMenue:
In order to acces the second instance of OberesMenue, you can add an id:
<ersteFrage>:
name: "ersteFrage"
GridLayout:
cols: 1
size_hint_y: 1
GridLayout:
cols: 1
size_hint_y: 0.08
OberesMenue:
id: in_ersteFrage
Then in your on_enter() method of Pruefungsmodus, you can change that instance by using:
def on_enter(self):
text = "Zeit"
self.manager.get_screen('ersteFrage').ids.in_ersteFrage.labeltext = text #DAS Klappt nicht
Note that this changes the Label in the second instance of OberesMenue, but has no effect on the first. Your original code was changing the first instance, but not the second. And you can't put the same instance in both places at the same time, since a Widget can have only one parent at a time.
So, if those instances are intended to be identical, then you need to change the Label in both.
If you really want to share the same instance, you can keep your own record of where it is and use remove_widget() and add_widget() to move it from one parent to another.
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.
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
I'm new to stack overflow but I've been programming in python for a couple years. One thing I havent done much of is object oriented programming. I just started learning kivy and I think I might have screwed up the root of my program by organizing it wrong. I used classes to define each label, button, layout...etc. now I'm wondering how I can reference the attributes of each text input to use what's filled in for other methods I want to define.
Example: have a button when pressed gets the input from two different text inputs and adds them together and a label displays it.
You can see what I've tried in my code but I'm having a hell of a time figuring out how to reference all these things from different classes.
I hope my code is understandable...sorry its lengthy but I want you to see the whole scope of what I did. I'm really hoping I can get a solution to where I can keep my organization and have certain things only show up under their own files but I understand if I have to change a lot of things...
Main.py
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.button import Button
from kivy.uix.textinput import TextInput
from kivy.uix.label import Label
from kivy.uix.tabbedpanel import TabbedPanel
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import ObjectProperty
from kivy.uix.gridlayout import GridLayout
from kivy.uix.anchorlayout import AnchorLayout
from kivy.uix.togglebutton import ToggleButton
from kivy.uix.relativelayout import RelativeLayout
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.screenmanager import ScreenManager, Screen
from os import listdir
from kivy.core.window import Window
#load all files with 'kv' in folder
kv_path = './kv/'
for kv in listdir(kv_path):
Builder.load_file(kv_path+kv)
#move the keyboard below text input
Window.softinput_mode = 'below_target'
#classes for savings and loan screens
class SaveButton(Button):
pass
class LoanButton(Button):
pass
class Calculate(Button):
def add(self):
total = SaveDepositInput.inideposit +GoalAmountInput.amount
return total
pass
class TotalsLabel(Label):
pass
#layout classes
class MainBoxLayout(BoxLayout):
pass
class InsideAnchorLayout(AnchorLayout):
pass
class OneColGridlayout(GridLayout):
pass
class AColGridLayout(GridLayout):
pass
class TwoColGridLayout(GridLayout):
pass
class WidgetRelativeLayout(RelativeLayout):
pass
#Toggle Buttons
class DailyToggle(ToggleButton):
pass
class WeeklyToggle(ToggleButton):
pass
class BiWeeklyToggle(ToggleButton):
pass
class MonthlyToggle(ToggleButton):
pass
class YearlyToggle(ToggleButton):
pass
class NoneToggle(ToggleButton):
pass
class Monthly2Toggle(ToggleButton):
pass
class Yearly2Toggle(ToggleButton):
pass
#classes for screen change
class SaveScreen(Screen):
pass
class LoanScreen(Screen):
pass
class SaveLoanTabs(TabbedPanel):
pass
#classes for savings screen
class OutputLabel(Label):
pass
class GoalOutputLabel(Label):
pass
class NoReinvestLabel(Label):
pass
class SaveInstructLabel(Label):
pass
class SaveDepositLabel(Label):
pass
class SaveDepositInput(TextInput):
def inideposit(self):
initial = root.TextInput.text
deposit = int(initial)
return deposit
pass
class SaveYearsLabel(Label):
pass
class SaveYearsInput(TextInput):
pass
class SaveMonthsInput(TextInput):
pass
class ChooseCompoundLabel(Label):
pass
class SaveInterestLabel(Label):
pass
class SaveInterestInput(TextInput):
pass
class RepeatDepositLabel(Label):
pass
class RepeatDeposit2Label(Label):
pass
class RepeatDepositInput(TextInput):
pass
class YearsLabel(Label):
pass
class MonthsLabel(Label):
pass
class GoalAmount(Label):
pass
class GoalAmountInput(TextInput):
def amount(self):
initial = root.TextInput.text
goal = int(initial)
return goal
pass
#classes for loan screen
class LoanOutputLabel(Label):
pass
class LoanInstructLabel(Label):
pass
class LoanAmountLabel(Label):
pass
class LoanAmountInput(TextInput):
pass
# Create the screen manager
sm = ScreenManager()
sm.add_widget(SaveScreen(name='save'))
sm.add_widget(LoanScreen(name='loan'))
#class to run app
class InterestApp(App):
def build(self):
self.title = "Compound Interest and Loan Application"
return sm
#run app
if __name__ == "__main__":
InterestApp().run()
Main.kv file(mostly used for layout formatting)
<SaveScreen>:
MainBoxLayout:
GridLayout:
cols: 2
SaveButton:
on_press: root.manager.current = 'save'
LoanButton:
on_press: root.manager.current = 'loan'
InsideAnchorLayout:
GridLayout:
cols: 1
canvas:
Color:
rgba: .7,1,.7,1
Rectangle:
size: self.size
pos: self.pos
SaveInstructLabel:
InsideAnchorLayout:
TwoColGridLayout:
SaveDepositLabel:
SaveDepositInput:
InsideAnchorLayout:
AColGridLayout:
ChooseCompoundLabel:
InsideAnchorLayout:
AColGridLayout:
cols: 3
DailyToggle:
MonthlyToggle:
YearlyToggle:
InsideAnchorLayout:
TwoColGridLayout:
SaveInterestLabel:
SaveInterestInput:
InsideAnchorLayout:
AColGridLayout:
RepeatDepositLabel:
InsideAnchorLayout:
AColGridLayout:
cols: 5
NoneToggle:
WeeklyToggle:
BiWeeklyToggle:
Monthly2Toggle:
Yearly2Toggle:
InsideAnchorLayout:
TwoColGridLayout:
RepeatDeposit2Label:
RepeatDepositInput:
InsideAnchorLayout:
TwoColGridLayout:
size_hint_y: None
height: dp(50)
SaveYearsLabel:
TwoColGridLayout:
YearsLabel:
SaveYearsInput:
MonthsLabel:
SaveMonthsInput:
InsideAnchorLayout:
TwoColGridLayout:
GoalAmount:
GoalAmountInput:
InsideAnchorLayout:
GridLayout:
cols: 1
canvas:
Color:
rgba: .5,1,1,1
Rectangle:
size: self.size
pos: self.pos
size_hint: None, None
height: dp(80)
width: self.parent.width - dp(15)
TotalsLabel:
OutputLabel:
GoalOutputLabel:
NoReinvestLabel:
InsideAnchorLayout:
AColGridLayout:
Calculate:
<LoanScreen>:
MainBoxLayout:
TwoColGridLayout:
SaveButton:
on_press: root.manager.current = 'save'
LoanButton:
on_press: root.manager.current = 'loan'
Buttons.kv
<SaveButton>:
id: 'save'
text: "[u]Save[/u]"
color: 1, .9, 0, 1
background_normal: ''
background_color: (.5, .5, .5, 1) if self.state == 'normal' else (0, .75, 1, 1)
group: 'menu'
markup: True
<LoanButton>:
text: "[u]Loan[/u]"
markup: True
color: 1, .9, 0, 1
background_normal: ''
background_color: (.5, .5, .5, 1) if self.state == 'normal' else (0, .75, 1, 1)
group: 'menu'
<DailyToggle>:
text: 'Daily'
group: 'compound'
<MonthlyToggle>:
text: 'Monthly'
group: 'compound'
<YearlyToggle>:
text: 'Yearly'
group: 'compound'
<WeeklyToggle>:
text: 'Weekly'
group: 'repeat'
<Yearly2Toggle>:
text: 'Yearly'
group: 'repeat'
<Monthly2Toggle>:
text: 'Monthly'
group: 'repeat'
<BiWeeklyToggle>:
text: 'Bi-Weekly'
group: 'repeat'
<NoneToggle>:
text: 'None'
group: 'repeat'
<Calculate>:
text: '[u][b]Calculate[/b][/u]'
markup: True
on_release: self.add
Labels.kv
<SaveInstructLabel>:
text: "[b]This is the Savings screen. It will calculate compounded interest over a period of time and tell you the result. Follow each prompt to calculate.[/b]"
text_size: root.width, None
size: self.texture_size
valign: 'middle'
halign: 'center'
color: 0,0,0,1
markup: True
<SaveDepositLabel>:
text: "Enter initial deposit amount:"
text_size: root.width, None
size: self.texture_size
valign: 'middle'
halign: 'center'
color: 0,0,0,1
<ChooseCompoundLabel>:
text: "Choose frequency of compounding interest:"
text_size: root.width, None
size: self.texture_size
valign: 'middle'
halign: 'center'
color: 0,0,0,1
<SaveInterestLabel>:
text: 'Enter the interest APY:'
text_size: root.width, None
size: self.texture_size
valign: 'middle'
halign: 'center'
color: 0,0,0,1
<RepeatDepositLabel>:
text: 'How often will you make a deposit:'
text_size: root.width, None
size: self.texture_size
valign: 'middle'
halign: 'center'
color: 0,0,0,1
<SaveYearsLabel>:
text: 'Enter the amount of years and months you will have this account build:'
text_size: root.width, None
size: self.texture_size
valign: 'middle'
halign: 'center'
color: 0,0,0,1
font_size: dp(15)
<YearsLabel>:
text: 'Years:'
text_size: root.width, None
size: self.texture_size
valign: 'middle'
halign: 'right'
color: 0,0,0,1
<MonthsLabel>:
text: 'Months:'
text_size: root.width, None
size: self.texture_size
valign: 'middle'
halign: 'right'
color: 0,0,0,1
<GoalAmount>:
text: '(Optional)Enter an amount you would like to reach:'
text_size: root.width, None
size: self.texture_size
valign: 'middle'
halign: 'center'
color: 0,0,0,1
<OutputLabel>:
text: app.Calculate.add
text_size: root.width, None
size: self.texture_size
valign: 'middle'
halign: 'center'
color: 0,0,0,1
<GoalOutputLabel>:
text: 'total years to reach goal'
text_size: root.width, None
size: self.texture_size
valign: 'middle'
halign: 'center'
color: 0,0,0,1
<NoReinvestLabel>:
text: 'if you didnt reinvest'
text_size: root.width, None
size: self.texture_size
valign: 'middle'
halign: 'center'
color: 0,0,0,1
<TotalsLabel>:
text: '[u][b]TOTALS:[/b][/u]'
markup: True
valign: 'middle'
halign: 'center'
color: 0,0,0,1
<RepeatDeposit2Label>:
text: 'Enter recurring deposit amount:'
text_size: root.width, None
size: self.texture_size
valign: 'middle'
halign: 'center'
color: 0,0,0,1
Textboxes.kv
<SaveDepositInput>:
multiline: False
hint_text: '$0.00'
input_filter: 'float'
size_hint_y: None
height: dp(25)
<SaveInterestInput>:
multiline: False
hint_text: '0.0'
input_filter: 'float'
size_hint_y: None
height: dp(25)
<SaveYearsInput>:
multiline: False
hint_text: '0'
input_filter: 'int'
size_hint_y: None
height: dp(25)
<SaveMonthsInput>:
multiline: False
hint_text: '0'
input_filter: 'int'
size_hint_y: None
height: dp(25)
<GoalAmountInput>:
multiline: False
hint_text: '$0.00'
input_filter: 'float'
size_hint_y: None
height: dp(25)
<RepeatDepositInput>:
multiline: False
hint_text: '$0.00'
input_filter: 'float'
size_hint_y: None
height: dp(25)
And Layouts.kv
<MainBoxLayout>:
spacing: dp(2)
orientation: 'vertical'
canvas.before:
Color:
rgba: .7,1,.7,1
Rectangle:
size: self.size
pos: self.pos
<TwoColGridLayout>:
cols: 2
size_hint: .95, .70
canvas:
Color:
rgba: .5,1,1,1
Rectangle:
size: self.size
pos: self.pos
<OneColGridLayout>:
cols: 1
<AColGridLayout>:
cols: 1
size_hint: .95,.70
canvas:
Color:
rgba: .5,1,1,1
Rectangle:
size: self.size
pos: self.pos
<WidgetRelativeLayout>:
<InsideAnchorLayout>:
anchor_x: 'center'
In your Calculate Button, the add method is trying to call static methods, but the methods you name are actually instance methods. So you need to call them as instance methods. That means that you must have the instances of SaveDepositInput and GoalAmountInput. Since all of these things are in your SaveScreen, you can easily reference them using ids. To do this you cn add an id to SaveDepositInput in your SaveScreen:
InsideAnchorLayout:
TwoColGridLayout:
SaveDepositLabel:
SaveDepositInput:
id: save_deposit_input
and for the GoalInputAmount:
InsideAnchorLayout:
TwoColGridLayout:
GoalAmount:
GoalAmountInput:
id: goal_amount_input
then, in order to access these from the Calculate Button:
InsideAnchorLayout:
AColGridLayout:
Calculate:
gai: goal_amount_input
sdi: save_deposit_input
Then, the CalculateButton class becomes:
class Calculate(Button):
def add(self):
total = self.sdi.inideposit() + self.gai.amount()
return total
A couple other issues. The CalculateButton in your Buttons.kv should be:
<Calculate>:
text: '[u][b]Calculate[/b][/u]'
markup: True
on_release: self.add()
( you were missing the ())
And you have a similar class vs instance issue with your OutputLabel in your Labels.kv.