Can't access popups content in kivy - python

I have a problem with accessing popups content.
Here is popup class in .py:
class LicencePopup(Popup):
def dismiss_popup(self, *args):
self.dismiss()
def submit_licence(self):
# print self.content.ids.licence_field.text
# print self.ids.licence_field.text
# print self.content.ids[licence_field].text
Popup in .kv look like this:
<LicencePopup>:
size_hint: .3, .35
title: 'Enter license key'
separator_height: 0
title_size: 35
BoxLayout:
orientation: "vertical"
TextInput:
id: license_field
multiline: False
text: "59353-58506-87377-00410"
font_size: 24
Label:
id: license_label
BoxLayout:
Button:
text: "Cancel"
on_release: root.dismiss_popup()
Button:
text: "Submit"
on_release: root.submit_licence()
My problem is how to get text from TextInput(id: licence_field).
I have tried a few things(commented prints) but I can't get this working.
Can you please help with this?

Related

Popup in Kivy Python does not get dismissed for more than one time

I have made a popup to show up when an error occurs, with a button that closes the popup when clicked. All worked well until I tried getting an error for 2 times. In the second time the popup did not close and I am wondering if there is a way to work it out.
This is the python code:
class MyPopup(Popup):
filechooser= ObjectProperty(None)
class ErrorPopup(Popup):
filechooser= ObjectProperty(None)
class Main(FloatLayout):
audio_check= ObjectProperty(None)
video_check= ObjectProperty(None)
spinner_id= ObjectProperty(None)
yt_link=ObjectProperty(None)
name=ObjectProperty(None)
error_label=ObjectProperty(None)
def submit_text(self):
self.error_popup=MyApp()
if self.audio_check.active and self.video_check.active:
try:
YouTube(self.yt_link.text).streams.filter(res=self.spinner_id.text).first().download(path, filename=self.name.text+'.mp4')
except:
self.error_popup.error()
elif self.audio_check.active and not self.video_check.active:
try:
YouTube(self.yt_link.text).streams.filter(only_audio=True).first().download(path, filename=self.name.text+'.mp3')
except:
self.error_popup.error()
elif not self.audio_check.active and self.video_check.active:
try:
YouTube(self.yt_link.text).streams.filter(res=self.spinner_id.text, only_video =True).first().download(path, filename=self.name.text+'.mp4')
except:
self.error_popup.error()
elif not self.audio_check.active and not self.video_check.active:
self.error_popup.error()
def spinner_clicked(self, value):
self.ids.spinner_id.text= value
class MyApp(App):
def build(self):
return Main()
def open_popup(self):
self.popup = MyPopup()
self.popup.open()
def dismiss_popup(self):
self.popup.dismiss()
global path
path=self.popup.filechooser.path
def error(self):
self.error_popup= ErrorPopup()
self.error_popup.open()
def try_again(self):
self.error_popup.dismiss()
print("Andrew")
if __name__ == '__main__':
MyApp().run()
This is the kivy code:
<MyPopup>:
auto_dismiss: False
title: "Select a folder"
filechooser: filechooser
FloatLayout:
FileChooserIconView:
id: filechooser
Button:
id:my_button
text: 'Save'
size_hint: (0.1, 0.1)
pos_hint:{'x': 0, 'y': 0}
on_release: app.dismiss_popup()
<ErrorPopup>:
title: "Error"
Button:
text: "Try Again"
on_release: app.try_again()
<Main>:
audio_check: audio_check
video_check: video_check
spinner_id: spinner_id
yt_link: yt_link
name: name
folder_button: folder_button
BoxLayout:
orientation:'vertical'
cols: 4
Label:
text: "YouTube Downloader"
halign: 'center'
bold: True
font_size:'50sp'
TextInput:
id: yt_link
size_hint: (.5, .2)
multiline: False
hint_text: 'Enter the link of the Youtube video you want to download.'
pos_hint: {"x": 0.25}
TextInput:
id: name
size_hint: (.5, .2)
multiline: False
hint_text: 'Enter the name you want the file to have.'
pos_hint: {"x": 0.25}
BoxLayout:
cols:4
BoxLayout:
Label:
text: "Audio:"
halign: 'center'
font_size:'20sp'
CheckBox:
id: audio_check
BoxLayout:
Label:
text: "Video:"
halign: 'center'
font_size:'20sp'
CheckBox:
id: video_check
FloatLayout:
Spinner:
id: spinner_id
text: "Quality"
values: ['144p', '240p', '360p', '480p', '720p', '1080p', '1440p', '2160p']
on_text: root.spinner_clicked(spinner_id.text)
size_hint: None, None
size: 130, 50
pos_hint: {'x': .2, 'y':.4}
FloatLayout:
Button:
id:folder_button
text: 'Folder'
on_release: app.open_popup()
size_hint: None, None
size: 130, 50
pos_hint: {'x':0.2,'y':.4}
Button:
text: "Submit"
size_hint: (.5, .2)
pos_hint: {"x": 0.25}
on_release: root.submit_text()
The problem is in your submit() method. The code:
self.error_popup=MyApp()
is creating a new instance of MyApp, then the code:
self.error_popup.error()
is calling the error() method from that new instance of MyApp. You need to be calling the methods of the App that you are running. To do that, just remove the line:
self.error_popup=MyApp()
And replace:
self.error_popup.error()
with:
App.get_running_app().error()
This makes sure that you are calling the error() method of the App that you are running.

