Calling a variable not working in kivy's kv-language - python-2.7

My question is this, after I set a variable on one screen how do I call it on another?
Here is the code for what I am trying to do:
main.py
import kivy
kivy.require('1.10.0')
from kivy.app import App
from kivy.uix.screenmanager import Screen, ScreenManager
class Manager(ScreenManager):
pass
class FirstScreen(Screen):
pass
class SecondScreen(Screen):
pass
class ExampleApp(App):
def build(self):
return Manager()
if __name__ == '__main__':
ExampleApp().run()
example.kv
#: import sm kivy.uix.screenmanager
#: set Question 'not working'
<Manager>
transition: sm.FadeTransition()
FirstScreen:
SecondScreen:
<FirstScreen>
BoxLayout:
TextInput:
id: txt
multiline: False
Button:
text: 'Press Me'
on_release:
Question = txt.text
app.root.current = 'Next'
<SecondScreen>
name: 'Next'
Label:
text: Question
When this is run everything works as it should. With one exception. The Label on SecondScreen reads "not working" when it should read whatever I type into the text input on FirstScreen. Why can I not accomplish this task?

You have to provide id tag and use ids method or ObjectProperty to reference the variables. Please refer to the two example below for details.
Example 1 - Using ids method
An id is a weakref to the widget.
main.py
from kivy.app import App
from kivy.uix.screenmanager import Screen, ScreenManager
class Manager(ScreenManager):
pass
class FirstScreen(Screen):
pass
class SecondScreen(Screen):
pass
class ExampleApp(App):
def build(self):
return Manager()
if __name__ == '__main__':
ExampleApp().run()
example.kv
#:kivy 1.10.0
#:import FadeTransition kivy.uix.screenmanager.FadeTransition
#: set Question 'not working'
<Manager>
transition: FadeTransition()
FirstScreen:
SecondScreen:
id: second_screen
<FirstScreen>
BoxLayout:
TextInput:
id: txt
text: "Working!"
multiline: False
Button:
text: 'Press Me'
on_release:
root.manager.ids.second_screen.ids.label.text = txt.text
app.root.current = 'Next'
<SecondScreen>
name: 'Next'
Label:
id: label
text: Question
Output - Using ids method
Example 2 - Using ObjectProperty
The ‘best practice’ to use the ObjectProperty. This creates a direct reference, provides faster access and is more explicit.
main.py
from kivy.app import App
from kivy.uix.screenmanager import Screen, ScreenManager
from kivy.properties import ObjectProperty
class Manager(ScreenManager):
second_screen = ObjectProperty()
class FirstScreen(Screen):
pass
class SecondScreen(Screen):
label = ObjectProperty()
class ObjectPropertyApp(App):
def build(self):
return Manager()
if __name__ == '__main__':
ObjectPropertyApp().run()
objectproperty.kv
#:kivy 1.10.0
#:import FadeTransition kivy.uix.screenmanager.FadeTransition
#: set Question 'not working'
<Manager>
second_screen: second_screen
transition: FadeTransition()
FirstScreen:
SecondScreen:
id: second_screen
<FirstScreen>
BoxLayout:
TextInput:
id: txt
text: "Working!"
multiline: False
Button:
text: 'Press Me'
on_release:
root.manager.second_screen.label.text = txt.text
app.root.current = 'Next'
<SecondScreen>
name: 'Next'
label: label
Label:
id: label
text: Question
Output - Using ObjectProperty

Related

How to manage multiple screen in kivy?

I am using kivy to scan cards.How do I manage multiple screens . I wanted to capture the card first and the captured card should be passed to tesseract?
from kivy.app import App
from kivy.lang import Builder
import time
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.screenmanager import ScreenManager, Screen
from PIL import Image, ImageEnhance, ImageFilter
import pytesseract
from kivy.uix.button import Button
Builder.load_string("""
<CameraClick>:
orientation: 'vertical'
Camera:
id: camera
resolution: (640, 480)
play: False
ToggleButton:
text: 'Play'
on_press: camera.play = not camera.play
size_hint_y: None
height: '48dp'
Button:
text: 'Capture'
size_hint_y: None
height: '48dp'
on_press: root.capture()
<SettingsScreen>:
BoxLayout:
Button:
text: 'My settings button'
Button:
text: 'Back to menu'
on_press: root.manager.current = 'menu'
""")
class CameraClick(BoxLayout):
def capture(self):
'''
Function to capture the images and give them the names
according to their captured time and date.
'''
camera = self.ids['camera']
timestr = time.strftime("%Y%m%d_%H%M%S")
camera.export_to_png("reading.png".format(timestr))
print("Captured")
class SettingsScreen(Screen):
def card(self):
im = Image.open(r"readimg.png")
p = pytesseract.image_to_string(im, lang='eng', config='-psm 6')
print p
return Button(text=p)
# Create the screen manager
sm = ScreenManager()
sm.add_widget(CameraClick(name='menu'))
sm.add_widget(SettingsScreen(name='settings'))
class TestApp(App):
def build(self):
return sm
if __name__ == '__main__':
TestApp().run()
I am new to kivy I wanted to know how to manage multiple screens.How to display the content of the card from tesseract in another screen?

