I am trying to display the value of a slider on a different screen. i have tried this(below code) but for some reason, the value doesn't seem to show up. the code runs fine but no value is returned. Thanks for your help :) Cheers.
temperature screen
here is a snippet of the python code:
class Thermostat(Screen):
label = StringProperty()
def display(self):
tempVal = self.label
return str(tempVal)
and the kv files:
<Thermostat>:
name: "thermostat"
BoxLayout:
orientation: 'horizontal'
cols: 2
Label:
id: label
font_size: "11sp"
text: "INSIDE: " + root.display()
Label:
text: "More Info"
font_size: "11sp"
kv file 2:This screen holds the true value from the slider, i am trying to pass that value to the Thermostat screen.
<Temperature>:
BoxLayout:
size_hint_y: None
height: '48dp'
cols: 3
Label:
text: 'THERMOSTAT'
Slider:
id: temp
min: 40
max: 100
value: 1
step: 1
on_value: app.root.get_screen('thermostat').label = str('{}'.format(temp.value))
Label:
id: slide_val
text: '{}'.format(temp.value)
root.display is only called once, at the beginning of the program. For it to work well, every time you change the value of the slider root.display should be called.
However, it is very simple to do this using propertis in kv languaje:
from kivy.app import App
from kivy.uix.screenmanager import Screen, ScreenManager
from kivy.lang.builder import Builder
Builder.load_string('''
<Manager>:
id: manager
Thermostat:
id: thermostat
name: 'thermostat'
manager: 'screen_manager'
temp: temperature.temp #<<<<<<<<<<<<
Temperature:
id: temperature
name: 'temperature'
manager: 'screen_manager'
<Thermostat>:
temp: 0 #<<<<<<<<<<<<
BoxLayout:
orientation: 'horizontal'
cols: 3
Label:
id: label
font_size: "11sp"
text: "INSIDE: {}".format(root.temp) #<<<<<<<<<<<<
Label:
text: "More Info"
font_size: "11sp"
Button:
text: ">"
on_release: app.root.current= "temperature"
size_hint_x: None
width: 30
<Temperature>:
temp: temp_slider.value #<<<<<<<<<<<<
BoxLayout:
cols: 4
Button:
text: "<"
on_press: app.root.current = "thermostat"
size_hint_x: None
width: 30
Label:
text: 'THERMOSTAT'
Slider:
id: temp_slider
min: 40
max: 100
value: 40
step: 1
Label:
id: slide_val
text: str(root.temp)
''')
class Thermostat(Screen):
pass
class Temperature(Screen):
pass
class Manager(ScreenManager):
pass
class ExampleApp(App):
def build(self):
return Manager()
if __name__ == "__main__":
ExampleApp().run()
If you want to use the slider's value in your class Temperature, simply declare the property in the class:
from kivy.properties import NumericProperty
class Temperature(Screen):
temp = NumericProperty()
def __init__(self, **kwargs):
super(Temperature, self).__init__(**kwargs)
Related
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.
I would like to use global variables that once calculated with a method on the Input Screen, can be used to display information on the display screen but also be imported to the Display Screen to finish other calculations that will displayed on the screen.
My current global variables will be created on the Input Screen calculations() and Display Screen display fill. Also, the global variables will be used in an on_enter function in more calculations.
I am also having an issue getting the camera to capture the image. It displays on the screen but I dont get a saved picture.
main.py
import kivy
import time
from kivy.app import App
from kivy.lang import Builder
from kivy.metrics import dp, sp
from kivy.uix.button import Button
from kivy.uix.camera import Camera
from kivy.uix.gridlayout import GridLayout
from kivy.uix.image import Image
from kivy.uix.screenmanager import Screen, ScreenManager
Builder.load_file('tipBot.kv')
Builder.load_file('camera.kv')
Builder.load_file('input.kv')
#global variables
amount = ''
tip = ''
total = ''
split= ''
class CameraScreen(Screen):
pass
class DisplayScreen(Screen):
def displayfill(self):
input1 = self.manager.get_screen("input_screen")
amount = input1.ids.orgamount.text
tip_3 = input1.ids.orgtip.text
self.finalamount.ids.text = "Tip: {tip} Tip %: {tip_3} Total: {total}"
class InputScreen(Screen):
def calculations(self):
org_amount = self.ids.orgamount.text
org_tip = int(self.ids.orgtip.text)
org_split = int(self.ids.split1.text)
tip1 = org_tip/100
tip = round(tip1*float(org_amount), 2)
total = round(tip + float(org_amount), 2)
total_str = str(int(total))
total_x = total_str[-1]
if org_split == 0:
split = org_split
else:
split = round(total/org_split, 2)
class SettingScreen(Screen):
pass
class ScreenSwitch(ScreenManager):
pass
class tipBotApp(App):
def build(self):
self.title = "tibBot version: 1"
return ScreenSwitch()
def capture(self, *args):
cam = self.root.ids.camera
timestamp = time.strftime("%Y%m%d_%H%M%S")
cam.export_to_png("Image.png")
tipBotApp().run()
camera.kv
<CameraScreen>:
GridLayout:
cols: 1
Camera:
id: camera
BoxLayout:
cols: 2
rows: 1
Button:
id: camerainput
text: "CAPTURE"
on_press: app.capture
Button:
id: cameramanual
text: "MANUAL ENTRY"
pos: dp(600), dp(400)
on_press: app.root.current = "input_screen"
input.kv
<InputScreen>:
GridLayout:
cols: 1
Label:
text: "PLEASE ENTER INFORMATION"
bold: True
font_size: '35sp'
GridLayout:
cols: 2
rows: 6
Label:
text: "Enter Original Amount of Bill:"
bold: True
font_size: '30sp'
TextInput:
id: orgamount
hint_text: 'Enter number w/ 2 decimal places'
hint_text_color: 'gray'
multiline: False
font_size: '30sp'
Label:
text: 'Enter tip amount as whole number:'
bold: True
font_size: '30sp'
TextInput:
id: orgtip
hint_text_color: 'gray'
hint_text: 'Enter a whole number'
multiline: False
font_size: '30sp'
Label:
text: 'Number splitting bill:'
bold: True
font_size: '30sp'
TextInput:
id: split1
hint_text: 'Enter # splitting bill'
hint_text_color: 'gray'
font_size: '30sp'
multiline: False
GridLayout:
cols: 3
Button:
id: inputsubmit
text: 'SUBMIT'
on_press: root.calculations()
on_press: app.root.current = "display_screen"
Button:
id: inputreset
text: 'RESET'
Button:
id: inputsetting
text: 'SETTINGS'
tipBot.kv
<ScreenSwitch>:
CameraScreen:
name: 'camera_screen'
id: camera_screen
DisplayScreen:
name: 'display_screen'
id: display_screen
InputScreen:
name: 'input_screen'
id: input_screen
SettingScreen:
name: 'setting_screen'
id: setting_screen
display.kv
<DisplayScreen>:
Gridlayout:
cols: 1
Label:
text: "Original Amount Tip Information"
bold: True
font_size: '40sp'
TextInput:
id: finalamount
bold: True
font_size: '40sp'
Label:
text: "Rounded to Nearest Dollar"
bold: True
font_size: '40sp'
TextInput:
id: onedollaramount
bold: True
font_size: '40sp'
You are not actually accessing the global variables. If you create a variable with the same name as a global variable in a method, that variable will be a local variable that hides the global variable. For example, in your displayfill() method, there is a local variable named amount that is not related to the global variable with the same name. The fix is to add the line:
global amount
at the start of the displayfill() method.
I have a kivymd app that has a screen with a button on it. When you click this button an MDCard will appear on the screen. When you click on this new MDCard it will call a function that will print a message on the terminal. However, I am having trouble getting this MDCard to call the function. I am getting the error:
AttributeError: 'MDCard' object has no attribute 'option'
The MDCard is in a separate kv string from the main kv string. Essentially I have two kv strings. When you press the button, the second kv string will be added as a widget to the first kv string.
I figured it is because the second kv string doesn't have a class as a root but I don't know how to do this. How can I get the MDCard to call the function??
MAIN.PY
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import ObjectProperty
from kivymd.app import MDApp
from button_screen import button_screen
MainNav = '''
<ContentNavigationDrawer>:
ScrollView:
MDList:
OneLineListItem:
text: 'Go to Button Screen'
on_press:
root.nav_drawer.set_state("close")
root.screen_manager.current = "go_to_button_screen"
Screen:
MDToolbar:
id: toolbar
pos_hint: {"top": 1}
elevation: 10
left_action_items: [["menu", lambda x: nav_drawer.set_state("open")]]
MDNavigationLayout:
x: toolbar.height
ScreenManager:
id: screen_manager
Screen:
name: "words_nav_item"
button_screen:
name: "go_to_button_screen"
MDNavigationDrawer:
id: nav_drawer
ContentNavigationDrawer:
screen_manager: screen_manager
nav_drawer: nav_drawer
'''
class ContentNavigationDrawer(BoxLayout):
screen_manager = ObjectProperty()
nav_drawer = ObjectProperty()
class main_test(MDApp):
def build(self):
self.theme_cls.primary_palette = "Red"
return Builder.load_string(MainNav)
main_test().run()
BUTTON SCREEN .PY FILE
from kivy.lang import Builder
from kivymd.uix.screen import MDScreen
button_screen_kv = '''
<button_screen>:
MDGridLayout:
cols: 1
size: root.width, root.height
spacing: 40
md_bg_color: [0,0,.1,.1]
MDGridLayout:
cols: 1
size_hint_y: None
height: 40
MDGridLayout:
cols: 1
Button:
text: "Click to add card"
on_release:
root.add_card("card 1")
MDGridLayout:
id: add_card_here_id
cols: 1
'''
md_card_kv = '''
MDCard:
orientation: 'vertical'
size_hint: None, None
size: "360dp", "120dp"
ripple_behavior: True
on_release:
root.option("MDCard was clicked")
MDLabel:
id: LabelTextID
text: "this is an MDCard"
halign: 'center'
'''
class button_screen(MDScreen):
def __init__(self, **kwargs):
super().__init__(**kwargs)
Builder.load_string(button_screen_kv)
self.md_card_widget = Builder.load_string(md_card_kv)
def option(self, string):
print(f"{string}")
def add_card(self, *args):
self.ids.add_card_here_id.add_widget(self.md_card_widget)
I came up with the following that works however, I am still new to programming so I don't know if this is a stable solution. Please advise me there
The Solution:
I added another class class user_card(MDGridLayout) in the buttonscreen.py and placed the kv string there.
I set that class as the root widget in the kv string
in the init method I placed a function that will return the kv string return self.user_card_string
then I added that class as a parameter in the add_widget and passed the col as an argument: self.ids.add_card_here_id.add_widget(user_card(cols=1))
Everything works but I have never used two classes before. So I am unsure if this will present a future problem.
button_screen.py:
from kivy.lang import Builder
from kivymd.uix.gridlayout import MDGridLayout
from kivymd.uix.screen import MDScreen
button_screen_kv = '''
<button_screen>:
MDGridLayout:
cols: 1
size: root.width, root.height
spacing: 40
md_bg_color: [0,0,.1,.1]
MDGridLayout:
cols: 1
size_hint_y: None
height: 40
MDGridLayout:
cols: 1
Button:
text: "Click to add card"
on_release:
root.add_card("card 1")
MDGridLayout:
id: add_card_here_id
cols: 1
'''
md_card_kv = '''
<user_card>:
MDGridLayout:
cols: 1
MDCard:
orientation: 'vertical'
size_hint: None, None
size: "360dp", "120dp"
ripple_behavior: True
on_release:
root.option()
MDLabel:
id: LabelTextID
text: "this is an MDCard"
halign: 'center'
'''
class user_card(MDGridLayout):
user_card_string = Builder.load_string(md_card_kv)
def __init__(self, *args, **kwargs):
super().__init__(**kwargs)
self.load_card()
def option(self, *args):
print("MDCard was clicked")
def load_card(self):
return self.user_card_string
class button_screen(MDScreen):
def __init__(self, **kwargs):
super().__init__(**kwargs)
Builder.load_string(button_screen_kv)
def add_card(self, *args):
self.ids.add_card_here_id.add_widget(user_card(cols=1))
I have a piece of code. (1) The TextInput value should be shown , but first it should not be editable, after clicking the corresponding CheckBox, the TextInput will be editable.
(2) Using the iteration, the Label and the TextInput should get the value. The value at Label and TextInput should not be hard coded(although it's there in my code, #FJSevilla helped me for this one).
(3) However, the values of Label and TextInput are stored in a variable in json format. something like this(you can consider like key,value pair in map) [ variable = '{"a" : " Goc" , "b" : "Coc", "c" : "Dow" } ']
(you can see diagram for more clearance).
I appreciate the help.
from kivy.app import App
from kivy.uix.tabbedpanel import TabbedPanel
from kivy.lang import Builder
Builder.load_string("""
<Test>:
do_default_tab: False
TabbedPanelItem:
text: 'page1'
BoxLayout:
padding: 50, 50, 50, 50
orientation: 'horizontal'
BoxLayout:
spacing: 50
orientation: 'vertical'
size_hint_x: 1
Label:
text: 'a'
Label:
text: 'b'
Label:
text: 'c'
BoxLayout:
spacing: 50
orientation: 'vertical'
TextInput:
text: 'Goc'
TextInput:
text: 'Coc'
TextInput:
text: 'Dow'
BoxLayout:
spacing: 50
orientation: 'vertical'
size_hint_x: 0.40
CheckBox:
text: 'CheckBox'
CheckBox:
text: 'CheckBox'
CheckBox:
text: 'CheckBox'
BoxLayout:
spacing: 50
orientation: 'vertical'
size_hint_x: 0.60
Button:
text: 'save'
Button:
text: 'save'
Button:
text: 'save'
""")
class Test(TabbedPanel):
pass
class MyApp(App):
def build(self):
test = Test()
return test
if __name__ == '__main__':
MyApp().run()
First of all, thank you for providing an app which was easy to work with.
I tried to implement what you were looking for except the JSON. I am using a simple list, it should be straightforward to extend my code for a JSON.
Instead of using colums, I am using rows which makes it easier to link together the properties of the label textinput and checkbox.
from kivy.app import App
from kivy.uix.tabbedpanel import TabbedPanel
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import StringProperty
from kivy.uix.textinput import TextInput
from kivy.uix.checkbox import CheckBox
from kivy.lang import Builder
ROWS = ['Goc', 'COC', 'EEE']
Builder.load_string("""
<Test>:
do_default_tab: False
TabbedPanelItem:
text: 'page1'
Table:
padding: 50, 50, 50, 50
orientation: 'vertical'
<Row>:
spacing: 50
#orientation: 'vertical'
size_hint_x: 1
txt: txtinpt.text
Label:
text: root.txt
TextInput:
id: txtinpt
text: root.txt
disabled: not CheckBox.active
CheckBox:
id:CheckBox
text: 'CheckBox'
active: False
Button:
text: 'save'
""")
class Table(BoxLayout):
def __init__(self, **kwargs):
super(Table, self).__init__(**kwargs)
for row in ROWS:
self.add_widget(Row(row))
class Row(BoxLayout):
txt = StringProperty()
def __init__(self, row, **kwargs):
super(Row, self).__init__(**kwargs)
self.txt = row
class Test(TabbedPanel):
pass
class MyApp(App):
def build(self):
test = Test()
return test
if __name__ == '__main__':
MyApp().run()
I am new to programming with Kivy, I'm trying to develop a program that collects the number of people in a room.
And my difficulty is to pass values between KV file and the main. I need to get the value of the slider which is in KV file and use it in main.py program
How could it? already I tried several ways that were posted on different topics here on the site but could not. Perhaps because as I have no knowledge in the area did not know apply it right.
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.properties import NumericProperty, ObjectProperty
from kivy.lang import Builder
class ThemeBackground(Screen):
pass
class myApp(App):
def build(self):
root = ScreenManager()
root.add_widget(ThemeBackground(name='Screen'))
return root
if __name__ == '__main__':
myApp().run()
And Kv file
#:import random random.random
<ThemeBackground>:
orientation: 'vertical'
canvas:
Color:
rgb: 1, 1, 1
Rectangle:
source: 'data/images/background.jpg'
size: self.size
BoxLayout:
padding: 10
spacing: 10
size_hint: 1, None
pos_hint: {'top': 1}
height: 44
Image:
size_hint: None, None
size: 24, 24
source: 'data/logo/kivy-icon-24.png'
Label:
height: 24
text_size: self.size
color: (1, 1, 1, .8)
text: 'Kivy 1.9.0.'
valign: 'middle'
GridLayout:
cols: 2
Label:
text: 'Please enter \nthe number of occupants?'
bold: True
font_name: 'data/fonts/DejaVuSans.ttf'
font_size: 22
halign: 'center'
Slider:
id: slider
min: 0.0
max: 15.0
value: 1.0
step: 1.0
orientation: "horizontal"
width: "38dp"
Label
text: ''
Label
text: '{}'.format(slider.value)
halign: 'center'
valign: 'top'
bold: True
text_size: self.size
font_size: 18
Button:
text: 'Enter'
size_hint_y: None
height: '50sp'}
You should load the kv file in the build of your myApp:
class myApp(App):
def build(self):
self.load_kv("main.kv")
return ThemeBackground()
You have unneeded } in the bottom of kv file,the last character, remove it.
height: '50sp'}
Preview:
In order to access the values of the slider, add a variable myslider to both of python and kv files like this:
kv:
<ThemeBackground>:
orientation: 'vertical'
myslider: slider
python:
class ThemeBackground(Screen):
myslider = ObjectProperty(None)
Now you can access the value , min or max by:
class myApp(App):
def build(self):
self.load_kv("kivy.3.kv")
tb = ThemeBackground()
print "value =",tb.myslider.value # <---- value here
print "min =",tb.myslider.min # <--- min here
return tb