Inheritance with dataclasses for GridLayout of Kivy Python 3 - python

I would like to do that:
import kivy
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.gridlayout import GridLayout
from kivy.uix.textinput import TextInput
from dataclasses import dataclass
class MyGrid(GridLayout):
def __init__(self, **kwargs):
super.(MyGrid,self).__init__(**kwargs)
self.cols = 2
self.add_widget(Label(text="Pseudo: "))
self.pseudo = TextInput(multiline=False)
self.add_widget(self.pseudo)
class MyApp(App):
def build(self):
return MyGrid()
if __name__ == "__main__":
MyApp().run()
but with dataclasses. I have made several searches but didn't find anything.
Thanks to #JohnAnderson advices, I tried that:
#dataclass
class MyGrid(GridLayout):
pass
#dataclass
class MyApp(App):
def build(self):
root = MyGrid()
root.cols = 2
pseudo = TextInput(multiline=False)
root.add_widget(Label(text="Pseudo: "))
root.add_widget(pseudo)
return root
if __name__ == "__main__":
MyApp().run()
but I get this error:
File AppData\Local\Programs\Python\Python310\lib\site-packages\kivy\app.py", line 921, in _run_prepare
if not self.built:
AttributeError: 'MyApp' object has no attribute 'built'. Did you mean: 'build'?
These add_widget methods came from GridLayout of Kivy.
Someone could help to do this with dataclasses? Thanks in advance.

Here is a simple way to do what you want:
class MyApp(App):
def build(self):
root = MyGrid()
root.cols = 2
pseudo = TextInput(multiline=False)
root.add_widget(Label(text="Pseudo: "))
root.add_widget(pseudo)
return root

as you can see in Kivy documentation, add_widget adds a new widget as a child of this widget. So as an example, parent_widget.add_widget(child_widget) adds the child to the parent's widgets. This is why you need to use self.add_widget() if you want to add a child widget to your class (which is a GridLayout).

Related

How to create a function to change variables and refresh Kivy app with the updated variables

The app I am creating in Python 3 using Kivy is to teach myself the Hungarian language. When the app loads it simply shows a word in Hungarian and the English translation. What I want to do is when I click the only button (on_press) I need a function to be called and to replace the visible Hungarian word and English translation with a new one.
# hungarian_tutor.py
""" A program to teach Hungarian translated from English """
import kivy
kivy.require("1.11.1")
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.core.audio import SoundLoader
from random import choice
import time
import hungarian_language as hl
class Grid(GridLayout):
def __init__(self, **kwargs):
super(Grid, self).__init__(**kwargs)
self.cols = 1
self.phrase = choice(hl.basics)
self.eng_text = self.phrase[0]
self.hun_text = self.phrase[1]
self.hun_audio = self.phrase[2]
self.add_widget(Label(text="English > {}".format(self.eng_text), font_size=50))
self.add_widget(Label(text="Hungarian > {}".format(self.hun_text), font_size=50))
self.add_widget(Label(text=hl.alphabet, font_size=20))
self.btn1 = Button(text="New Phrase", font_size=40)
self.add_widget(self.btn1)
#self.btn1.bind(on_press=)
class MainApp(App):
def __init__(self, **kwargs):
super().__init__(**kwargs)
def build(self):
return Grid()
if __name__ == "__main__":
MainApp().run()
Thanks in advance
When you use:
self.btn1.bind(on_press=self.pressed)
Then the self.pressed() method should look something like:
def pressed(self, button_instance):
print(button_instance, 'pressed')

Kivy Script Does not show Labels in Sublime Text

I am new to Kivy.
When I run the below kivy script on Sublime Text, I get only a Blank Black screen.
import kivy
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.gridlayout import GridLayout
from kivy.uix.textinput import TextInput
kivy.require("1.10.1")
class LoginScreen(GridLayout):
def __init_(self, **kwargs):
super(LoginScreen, self).__init__(**kwargs)
self.cols = 2
self.add_widget(Label(text="Username :"))
self.username = TextInput(multiline=False)
self.add_widget(self.username)
class SimpleKivy(App):
def build(self):
return LoginScreen()
if __name__ == "__main__":
SimpleKivy().run()
The __init__() method of LoginScreen is spelled incorrectly. It should be:
def __init__(self, **kwargs):
not:
def __init_(self, **kwargs):
Note the number of underscores.