Why does kivy root.manager return None?

I am currently building an app for self measurement. I've faced the following problem : I want to have a result screen, with progress bars for my achievements. So far it looks like this:
<ResultScreen>:
BoxLayout:
Button:
text: 'Назад, к музыке'
on_press: root.manager.current = 'music'
ProgressBar:
max : 1000
value : root.manager.get_screen('music').slider.value
The problem is, root.manager works fine when applied to the Button and returns to the given screen. However in ProgressBar it appears to be None and returns the following error:
AttributeError: 'NoneType' object has no attribute 'get_screen'
What is wrong?
The full code:
main.py:
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.properties import (
NumericProperty, ReferenceListProperty, ObjectProperty
)
from kivy.vector import Vector
from kivy.clock import Clock
from kivy.uix.screenmanager import ScreenManager, Screen
class PongScreen(Screen):
pass
class MusicScreen(Screen):
pass
class DiscreteScreen(Screen):
pass
class ResultScreen(Screen):
pass
class PongApp(App):
def build(self):
sm = ScreenManager()
sm.add_widget(PongScreen(name='menu'))
sm.add_widget(MusicScreen(name='music'))
sm.add_widget(DiscreteScreen(name='discrete'))
sm.add_widget(ResultScreen(name='result'))
return sm
if __name__ == '__main__':
PongApp().run()
pong.kv:
#:kivy 1.0.9
#:import Factory kivy.factory.Factory
<MusicScreen>:
BoxLayout:
Button:
text: 'Назад в меню'
on_press: root.manager.current = 'menu'
Button:
text: 'Дальше, к дискретке'
on_press: root.manager.current = 'discrete'
Slider:
id: slider
min: 0
max: 20
step: 1
orientation: 'vertical'
Label:
text: 'Тактов выучено\n' + str(slider.value)
CheckBox:
id : new_song_checkbox
Label:
text : 'Новую песню выучил?\n' + str(new_song_checkbox.active)
CheckBox:
id : music_pleasure_checkbox
Label:
text : 'Доволен ли исполнением\n' + str(music_pleasure_checkbox.active)
<DiscreteScreen>:
BoxLayout:
Button:
text: 'В меню'
on_press: root.manager.current = 'menu'
Button:
text: 'Назад, к музыке'
on_press: root.manager.current = 'music'
Slider:
id: slider
min: 0
max: 180
step: 15
orientation: 'vertical'
Label:
text: 'Минут на код затрачено\n' + str(slider.value)
CheckBox:
id : article_checkbox
Label:
text : 'Статью прочитал?\n' + str(article_checkbox.active)
CheckBox:
id : lecture_checkbox
Label:
text : 'Посмотрел ли лекцию?\n' + str(lecture_checkbox.active)
<DiscreteScreen>:
BoxLayout:
Button:
text: 'В меню'
on_press: root.manager.current = 'menu'
Button:
text: 'Назад, к музыке'
on_press: root.manager.current = 'music'
Button:
text: 'Дальше, к результатам'
on_press: root.manager.current = 'result'
Slider:
id: slider
min: 0
max: 180
step: 15
orientation: 'vertical'
Label:
text: 'Минут на код затрачено\n' + str(slider.value)
CheckBox:
id : article_checkbox
Label:
text : 'Статью прочитал?\n' + str(article_checkbox.active)
CheckBox:
id : lecture_checkbox
Label:
text : 'Посмотрел ли лекцию?\n' + str(lecture_checkbox.active)
<ResultScreen>:
BoxLayout:
Button:
text: 'Назад, к музыке'
on_press: root.manager.current = 'music'
ProgressBar:
max : 1000
value : root.manager.get_screen('music').slider.value
<PongScreen>:
BoxLayout:
Button:
text: 'К музыке'
on_press: root.manager.current = 'music'
Button:
text: 'К дискретке'
on_press: root.manager.current = 'discrete'
Button:
text: 'К результатам'
on_press: root.manager.current = 'result'
Button:
text: 'Выход'
on_press: app.stop()
First of all value : root.manager.get_screen('music').slider.value is wrong because root.manager.get_screen('music') is supposed to be a Screen object and by default it doesn't have (also not in your code) any prop. slide.
Perhaps you mean value : root.manager.get_screen('music').ids.slider.value. But this will not solve your problem. Let's try to analyze the problem in simple way.
When the method run is called, the kv-rules are applied (by method load_kv) first then method build is called. In the method build you defined ScreenManager first thereafter added the Screens and described the screens in kvlang. Now when it encounters your .kv file and looks for root.manager (in value : root.manager.get_screen('music').ids.slider.value) it finds None (the default value, as it has not yet been added to ScreenManager, defined in your build method). That's the reason behind the AttributeError.
Now to solve this issue one of many ways could be,
You delay the value assigning process by a (built-in or custom) method like on_enter etc. as,
<ResultScreen>:
on_enter: pb.value = self.manager.get_screen('music').ids.slider.value
BoxLayout:
Button:
text: 'Назад, к музыке'
on_press: root.manager.current = 'music'
ProgressBar:
id: pb
max : 1000
Set a conditional statement (likely to be preferable) as,
ProgressBar:
id: pb
max : 1000
value : root.manager.get_screen('music').ids.slider.value if root.manager is not None else 0
Define the root (i.e. ScreenManager here) entirely in kvlang.
Other ways could be creating a property for slide.value in the associate class; manage it in the build method etc.