kivy - clear screen after saving image?

Using kivy 1.9.1/2
What I would like to achieve :
Saving the image when clicking 'OK' then clearing the screen. So the next time I enter the Signature screen, the screen doesn't contain anything but the 'OK' button.
My Issue:
canvas.clear doesn't work. I probably integrated it the wrong way.
Can someone help ?
I'm a beginner and have been stuck on this for days.
Thanks in advance.
#*** PYTHON FILE
from kivy.app import App
from kivy.lang import Builder
from kivy.config import Config
from kivy.uix.screenmanager import ScreenManager, Screen, SlideTransition
from kivy.uix.widget import Widget
from kivy.uix.button import Button
from kivy.graphics import Line
import datetime
Config.set('graphics', 'width', '1024')
Config.set('graphics', 'height', '768')
class Other(Screen):
pass
class Painter(Widget):
def __init__(self,**kwargs):
super(Painter, self).__init__(**kwargs)
self.canvas.clear()
def on_touch_down(self, touch):
with self.canvas:
touch.ud['line'] = Line(points=(touch.x, touch.y))
def on_touch_move(self, touch):
touch.ud['line'].points += [touch.x, touch.y]
class Signature(Screen):
def Save_image(self):
from PIL import Image, ImageFont, ImageDraw
self.export_to_png("test.png")
img=Image.open("test.png")
draw=ImageDraw.Draw(img)
font=ImageFont.truetype("/usr/share/fonts/truetype/noto/NotoSans-Bold.ttf",24, encoding="unic")
draw.text((0,0),str("{:%d %b %y-%Hh%Mm%Ss}".format(datetime.datetime.now())), (255,255,255), font=font)
img.save("test.png")
class ScreenManagement(ScreenManager):
pass
presentation = Builder.load_file("appdessin.kv")
class MainApp(App):
def build(self):
return presentation
if __name__ == '__main__':
MainApp().run()
#***KV FILE
#:import datetime datetime
#:kivy 1.9.1
ScreenManagement:
Other:
Signature:
<Other>:
name: "other"
id: otherScreen
BoxLayout:
Button:
text: "OK"
on_release:
root.manager.transition.direction = 'right'
app.root.current = "signature"
<Signature>:
name: "signature"
id: signatureScreen
BoxLayout:
Painter
Button:
background_color: 0,0,1,1
font_size: 32
size_hint: (0.1, 0.1)
text: "OK"
pos_hint: {"right":1, "bottom":1}
on_release:
root.Save_image()
root.manager.transition.direction = 'right'
app.root.current = "other"
As suggested by niavlys on kivy's google group, the answer is to clear the canvas everytime it is loaded. Obvious, but to achieve this, one has to declare in the kv file, in the screen:
on_pre_enter:
sign.canvas.clear()
BoxLayout:
Painter
id: sign

getting input from kivy textinput