How to reference Kivy App class attributes

I stuck at a problem of referencing app class real variable ,
I am a beginner in kivy
see this code
class Screen_mgr(ScreenManager):
pass
class MainScreen(Screen):
def func(self):
if(SimpleApp.num == 0): #this statement always returns True as num is always 0 in app class
SimpleApp.num +=10 #How can I access the num variable of app class
class SimpleApp(MDApp):
def __init__(self,**kwargs):
super().__init__(**kwargs)
self.theme_cls.theme_style = "Dark"
num = NumericProperty(0)
def build(self):
return Screen_mgr()
if __name__ == "__main__":
SimpleApp().run()
I want to use that num variable everywhere in python code only Not in KV code.
Thanks For Reading .
I think your code (at least what you posted of it) should work as you expect. Here is a version of your code, with additional code just to make it work. The Button calls the func every time you press it, and it shows the expected behavior (with num as a NumericProperty):
from kivy.lang import Builder
from kivy.properties import NumericProperty
from kivy.uix.screenmanager import ScreenManager, Screen
from kivymd.app import MDApp
class Screen_mgr(ScreenManager):
pass
class MainScreen(Screen):
def func(self):
app = MDApp.get_running_app()
print(app.num)
if(app.num == 0): #this statement always returns True as num is always 0 in app class
app.num +=10 #How can I access the num variable of app class
Builder.load_string('''
<Screen_mgr>:
MainScreen:
id: main
name: 'main'
Button:
text: 'doit'
on_release: main.func()
''')
class SimpleApp(MDApp):
def __init__(self,**kwargs):
super().__init__(**kwargs)
self.theme_cls.theme_style = "Dark"
num = NumericProperty(0)
def build(self):
return Screen_mgr()
if __name__ == "__main__":
SimpleApp().run()
You can define it outside of your class that will make it a global variable so you can use it everywhere in your .py file or .kv file

accessing variables within nested classes

I want to be able to access the variable values assigned within other classes. This may be only related to the methods in Kivy but it is in general related to my confusion over the class communication. My feeling is I need to send the instances down the tree such as in this example but I can't seem to get it working.
from kivy.uix.boxlayout import BoxLayout
from kivy.app import App
from kivy.uix.textinput import TextInput
class LevelTwo(BoxLayout):
def __init__(self, **kwargs):
super(LevelTwo, self).__init__(**kwargs)
self.wid = TextInput(id='var_id',text='string I want')
self.layout = BoxLayout(id='box_layout_two')
self.layout.add_widget(self.wid)
class LevelOne(BoxLayout):
def __init__(self, **kwargs):
super(LevelOne, self).__init__(**kwargs)
self.layout_outer = LevelTwo(id='box_layout_one')
class RootWidget(BoxLayout):
def __init__(self):
super(RootWidget, self).__init__()
self.widone = LevelOne()
print(self.widone.box_layout_one.box_layout_two.var_id.text)
--> stdout: '> string I want'
class MainApp(App):
def build(self):
return RootWidget()
if __name__ == '__main__':
MainApp().run()

Dynamically adding properties with kivy discouraged – why?