Set global font size for all children in box layout in Kivy

I've got three buttons in a box layout in Kivy. I want each of them to have the same fontsize. Is there a way to specify the font size for all widgets within a box layout, instead of having to define the font size in the child widgets?
This box layout's part of the .kv file looks like this
BoxLayout:
id: action_buttons
orientation: "horizontal"
size_hint: 1, None
height: "100dp"
Button:
id: cust_query
text: "Send Custom Query"
font_size: 24
Button:
id: man_query
text: "Manually Check Tables"
font_size: 24
ToggleButton:
id: sched_query
text: "Start Query Schedule"
on_state: root.schedule_switch_state(self)
font_size: 24
Is there a way to do this more like so:
BoxLayout:
id: action_buttons
orientation: "horizontal"
size_hint: 1, None
height: "100dp"
font_size: 24
Button:
id: cust_query
text: "Send Custom Query"
Button:
id: man_query
text: "Manually Check Tables"
ToggleButton:
id: sched_query
text: "Start Query Schedule"
on_state: root.schedule_switch_state(self)
I think I found a solution : font_size: self.parent.font_size
in *.kv
#:kivy 2.0.0
<Main>:
BoxLayout:
id: myboxlayout
orientation: "horizontal"
size: root.size
font_size: 24
Button:
text: "Button 1"
font_size: self.parent.font_size
Button:
text: "Button 2"
font_size: self.parent.font_size
first set a font size for the boxlayout
then point the fontsize of the button to their parent's fontisze
// hope this help : )

Kivy: How to submit the state/value of a CheckBox after submit Button