I want to use this for a later project, I just want to print user's input from the TextInput by clicking the button on the MainScreen, but when I run and click on the button with the text "Print Text" nothing happens no errors and no output.
The .kv file:
#: import FadeTransition kivy.uix.screenmanager.FadeTransition
ScreenManagement:
transition: FadeTransition()
MainScreen:
SecondScreen:
<MainScreen>:
name: "main"
Button:
on_release: root.get_text
text: "Print Text"
font_size: 50
size_hint:0.3,0.1
TextInput:
text:"Hello World"
size_hint: 0.35,0.25
pos_hint:{"right":1, "top":1}
color:1,0,0,1
id: user_text
Button:
color: 0,1,0,1
font_size: 25
size_hint: 0.3,0.25
text: "Continue"
on_release: app.root.current = "other"
pos_hint:{"right":1, "top":0}
<SecondScreen>:
name: "other"
FloatLayout:
Button:
color: 0,1,0,1
font_size: 25
size_hint: 0.3,0.25
text: "Back Home"
on_release: app.root.current = "main"
pos_hint:{"right":1, "top":1}
The python code:
from kivy.app import App
#kivy.require("1.9.1")
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen , FadeTransition
from kivy.uix.widget import Widget
from kivy.graphics import Line
from kivy.uix.textinput import TextInput
class MainScreen(Screen):
def get_text(self,*args):
textinput= self.ids.user_text
user= TextInput.text
print(user)
class SecondScreen(Screen):
pass
class ScreenManagement(ScreenManager):
pass
gui = Builder.load_file("main.kv")
class MainApp(App):
def build(self):
return gui
MainApp().run()
When you code in kv, you bind directly as if you'd call the function e.g.
on_release: do_this()
but you did it without parenthesis as if it was a casual python binding:
self.bind(on_release=do_this)
Add the parenthesis and it should print:
on_release: root.get_text()

Getting Kivy to update Async image with Clock

I have several screens run by ScreenManager, and on one I have an image that is loaded with an image taken from a URL (for weather). My issue is, I can't seem to quite get the URL & image updated periodically:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.properties import ObjectProperty, StringProperty
from kivy.clock import Clock
import pyowm
class Weather(Screen):
addr = StringProperty()
def wx_forecast(self):
owm = pyowm.OWM('******************')
observation = owm.weather_at_place('London,uk')
w = observation.get_weather()
i = w.get_weather_icon_name()
addr = str("http://openweathermap.org/img/w/" + i + ".png")
print(addr)
return addr
def update(self):
Clock.schedule_interval(self.ids.wxlabel.source, 45)
#def update(self):
#self.wx_forecast()
#Clock.schedule_interval(lambda dt: self.ids.wxlabel, 30)
class ScreenManagement(ScreenManager):
pass
smsettings = Builder.load_string( """
ScreenManagement:
Weather:
<Weather>:
name: 'weather'
FloatLayout:
BoxLayout:
AsyncImage:
id: wxlabel
source: root.wx_forecast()
BoxLayout:
size_hint_y: None
height: 30
Button:
text: 'Change Location'
on_press:
Button:
text: 'More Details'
on_release:
""" )
class HomeUtilities(App):
def build(self):
return smsettings
if __name__=='__main__':
HomeUtilities().run()
Where the def update is where I am having issues; I have tried calling the function wx_forecast again, even trying another function outside the Weather class, but all it says is str: has no attribute 'wx_forecast'
So I believe I am on the right lines? Or I could be completely mistaken, but nothing I try seems to work. Even putting self.ids.wxlabel.source.sunny.png brings up str: has no attribute image but the file is there.

Exchanging Variables between Screens in kivy python

I tried to make an app, with two screens, one with an Textinput and the other one Label, that is displaying the Text of the TextInput.
I tried to make this by creating an StringProperty in the app class, but I had a problem with accessing the Property.
I would like to know how to access the Variable.
Here is the source code:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.properties import StringProperty
from kivy.uix.boxlayout import BoxLayout
class Manager(ScreenManager):
pass
class FirstScreen(Screen):
pass
class SecondScreen(Screen):
pass
root_widget = Builder.load_string('''
Manager:
FirstScreen:
SecondScreen:
<FirstScreen>:
name: 'first'
BoxLayout:
orientation: 'vertical'
TextInput:
id: my_text
font_size: 50
Button:
id: b1
text: 'Go to next Screen'
on_release: app.root.current = 'second'
<SecondScreen>:
name: 'second'
BoxLayout:
orientation: 'vertical'
Label:
id: my_Label
text: root.txt
Button
id: b2
text: 'Go back'
on_release: app.root.current = 'first'
''')
class Caption(App):
txt = StringProperty('')
def build(self):
return root_widget
Caption().run()
Screen class has an attribute called 'manager' which specifies which manager that screen belongs to. In ScreenManager class, there is an attribute called 'screens', which is a ListProperty object that holds all the screens. If you want to reach out an information about another screen, you can use this way. In your case, you need to update your your b1 id button in your kv Builder with this:
Button:
id: b1
text: 'Go to next screen'
on_release:
root.manager.screens[1].ids.my_Label.text = root.ids.my_text.text
root.manager.current = 'second'
For more complex behaviours, you can define related Property in that particular Page class and reach out from python with:
self.manager.screens[<screen_number>].ids.<widget_id>.<property_name>