The class kivy.event.EventDispatcher has a method called apply_property() which allows adding a property to a class at runtime.
The docs contain a warning:
This method is not recommended for common usage because you
should declare the properties in your class instead of using this
method.
It is not clear to me why this usage is discouraged, and declaration in class preferred. Can anyone enlighten me?
apply_property() is used to add property to a single class instance but has a side effect of polluting properties of other instances as well. Consider following code:
#!/usr/bin/kivy
import kivy
kivy.require('1.9.1')
from kivy.app import App
from kivy.lang import Builder
from kivy.properties import NumericProperty
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
Builder.load_string('''
<MyButton>:
on_press: print('np' in self.properties())
''')
class MyButton(Button):
pass
class MainApp(App):
def build(self):
mb1 = MyButton(text="mb1")
mb2 = MyButton(text="mb2")
mb1.apply_property(np=NumericProperty(100))
layout = BoxLayout()
layout.add_widget(mb1)
layout.add_widget(mb2)
return layout
if __name__ == '__main__':
MainApp().run()
As you can see, even though I used apply_property on mb1 instance, mb2 reports that it has such property as well. This is because properties are added to the class, not the instance. However, only mb1 has an actual value:
#!/usr/bin/kivy
import kivy
kivy.require('1.9.1')
from kivy.app import App
from kivy.lang import Builder
from kivy.properties import NumericProperty
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
Builder.load_string('''
<MyButton>:
on_press: print(self.np)
''')
class MyButton(Button):
pass
class MainApp(App):
def build(self):
mb1 = MyButton(text="mb1")
mb2 = MyButton(text="mb2")
mb1.apply_property(np=NumericProperty(100))
layout = BoxLayout()
layout.add_widget(mb1)
layout.add_widget(mb2)
return layout
if __name__ == '__main__':
MainApp().run()
Trying to get the value of np property from mb2 instance yields an AttributeError. A safe alternative:
#!/usr/bin/kivy
import kivy
kivy.require('1.9.1')
from kivy.app import App
from kivy.lang import Builder
from kivy.properties import NumericProperty
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
Builder.load_string('''
<MyButton>:
on_press: print(self.np)
''')
class MyButton(Button):
np=NumericProperty(100)
class MainApp(App):
def build(self):
mb1 = MyButton(text="mb1")
mb2 = MyButton(text="mb2")
layout = BoxLayout()
layout.add_widget(mb1)
layout.add_widget(mb2)
return layout
if __name__ == '__main__':
MainApp().run()
Source: this issue.
In addition to #Nykakin's example, apply_property also interferes with inheritance in a way 'regular' class variables don't, which might therefore lead to unexpected behaviour. Here, MyButton2 is a subclass of MyButton1 and instances get attributes pp and oo. While assigning a class variable oo in MyButton1 does not interfere with instances of MyButton2, adding a Property with apply_property to an instance of MyButton1 suddenly makes pp inaccessible in MyButton2:
from kivy.properties import NumericProperty
from kivy.app import App
from kivy.uix.button import Button
from kivy.lang import Builder
class MyButton1(Button):
pass
class MyButton2(MyButton1):
def __init__(self, **kwargs):
super(MyButton2, self).__init__(**kwargs)
self.pp = 11
self.oo = 42
bl = Builder.load_string("""BoxLayout:
MyButton1:
id: hb01
text: "MyButton1"
MyButton2:
id: hb02
text: "MyButton2"
""")
def on_press(sender):
on_press.counter += 1
print "in on_press:"
try:
print " Now pp == {}".format(sender.pp)
except:
print " no attribute 'pp'"
prop = sender.property('pp', quiet=True)
sender.apply_property(pp=NumericProperty(on_press.counter))
print " Applying property ... Now it's {}".format(sender.pp)
try:
print " Now oo == {}".format(sender.oo)
except:
print " no attribute 'oo'"
sender.__class__.oo = on_press.counter + 17
on_press.counter = 0
def on_press2(sender):
print "on_press2:"
try:
print " Now pp == {}".format(sender.pp)
except:
print " no attribute 'pp'"
try:
print " Now oo == {}".format(sender.oo)
except:
print " no attribute 'oo'"
class T01App(App):
def build(self):
return bl
def on_start(self):
self.root.ids.hb01.bind(on_press=on_press)
self.root.ids.hb02.bind(on_press=on_press2)
if __name__ == '__main__':
T01App().run()

Categories

Resources