I'm a total beginner in coding and I wanted to develop a Multiple Choice Quiz App in chemistry for my students.
How can I after choosing one of the three displayed Options in my code in Kivy and hitting the submit button display that the right answere was selected?
I have three checkboxes and a submit button. After an answer is clicked and the submit button is clicked, the program schoul print correct or wrong. I managed to get the check boxes and the submit button but I don't know how to write something that does the folowing:
x Click a CheckBox [user]
x Click the submit Button [user]
x function in root class evalueates if the correct Checkbox was choosen.
x function prints correct or wrong in Label with the id: result.
I have triede to work through the documentation for kivy but I didn't understand much to be honest. I have tried different answeres here in StackOverFlow like the (on_active: root.gender = self.text) method but I got an invalid attribute 'active' error.
Logic code: QuizTestApp.py
from kivy.app import App
from kivy.uix.screenmanager import Screen, ScreenManager
from kivy.lang import Builder
Builder.load_file('Question_1.kv')
Builder.load_file('Question_2.kv')
class Question_1(Screen):
#############################################
### The choice function should evaluate the CheckBox and write output if its
### right of wrong.
#############################################
def choice(self, answer):
if answer == True:
output = 'Correct :D'
else:
output = 'wrong :/'
self.ids.result.text = output
###########################################################
class Question_2(Screen):
pass
sm = ScreenManager()
sm.add_widget(Question_1(name='quest1'))
sm.add_widget(Question_2(name='quest2'))
class QuizApp(App):
def build(self):
return sm
if __name__ == '__main__':
QuizApp().run()
Kivy code: Question1.kv
<CheckBoxBox#CheckBox>:
<CheckBoxLabel#ButtonBehavior+Label>:
<CheckBoxQuestion#BoxLayout>:
text: ''
group: ''
CheckBoxBox:
id: cb
group: root.group
CheckBoxLabel:
on_press: cb._do_press()
text: root.text
<Question_1>:
BoxLayout:
orientation: 'vertical'
Label:
size_hint_y: 0.2
text: '1. Question'
font_size: 30
BoxLayout:
orientation: 'horizontal'
size_hint_y: 0.6
BoxLayout:
orientation: 'vertical'
Label:
text: 'Niacin ist giftig'
Label:
text: 'Thiamin ist essentiell'
Label:
text: 'Vitamin C ist wichtig'
BoxLayout:
orientation: 'vertical'
CheckBoxQuestion:
text: '1, 2'
group: 'opts'
id: chk_1
CheckBoxQuestion:
text: '1, 3'
group: 'opts'
id: chk_2
CheckBoxQuestion:
text: '2, 3'
group: 'opts'
id: chk_3
BoxLayout:
orientation: 'horizontal'
size_hint_y: 0.2
Button:
text: 'back'
Label:
id: result
text: ''
###################################
### The next Button should submit the value/state of the checkbox to the
### choice function
###################################
Button:
text: 'submit'
on_press: root.choice(chk_3)
####################################
Button:
text: 'next'
on_press: root.manager.current = 'quest2'`

Can you automatically load user information in kivy

I am making an app where there is a profile screen in which you can enter generic profile information (name, height, weight, ect..) using textinput boxes. I know there is a way to put a button next to each textinput box to save the information and another button to load the information. I am wondering if there is a way to automatically load this information when the user opens the app rather than manually loading the information by hitting a button.
<Phone>:
result: _result
h: _h
w: _w
AnchorLayout:
anchor_x: 'center'
anchor_y: 'top'
ScreenManager:
size_hint: 1, .9
id: _screen_manager
Screen:
name: 'home'
canvas.before:
Rectangle:
pos: self.pos
size: self.size
source: "/home/aaron/Desktop/main.png"
Label:
markup: True
text: '[size=100][color=ff3333]Welcome to [color=ff3333]Diabetes Manager[/color][/size]'
Screen:
name: 'menu'
GridLayout:
cols: 2
padding: 50
canvas.before:
Rectangle:
pos: self.pos
size: self.size
source: "/home/aaron/Desktop/main.png"
Button:
text: 'My Profile'
on_press: _screen_manager.current = 'profile'
Button:
text: 'History'
on_press: _screen_manager.current = 'history'
Button:
text: 'New Entry'
on_press: _screen_manager.current = 'new_entry'
Button:
text: 'Graph'
on_press: _screen_manager.current = 'graph'
Button:
text: 'Diet'
on_press: _screen_manager.current = 'diet'
Button:
text: 'Settings'
on_press: _screen_manager.current = 'settings'
Screen:
name: 'profile'
GridLayout:
cols: 1
BoxLayout:
Label:
size_hint_x: 0.22
bold: True
markup: True
text: '[size=40][color=0000ff]Name[/color][/size]'
TextInput:
id: _name
hint_text: 'Name'
BoxLayout:
Label:
size_hint_x: 0.22
bold: True
markup: True
text: '[size=40][color=0000ff]Gender[/color][/size]'
TextInput:
id: _gender1
hint_text: 'Gender'
BoxLayout:
Label:
size_hint_x: 0.22
bold: True
markup: True
text: '[size=34][color=0000ff]Type of Diabetes[/color][/size]'
TextInput:
id: _type
hint_text: 'Type of Diabetes'
BoxLayout:
Label:
size_hint_x: 0.22
bold: True
markup: True
text: '[size=40][color=0000ff]Height (in)[/color][/size]'
TextInput:
id: _h
hint_text: 'Height in inches'
BoxLayout:
Label:
size_hint_x: 0.22
bold: True
markup: True
text: '[size=40][color=0000ff]Weight (lb)[/color][/size]'
TextInput:
id: _w
hint_text: 'Weight in pounds'
BoxLayout:
Button:
text: 'Calculate BMI'
on_press: root.product(*args)
Label:
size_hint_x: 4.5
id:_result
bold: True
markup: True
text: '[size=40][color=0000ff]BMI[/color][/size]'
BoxLayout:
Label:
size_hint_x: 0.22
bold: True
markup: True
text: '[size=30][color=0000ff]List of Medications[/color][/size]'
TextInput:
id: _meds
hint_text: 'List of Medications'
BoxLayout:
Label:
size_hint_x: 0.22
bold: True
markup: True
text: '[size=38][color=0000ff]Insulin Times[/color][/size]'
TextInput:
id: _times
hint_text: 'Please Enter Times to Take Insulin'
Screen:
name: 'history'
GridLayout:
cols:1
Screen:
name: 'new_entry'
GridLayout:
cols:1
BoxLayout:
Label:
size_hint_x: 0.22
bold: True
markup: True
text: '[size=40][color=0000ff]Time[/color][/size]'
TextInput:
id: _time
hint_text: 'Current Time'
BoxLayout:
Label:
size_hint_x: 0.22
bold: True
markup: True
text: '[size=28][color=0000ff]Blood Sugar (mg/dL)[/color][/size]'
TextInput:
id: _glucose_reading
hint_text: 'Current Blood Sugar'
BoxLayout:
Label:
size_hint_x: 0.22
bold: True
markup: True
text: '[size=40][color=0000ff]Carbs[/color][/size]'
TextInput:
id: _food
hint_text: 'Total Carbs for meal'
BoxLayout:
Label:
size_hint_x: 0.22
bold: True
markup: True
text: '[size=30][color=0000ff]Medications Taken[/color][/size]'
TextInput:
id: _meds_taken
hint_text: 'Please Enter Any Medications Taken'
Screen:
name: 'graph'
GridLayout:
cols: 3
padding: 50
Label:
markup: True
text: '[size=24][color=dd88ff]Your Graph[/color][/size]'
Screen:
name: 'diet'
GridLayout:
cols: 3
padding: 50
Label:
markup: True
text: '[size=24][color=dd88ff]Reccomended Diet[/color][/size]'
Screen:
name: 'settings'
GridLayout:
cols: 3
padding: 50
Label:
markup: True
text: '[size=24][color=dd88ff]Settings[/color][/size]'
AnchorLayout:
anchor_x: 'center'
anchor_y: 'bottom'
BoxLayout:
orientation: 'horizontal'
size_hint: 1, .1
Button:
id: btnExit
text: 'Exit'
on_press: app.stop()
Button:
text: 'Menu'
on_press: _screen_manager.current = 'menu'
You can save the info in a json (import json) file, and load it using on_start event method.
Kivy uses a subclass of ConfigParser to parse standard ini files. Documentation on how to use this to load app-specific settings is on the kivy.app doc page.
From the docs:
class TestApp(App):
def build_config(self, config):
config.setdefaults('section1', {
'key1': 'value1',
'key2': '42'
})
def build(self):
config = self.config
return Label(text='key1 is %s and key2 is %d' % (
config.get('section1', 'key1'),
config.getint('section1', 'key2')))
Well, each App starts with build() function expecting a root widget to be returned, so either you can make a simple file loading with a function inside your App class and push values to each widget through ids or through root's widget children
or do the same loading function inside __init__() of your class where the widget values you want to update are.
For example class MyBox(BoxLayout) is a class with children which values you want to update. Then you call your loading function inside MyBox.__init__(). You can simplify it even more: use the loading function inside __init__() and create a list/dictionary/variables where you'll pass the values. Inside kv file you'll just access the variables through for example root.<variable>.

Categories

Resources