Python for kivy:Pass values between multiple screens - python

I am developing a kivy app in which ,there are two screens
1.LoginScreen
and 2.HomeScreen.
What required is -
A value 'xyz' which is computed in class LoginScreen, to be passed to the method 'insertdata' of class HomeScreen and want to display that value on a label.
For this I tried following code:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.screenmanager import Screen, ScreenManager
class loginScreen(Screen):
def __init__(self,**kwargs):
super(HomeScreen, self).__init__(**kwargs)
def auth(self):
xyz=1
self.manager.current="home"
obj=HomeScreen()
# 1. To Pass 'xyz' to method scrn2
HomeScreen.insertdata(obj)
class HomeScreen(Screen):
def __init__(self,**kwargs):
super(LoginScreen, self).__init__(**kwargs)
if (a==1):
# 2. To display label
self.scrn2()
def insertdata(self):
print "screen 2"
label=Label(text="good moring")
self.add_widget(label)
class ScreenApp(App):
pass
if __name__ == '__main__':
ScreenApp().run()
Here:
insertdata is called from method auth
1)the 1st way is proper , as it is passing 'xyz' and calling the method insertdata but it dosen't display label
2) in 1st way I have to create to create an object of HomeScreen ,to call insertdata, which in turn calls the ___init__ of Homescreen and init calls insertdata
insertdata called from __init__
1) It loads data before user authentication at loginscreen
insertdata gets total 3 calls, which is affecting app launch time.
Suggest me any simple and effective way for this.
Thanks in advance.

You can use Screen.manager() method to get an manager object from one screen, use it to retrieve another one with its ScreenManager.get_screen() method and then pass the value directly. For an working example check an answer of this question: Kivy - Slider Class value change on another screen

Related

kivy: How to add a callback to a unfocus event on TextIput widgets

I've got a problem tying callback funtions to the on_focus event of a TextInput.
I want it to trigger a validation event when the focus from the input widget is removed. And, in doing so, calling another method (via the on_validate_text method)
Here is the code:
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput
from kivy.uix.popup import Popup
from kivy.uix.button import Button
from kivy.app import App
class MyTextInput(TextInput):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.multiline = False
self.unfocus_on_touch = True
def on_focus(self, instance, value):
if not value: # DEFOCUSED
print('Focus is off')
class MainLayout(GridLayout):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.cols = 2
#First row
self.top_label = Label(text = 'No text')
self.add_widget(self.top_label)
self.top_input = MyTextInput(on_text_validate=self.change_top_label)
#Here im trying to trigger the validate event when the on_focus gets called
self.top_input.bind(on_focus=self.top_input.on_text_validate)
self.add_widget(self.top_input)
#Second row
self.bottom_label = Label(text='Bottom Label')
self.add_widget(self.bottom_label)
self.bottom_input = MyTextInput(on_text_validate=self.create_popup)
self.bottom_input.bind(on_focus=self.bottom_input.on_text_validate)
self.add_widget(self.bottom_input)
def change_top_label(self, instance):
self.top_label.text = instance.text
instance.text = ''
def create_popup(self, instance):
self.my_popup = Popup(title=instance.text, size_hint=(.5, .5))
self.my_popup.content = Button(text='CLOSE', on_release=self.my_popup.dismiss)
self.my_popup.open()
instance.text = ''
if __name__ == '__main__':
class MainApp(App):
def build(self):
return MainLayout()
MainApp().run()
In this case, when de top input gets defocused, I want it to call the change_top_label method through the validation event.
In the same way, when the bottom input gets defocused, the create_popup method should get called through the validation event.
I need both input to call a callback function when unfocused. But I can not define that function inside the on_focus method, because it needs to be different for every instance of MyTextInput.
I've tried binding on_text_validate to on_focus, and calling on_text_validate inside the on_focus metyhod, but it does not work.
Clearly there is something I'm missing.
If you could help me out here, It'd be great.
First of all, your code seems already doing what you wanted in the following (after the method on_text_validate is being called),
In this case, when de top input gets defocused, I want it to call the change_top_label method through the validation event...
Secondly,
I've tried binding on_text_validate to on_focus...
This seems confusing to me. The method on_text_validate gets called when you hit 'enter' (and if multiline is set to False) and that will also unfocus the TextInput. Also on_focus is kind of a default method that is called whenever the attr. focus changes. So and finally if you want just this,
I need both input to call a callback function when unfocused. But...
You can do that as TextInput_instance.bind(focus = some_method).

