I'm new at kivy and try to run a do_login function inside my MyApp Class from a kv generated button.
my kv layout with the button
RelativeLayout:
FloatingActionButton:
id: float_act_btn
on_press: ???how to call call do_login from MyApp
and my class with the containing do_login function
class MyApp(App):
def build(self):
main_widget = Builder.load_string(login_kv)
def do_login(self, *args):
print'jo'
How to use on_press to call do_login?
with on_press:do_login(login.text, password.text)' I get 'do_login' is not defined and the same with self.do_login I get MaterialRaisedButton' object has no attribute 'do_login'
make do_login a member of the MyApp class:
class MyApp(App):
def build(self):
main_widget = Builder.load_string(login_kv)
def do_login(self, *args):
print'jo'
and use app in kv as the keyword to access MyApp and call the function:
on_press: app.do_login()
from Kivy language:
There are three keywords specific to Kv language:
app: always refers to the instance of your application.
root: refers to the base widget/template in the current rule
self: always refer to the current widget
Related
How do you reference methods from outside classes in a .kv file? For example, here is my main.py:
import kivy
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.properties import ObjectProperty
from kivy.lang import Builder
import random
class MyClass:
def add():
return 1 + 1
class MainLayout(Widget):
pass
class MyApp(App):
def build(self):
return MainLayout()
if __name__ == "__main__":
MyApp().run()
And here is my main.kv:
<MainLayout>
GridLayout:
size: root.width, root.height
Button:
text: "Button"
on_press: root.add()
My problem is being able to access the add() function from the .kv file since the function is not inside the MainLayout class, I just need a button that will call add(). What is the proper method for doing this?
I could probably define add() in the MainLayout class but that might be too messy with a large program with many classes and methods.
I want to make a custom set of widgets and in some of them I would like to access specific widgets' properties inside of the add_widget(widget, index, canvas)method.
The problem is that the properties are always empty. This could be because I access them early but how do I fix it?
My Code:
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivymd.uix.label import MDLabel
from kivymd.app import MDApp
class CustomWidget(BoxLayout):
def add_widget(self, widget, index=0, canvas=None):
if isinstance(widget, MDLabel):
# Why is the text empty?
# Also how can I get the text value?
print("{}'s text is: {}".format(widget, widget.text))
else:
super(CustomWidget, self).add_widget(widget, index, canvas)
class MainApp(MDApp):
def __init__(self, **kwargs):
super(MainApp, self).__init__(**kwargs)
self.kv = Builder.load_string('''
#:kivy 2.0.0
CustomWidget:
MDLabel:
text: "Some text"
''')
def build(self):
return self.kv
if __name__ == '__main__':
MainApp().run()
The text is empty because it hasn't been set yet at the time it's added to the parent.
If you care about what its value changes to, you can bind to the new child widget's text property in add_widget so that you are notified when it changes and can act accordingly.
I read this question and tried to implement a close event for my app.
I wrote the following code in Kivy in Python.
#-*- coding: utf-8 -*-
from kivy.lang import Builder
Builder.load_string("""
<TextWidget>:
BoxLayout:
size: root.size
Button:
text: "Test App"
""")
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.core.window import Window
from kivy.properties import StringProperty
class TextWidget(Widget):
def __init__(self, **kwargs):
super(TextWidget, self).__init__(**kwargs)
self.text = 'test'
def on_request_close(self, *args):
print(self.text)
class TestApp(App):
def __init__(self, **kwargs):
super(TestApp, self).__init__(**kwargs)
def build(self):
scn = TextWidget
Window.bind(on_request_close=scn.on_request_close)
return TextWidget()
if __name__ == '__main__':
TestApp().run()
When I quit the app,"on_request_close" function is executed, but for some reason the print(self.text) fails, resulting in an error.
The errors are as follows:
AttributeError: 'WindowSDL' object has no attribute 'text'
How can I fix this problem?
You're trying to access the class itself instead of the TextWidget instance that has the text attribute.
You can do the binding within TextWidget's __init__ method to fix it (below) or you can access the instance by assigning it an id.
class TextWidget(Widget):
def __init__(self, **kwargs):
super(TextWidget, self).__init__(**kwargs)
Window.bind(on_request_close=self.on_request_close)
self.text = 'test'
def on_request_close(self,*args):
app=self.text
print(app)
class TestApp(App):
def build(self):
return TextWidget()
How to access a class in python code using on_release: by kivy? For example, a function that is in root I use. root.function() and a class?
on_release: # What to put here to access the function `chama`?
class Tela(ScreenManager):
pass
class teste(Screen):
def chama(self):
pass
def save_d(self):
class Prg(App):
def build(self):
return Tela()
Prg().run()
If you use kv (file or string), then a good way to access other classes is to use ids.
Here is an example:
main.py
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.lang import Builder
class Tela(ScreenManager):
pass
class Teste(Screen):
def chama(self):
print ('Hello')
class Teste2(Screen):
pass
class PrgApp(App):
def build(self):
return Builder.load_file('Prg.kv')
PrgApp().run()
Prg.kv:
Tela
Teste2
Button
on_release: t.chama()
Teste
id: t
note: the first letter of a widget class must be capitalized, otherwise you will get a syntax error
I am having issues getting Kivy to instantiate children Widgets. The issue here I believe is with how I am setting up the root widget. According to many examples I have seen including kivy's own documentation I should be able to instantiate children widgets to a root widget in the .kv file without using <> as such:
initApp.kv root_rule:
Root_Widget:
Test_Screen:
<Test_Screen>:
BoxLayout:
*there is stuff here, leaving blank to keep this question shorter*
Python File: (Note that the add_widget() is commented out)
class Test_Screen(Screen):
pass
class Root_Widget(ScreenManager):
def __init__(self, **kwargs):
super().__init__(**kwargs)
# self.add_widget(Test_Screen())
pass
class InitApp(App):
def build(self):
return Root_Widget()
if __name__ == '__main__':
InitApp().run()
However, this only leads to a blank app. There are two ways to fix this:
Uncomment the self.add_widget(Test_Screen()) line OR
Add <> to around the Root_Widget in the .kv file so it would then be a class rule:
initApp.kv class_rule:
<Root_Widget>:
Test_Screen:
<Test_Screen>:
BoxLayout:
*there is stuff here, leaving blank to keep this question shorter*
Question
My question is, what is the difference here? Nesting Test_Screen underneath Root_Widget in the .kv file should be the exact same as calling the add_widget() method correct? Is this true and if so how/why is it different when setting Root_Widget as a class rule VS. a root rule?
Are there unforeseen consequences to saying that Root_Widget is a class rule rather than a root rule? It seems to work just fine using this approach but I don't know if it will cause other trouble as the app becomes more complex.
Blank Window/App
The blank window/app could be due to one of the following:
kv file name mismatch e.g. app class name, class InitApp(App): then kv filename should be init.kv. If you are not using Builder to load kv then the kv file name should be init.kv and not InitApp.kv
No root widget in the return statement
No root rule in the kv file
kv filename - By name convention
By name convention
Kivy looks for a Kv file with the same name as your App class in
lowercase, minus “App” if it ends with ‘App’ e.g:
MyApp -> my.kv
Solution - Blank Window/App
Instantiate and add a Label widget under Test_Screen as follow:
<Test_Screen>:
BoxLayout:
Label:
text: "kv file - Root Rule vs Class Rule"
Question 1
what is the difference here? Nesting Test_Screen underneath
Root_Widget in the kv file should be the exact same as calling the
add_widget() method correct?
Answer 1
Yes it is the same.
Kivy App - without kv file
Use add_widget(Test_Screen()) function to instantiate add children widgets under the parent.
Kivy App - with kv file
Instantiate and add children widgets under the parent using Test_Screen:
Can use both e.g. using add_widget(Button()) to dynamically instantiate and add children widgets to a ScrollView.
Question 2
Is this true and if so how/why is it different when setting
Root_Widget as a class rule VS. a root rule?
Answer 2
When the kv file is parsed, the root rule will be set as the root attribute of the App instance. Whereas a class rule, defines how any instance of that class will be graphically represented.
Question 3
Are there unforeseen consequences to saying that Root_Widget is a class rule rather than a root rule?
Answer 3
I don't believe there is any unforeseen consequences. The only thing to note when using root rule or class rule in kv file are as follow.
kv file - Using root rule
If in your kv file, you have a root rule defined i.e. Root_Widget: then in your Python code, you can do one of the following:
Option 1
The kv file is init.kv
class InitApp(App):
pass
Option 2
The kv file is not init.kv but InitApp.kv
class InitApp(App):
def build(self):
return Builder.load_file("InitApp.kv")
kv file - Using class rule
If in your kv file, you have a class rule defined i.e. <Root_Widget>: then in your Python code, you can do one of the following:
Option 1
The kv file is init.kv
class InitApp(App):
def build(self):
return Root_Widget()
Option 2
The kv file is not init.kv but InitApp.kv
class InitApp(App):
def build(self):
Builder.load_file("InitApp.kv")
return Root_Widget()