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.
Related
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 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'm simply trying to make some example code I found which dynamically adds widgets to a view incorporate with a Screen Manager, and I cannot get it to work.
I found this example Associating Screens with GridLayout classes in kivy and as far as I know I've implemented the strategy defined there, but I keep getting kivy.uix.screenmanager.ScreenManagerException: ScreenManager accepts only Screen widget.
EDIT: Here's my updated code. now getting error: AttributeError: MainScreen instance has no attribute 'add_widget'
from kivy.uix.modalview import ModalView
from kivy.uix.listview import ListView
from kivy.uix.gridlayout import GridLayout
from kivy.lang import Builder
from kivy.app import App
import citylists
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
#using 'sla'...whatever that means...
Builder.load_string("""
#:import ListItemButton kivy.uix.listview
#:import sla kivy.adapters.listadapter
<ListViewModal>:
ListView:
size_hint: .8, .8
adapter:
sla.ListAdapter(
data=["Item #{0}".format(i) for i in range(100)],
cls=ListItemButton.ListItemButton)
""")
class ListViewModal(ModalView):
def __init__(self, **kwargs):
super(ListViewModal, self).__init__(**kwargs)
class MainView(Screen):
def __init__(self, **kwargs):
kwargs['cols'] = 1
super(MainView, self).__init__(**kwargs)
listview_modal = ListViewModal()
self.add_widget(listview_modal)
class MainScreen():
pass
mainscreen=MainScreen()
mainlayout = MainView()
mainscreen.add_widget(mainlayout)
class CARApp(App):
screen_manager = None
def build(self):
self.screen_manager = ScreenManager()
self.screen_manager.add_widget(mainscreen)
if __name__ == '__main__':
CARApp().run()
self.screen_manager.add_widget(MainScreen)
You're passing the actual class MainScreen, but you need to add an instance of the class, i.e. MainScreen().
Edit, although looking more at your code, you probably want to add the instance you have already created, which is mainscreen. It might also be neater to move this widget creation into the build method, since that's where it's actually needed.
I am using a screen manager and would like to add widgets to the screen subclass without using the .kv file.
class MainMenu(Screen):
def __init__(self, **kwargs):
gLayout = GridLayout()
gLayout.add_widget(Button(text = 'test'))
class Sis(App):
def build(self):
root = ScreenManager()
root.add_widget(MainMenu(name = 'mainMenu'))
root.current = 'mainMenu'
return root
Sis().run()
When I try to run the above code I get (pygame parachute) Segmentation Fault.
If I create the layout in the .kv file it works fine.
I've tried fiddling around with on_pre_enter and on_enter but I'm pretty sure I was using them wrong.
Any help is appreciated.
You forgot calling parent constructor of MainMenu class:
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.gridlayout import GridLayout
from kivy.uix.button import Button
class MainMenu(Screen):
def __init__(self, **kwargs):
super(MainMenu, self).__init__(**kwargs)
self.add_widget(Button(text = 'test'))
class Sis(App):
def build(self):
root = ScreenManager()
root.add_widget(MainMenu(name = 'mainMenu'))
root.current = 'mainMenu'
return root
Sis().run()