Kivy TabbedPanel switch_to work inconsistently

I am writing a code which starts the frontend, runs the backend and then loads the frontend. The frontend consists of TabbedPanel, and the currently displayed tab may be change by backend.
Here's the MRE:
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.tabbedpanel import TabbedPanel, TabbedPanelHeader
def button(instance):
instance.parent.parent.switch_to(instance.parent.parent.tab_2) # accessing TabbedPanel without messing with sending
# a variable
def backend(frontend):
# this class represents main backend function. In the result of its execution there might be a need to switch to
# another tab
frontend.switch_to(frontend.tab_2)
class MyTabbedPanel(TabbedPanel):
def __init__(self, **kwargs):
super().__init__()
self.tab_1 = TabbedPanelHeader()
self.tab_2 = TabbedPanelHeader()
self.tab_1.content = Button(text='Tab 1')
self.tab_1.content.bind(on_release=button)
self.tab_2.content = Label(text='Tab 2')
self.add_widget(self.tab_1)
self.add_widget(self.tab_2)
class Application(App):
def build(self):
frontend = MyTabbedPanel()
backend(frontend)
return frontend
Application().run()
The button, which I have added to compare, to switch from tab 1 to tab 2 works just fine, however, the auto swith when starting the app does not work.
What is the problem? Thank you in advance.
At the time that you're calling backend, there is no root widget returned by the build method, let alone a tab to switch to.
One way to solve this, is to schedule the call to the backend for after the build ends, using the Clock module.
def build(self):
frontend = MyTabbedPanel()
# backend(frontend)
from functools import partial
from kivy.clock import Clock
Clock.schedule_once(partial(backend, frontend))
return frontend
You also have to add an args argument to the backend method, because Clock sends a dt value:
def backend(frontend, *args):

Add UIImagePickerController to a kivy-ios-app (Python)

I want to access my images/photo gallery on an iOS device from a kivy application.
Kivy has no native way implemented to do this, so I'm trying to solve it with kivy/pyobjus
where I can use the UIImagePickerController (from Apples UIKit).
from kivy.app import App
from kivy.lang import Builder
from pyobjus import autoclass, protocol
class TestApp(App):
ui = Builder.load_file("main.kv")
def build(self):
return self.ui
def imagePicker(self):
UIImagePickerController = autoclass('UIImagePickerController')
self.picker = UIImagePickerController.alloc().init()
self.picker.delegate = self
self.picker.sourceType = 0
#protocol('UIImagePickerControllerDelegate')
def imagePickerControllerDidFinish(self, image):
print("ABC")
The ui is just a button, which calls the imagePicker function.
I have three questions on this code:
How can I display the imagePicker?
When I'm using imagePicker.delegate = self, the App crashes because
[...] delegate, but there is no #protocol methods declared.
But I declared a protocol with "#protocol('UIImagePickerControllerDelegate')"
So why it won't use my declared protocol? (I tried also to add the "UIImagePickerControllerDelegate" in the protocols.py from pyobjus. This didn't solved the problem)
If the protocol will work, it is the correct way to use the "imagePickerControllerDidFinish(self, image)" method to access the image?

How to Bind on_press to GridLayout in kivy python

