Actually my doubt is that how can we provide parameters to a kivy class.. Example when we make a normal class in python we make a __init__ function under which we provide some parameters def __init__(self,x,y,z) . How can we provide this type of parameters to a kivy class...
I have this class which I created in Kivy my.kv file
<MyGrid>:
input : input
label : label
hint_text : self.hint_text
pos_hint : self.pos_hint
MDCard:
size_hint : 0.75,0.44
pos_hint : self.pos_hint # This is first parameter
elevation: 1
FloatLayout:
MDTextField:
id : input
markup: True
multiline : True
size_hint : 0.8,0.7
pos_hint:{'x':0.05,'top':0.82}
mode : 'rectangle'
hint_text : self.hint_text # This is the second parameter
As u can see ,I have tried using self.pos_hint and self.hint_text but that doesn't work .I want to provide different pos and text for each MyGrid widget .. so any idea how can this be achieved or is their something which i am doing wrong.
#main .py file consist of just this class MyGrid
class MyGrid(FloatLayout):
def __init__(self,**kwargs):
super(MyGrid, self).__init__(**kwargs)
If you create a class by extending an existing Widget (the FloatLayout class is a Widget), then the __init__() of the super class will be called automatically. When you create an instance of MyGrid, the __init__() method of FloatLayout will be called. So you can define MyGrid like this:
class MyGrid(FloatLayout):
pass
and you can specify properties of MyGrid just as you would for FloatLayout. For example, in your kv:
<MyGrid>:
pos_hint: {'center_x':0.5, 'top':1.0}
So, in general, you can treat MyGrid exactly as you would FloatLayout.
And you can create your own properties in MyGrid, that can then be referenced in the 'kv'. Here is a modification of your posted code that does that:
from kivy.lang import Builder
from kivy.properties import StringProperty, DictProperty
from kivy.uix.floatlayout import FloatLayout
from kivymd.app import MDApp
kv = '''
<MyGrid>:
input: input
MDCard:
size_hint : 0.75,0.44
pos_hint : root.card_pos_hint # This is first parameter
elevation: 1
FloatLayout:
MDTextField:
id : input
markup: True
multiline : True
size_hint : 0.8,0.7
pos_hint:{'x':0.05,'top':0.82}
mode : 'rectangle'
hint_text : root.hint_text # This is the second parameter
'''
class MyGrid(FloatLayout):
hint_text = StringProperty('')
card_pos_hint = DictProperty()
class TestApp(MDApp):
def build(self):
Builder.load_string(kv)
return MyGrid(hint_text='This is a Hint', card_pos_hint={'right':1, 'top':1})
TestApp().run()
Note that the root in the kv refers to MyGrid. Also, kivy automatically handles properties provided in the MyGrid() creation as long as they are already defined in the MyGrid class. And, since hint_text and card_pos_hint are kivy Properties, the MDTextField hint will automatically update whenever you change the hint_text property of the MyGrid instance. Similarly, the position of the MDCard will automatically update whenever you modify the card_pos_hint property of the MyGrid instance.
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.
so here is my Class
class CreateTask(Screen):
def CreateTask(self, *args):
bl = BoxLayout(orientation="vertical",spacing=10)
name=self.ids.TaskName.text
desc=self.ids.TaskDesc.text
bl.add_widget(name)
bl.add_widget(desc)
self.MainLayout.add_widget(bl)
and that is the kv of MainLayout
<SecondWindow>:
name:"second"
BoxLayout:
id:MainLayout
orientation:"vertical"
Button:
text:"Add Task"
on_release:
app.root.current="third"
root.manager.transition.direction = "right"
Button:
text:"Come Back"
on_release:
app.root.current ="main"
root.manager.transition.direction = "right"
it has to create widgets by clicking in the BoxLayout which is in another class. But when i run it i get "AttributeError: 'super' object has no attribute 'getattr'" error, so how do i refer to the BoxLayout if it's in another class?
here is my .py file
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.button import Button
from kivy.uix.textinput import TextInput
from kivy.uix.label import Label
from kivy.uix.boxlayout import BoxLayout
from kivy.core.window import Window
from kivy.uix.anchorlayout import AnchorLayout
Window.clearcolor = (1,1,1,1)
class MainWindow(Screen):
pass
class SecondWindow(Screen):
pass
class CreateTask(Screen):
def CreateTask(self,*args):
bl = BoxLayout(orientation="vertical",spacing=10)
name=self.ids.TaskName.text
desc=self.ids.TaskDesc.text
lbl_name = Label(text=name)
lbl_desc = Label(text=desc)
bl.add_widget(lbl_name)
bl.add_widget(lbl_desc)
self.get_screen("second").ids.MainLayout.add_widget(bl)
class RegisterWindow(Screen):
pass
class WindowManager(ScreenManager):
pass
class MainScreenApp(App):
def build(self):
return kv
kv=Builder.load_file("mainscreen.kv")
if __name__ == "__main__":
MainScreenApp().run()
You have to put instances of both the screens inside the screen manager to be able to access them. Put this in the .kv file:
<WindowManager>:
CreateTask
SecondWindow
Then edit this in the .py file:
self.get_screen("second").ids.MainLayout.add_widget(bl)
to:
self.root.get_screen("second").ids.MainLayout.add_widget(bl)
Here's the explaination:
Since you were calling self from a method of CreateTask class, it was referring to the instance of CreateTask class. I told you to put an instance of CreateTask class as well as SecondWindow class inside the WindowManager. So this makes WindowManager the root of both CreateTask and SecondWindow classes. Therefore with respect to CreateTask, the WindowManager would be self.root. Hence with respect to CreateTask class, SecondWindow would be self.root.get_screen("second")
I would like to change a base widget property in kivy. This is easily done in the kivy language like so:
<Label>:
font_size: sp(30)
This does not have to be in my widget tree to affect all classes that use Label as a base class upon app initialization. So, my following example app shows up with two buttons whose text is larger than the default, which is what I want.
testApp.py
class Main_Screen(Screen):
pass
class Root_Widget(ScreenManager):
pass
class testApp(App):
def build(self):
return Root_Widget()
if __name__ == '__main__':
testApp().run()
test.kv
<Root_Widget>:
Main_Screen:
BoxLayout:
Label:
text: 'Label1'
Label:
text: 'Label2'
<Label>:
font_size: sp(30)
However, I would like to update this font_size value based on my window size (which I know how to change dynamically I just haven't included all that here). But how do I access the font_size property of the base class widget from python so that it can be changed?
Questions
How can I accomplish this change via python in a way that allows me to change it at the instantiation of my app?
Add import statement for label, from kivy.uix.label import Label
Add import statement for sp, from kivy.metrics import sp
Use Label.font_size = sp(30)
Snippet - Python code
from kivy.uix.label import Label
from kivy.metrics import sp
class testApp(App):
def build(self):
Label.font_size = sp(30)
return Root_Widget()
Output
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