i was trying to bind on_press method to gridLayout in kv language but i got this error AttributeError: pressed. I did some research even in the kivy doc but no help .So if any one has a solution to this problem please you may be a good resource
here is my testApp.py
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
class screendb(BoxLayout):
def mycall_back(self):
print('hello')
class testApp(App):
def build(self):
return screendb()
if __name__=='__main__':
testApp().run()
here is my testApp.kv
<Screendb#BoxLayout>:
GridLayout:
on_pressed:root.Mycall_back()
In your py file:
# Behaviors let you add behavior from one widget to another widget
from kivy.uix.behaviors import ButtonBehavior
from kivy.uix.gridlayout import GridLayout
# We create a new widget that is a GridLayout with access to Button Behaviors
# Like Button's 'on_press' method
class ButtonGrid(ButtonBehavior, GridLayout):
pass
class screendb(BoxLayout):
def mycall_back(self):
print('hello')
class testApp(App):
def build(self):
return screendb()
In your kv file:
# We create a Root Widget for the ButtonGrid
<ButtonGrid>:
<Screendb#BoxLayout>:
# We add an instance of the ButtonGrid class to our main layout
ButtonGrid:
# We can now use on_press because it is a part of the ButtonBehavior class, that makes up your ButtonGrid class.
on_press:root.mycall_back()
Note: There were a few minor mistakes in your post as well. For example, there is no method 'on_pressed', only 'on_press', you also wrote your callback as 'mycall_back' in your py file while writing it as 'Mycall_back' in your kv file, which refers to a different method that exists. Make sure your letter cases match.
video example

Kivy Sending text from spinner to another function

I've been trying to figure out how to get the value selected in a spinner into another function. I basically need a user to select some option and then press "save" prompting another function to write the data to a file (right now I just have it setup to print). When I run the form.finkle function it prints kivy.uix.button.Button object at 0x02C149D0
I'm sure its an easy fix, but I've been stuck on it for days.
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput
from kivy.uix.button import Button
from kivy.uix.popup import Popup
from kivy.uix.textinput import TextInput
from kivy.uix.spinner import Spinner
condspin = Spinner(text='Condition',values=('Good','Fair','Poor','Missing'))
typespin = Spinner(text='Type', values=('Metal','Wood','Pin','Missing'))
commlabel = Label(text='Comment')
commtext = TextInput(text="")
class Goose(App):
def build(self):
layout = GridLayout(cols=2,rows=6,padding=10,spacing=10)
layout.add_widget(Button(text='Hunter Parking'))
layout.add_widget(Button(text='Boat Launch'))
layout.add_widget(Button(text='ETRAP'))
layout.add_widget(Button(text='Monument',on_press=form.monform))
layout.add_widget(Button(text='Camp Site'))
layout.add_widget(Button(text='Sign'))
layout.add_widget(Button(text='Building'))
layout.add_widget(Button(text='Trail Head'))
layout.add_widget(Button(text='Dam'))
layout.add_widget(Button(text='Day Use'))
layout.add_widget(Button(text='Pavilion'))
layout.add_widget(Button(text='Misc Point'))
return layout
class form():
def finkle(condtest):
print condtest
def monform(self):
monbox = GridLayout(cols=2,rows=8,padding=20,spacing=20)
monpopup = Popup(title="Monument",content=monbox)
closebut = Button(text="Close")
closebut.bind(on_press=monpopup.dismiss)
savebut = Button(text="Save Point")
savebut.bind(on_press=form.finkle)
condtest = condspin.text
monbox.add_widget(condspin)
monbox.add_widget(typespin)
monbox.add_widget(commlabel)
monbox.add_widget(commtext)
monbox.add_widget(savebut)
monbox.add_widget(closebut)
monpopup.open()
Goose().run()
Since you have made the spinner global, you could just do print(condspin.text). More generally, you could pass the spinner as an argument, e.g.
from functools import partial
savebut.bind(on_press=partial(self.finkle, condspin))
and redefine the finkle method as
def finkle(self, spinner, button)
Note that I changed form.finkle to self.finkle and added both the self and spinner arguments. It's bad practice to call the method via the class like that.
There are some significant other bad style things in your code, and I would recommend some other changes. Mostly I would make use of kv language for basically everything, it will make the widget trees much clearer, more robust to changes later, and also make this binding very simple (you'd be able to refer to the spinner text via a kv id). Also, the form class is semi-unnecessary, you could replace it with a FormWidget that is the GridLayout you make in the monform function, adding all its children and behaviour in kv.

Categories