Trying to populate the text of three buttons with the content of myList["One", "Two", "Three"]
btn1 = myList[1] etc
myList will be populated fron csv file
from kivy.app import App
from kivy.lang import Builder
kv = """
BoxLayout:
Button:
id: btn1
Button:
id: btn2
Button:
id: btn3
"""
class TestApp(App):
def build(self):
my_box = Builder.load_string(kv)
my_ShowList = ['My Way', 'Wine Drinker', 'Boots']
'''
This is where I get lost
want to use for loop to populate Button text with my_ShowList items
'''
return my_box
if __name__ == '__main__':
TestApp().run()enter code here`
You can do it entirely in python code:
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
class TestClass(App):
def build(self):
my_box = BoxLayout()
my_show_list = ["My Way", "Wine Drinker", "Boots"]
my_box.my_buttons = [] # if you want to keep an "easy" reference to your buttons to do something with them later
#kivy doesnt crashes because it creates the property automatically
for message in my_show_list:
button = Button(text=message)
my_box.my_buttons.append(button)
my_box.add_widget(button)
return my_box
if __name__ == "__main__":
TestClass().run()
This should solve this problem:
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
class MyLayout(BoxLayout):
def __init__(self, **kwargs):
super(MyLayout, self).__init__(**kwargs)
self.btn_list = ['My Way', 'Wine Drinker', 'Boots']
for btn_text in self.btn_list:
self.add_widget(Button(text=btn_text))
class MyApp(App):
def build(self):
return MyLayout()
if __name__ == '__main__':
MyApp().run()
Related
Im trying to add labels for each item in OneLineAvatarListItem, but item adding only for last OneLineListItem, can i do it using python only?
My code:
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.image import Image
from kivy.uix.scrollview import ScrollView
from kivy.core.window import Window
from kivymd.uix.screen import Screen
from kivymd.uix.list import MDList, OneLineAvatarListItem
class MyApp(MDApp):
def build(self):
Window.clearcolor = (100, 100, 100, 1)
window = BoxLayout()
screen = Screen()
scroll = ScrollView()
list_view = MDList()
scroll.add_widget(list_view)
for i in range(10):
items = OneLineAvatarListItem(text=str(i))
label = Label(text='www', color=[.1, .1, .1, 1])
items.add_widget(label)
list_view.add_widget(items)
screen.add_widget(scroll)
window.add_widget(screen)
return window
MyApp().run()
Im getting that
Using example from documentation - CustomItem - I created custom ListItem with label which use ILeftBody to display on left side of standard text.
from kivymd.app import MDApp
from kivymd.uix.list import OneLineAvatarListItem, ILeftBody
from kivymd.uix.label import MDLabel
from kivy.lang import Builder
KV = '''
<MyItemList>:
LeftLabel:
id: left_label
BoxLayout:
ScrollView:
MDList:
id: scroll
'''
class MyItemList(OneLineAvatarListItem):
'''Custom list item.'''
class LeftLabel(ILeftBody, MDLabel):
'''Custom left container.'''
class MainApp(MDApp):
def build(self):
return Builder.load_string(KV)
def on_start(self):
for i in range(30):
item = MyItemList(text=f"Item {i}", on_release=self.on_click_item)
#print(item.ids)
item.ids.left_label.text = str(i)
self.root.ids.scroll.add_widget(item)
def on_click_item(self, widget):
print('text:', widget.text, 'left_label.text:', widget.ids.left_label.text)
MainApp().run()
Result:
I tried to add other label with IRightBody but it didn't work for me with OneLineAvatarListItem but work with OneLineAvatarIconListItem (with Icon in name).
from kivymd.app import MDApp
from kivymd.uix.list import OneLineAvatarIconListItem, ILeftBody, IRightBody
from kivymd.uix.label import MDLabel
from kivy.lang import Builder
KV = '''
<MyItemList>:
LeftLabel:
id: left_label
RightLabel:
id: right_label
BoxLayout:
ScrollView:
MDList:
id: scroll
'''
class MyItemList(OneLineAvatarIconListItem):
'''Custom list item.'''
class LeftLabel(ILeftBody, MDLabel):
'''Custom left container.'''
class RightLabel(IRightBody, MDLabel):
'''Custom right container.'''
class MainApp(MDApp):
def build(self):
return Builder.load_string(KV)
def on_start(self):
for i in range(30):
item = MyItemList(text=f"Item {i}", on_release=self.on_click_item)
#print(item.ids)
item.ids.left_label.text = str(i)
item.ids.right_label.text = str(100+i)
self.root.ids.scroll.add_widget(item)
def on_click_item(self, widget):
print('text:', widget.text, 'left_label.text:', widget.ids.left_label.text, 'right_label.text:', widget.ids.right_label.text)
MainApp().run()
Result:
For Label you can use ILeftBody/IRightBody without Touch and it will run function assigned to ListItem. But if you want to add Button, CheckButton and assign function to this widget then it may need ILeftBodyTouch/IRightBodyTouch without Touch
from kivymd.app import MDApp
from kivymd.uix.list import OneLineAvatarIconListItem, ILeftBody, IRightBodyTouch
from kivymd.uix.label import MDLabel
from kivymd.uix.button import MDTextButton
from kivy.lang import Builder
KV = '''
<MyItemList>:
LeftLabel:
id: left_label
RightButton:
id: right_button
# on_release: app.on_click_right_button(self)
BoxLayout:
ScrollView:
MDList:
id: scroll
'''
class MyItemList(OneLineAvatarIconListItem):
'''Custom list item.'''
class LeftLabel(ILeftBody, MDLabel):
'''Custom left container.'''
class RightButton(IRightBodyTouch, MDTextButton):
'''Custom right container.'''
class MainApp(MDApp):
def build(self):
return Builder.load_string(KV)
def on_start(self):
for i in range(30):
item = MyItemList(text=f'Item {i}', on_release=self.on_click_item)
#print(item.ids)
item.ids.left_label.text = str(i)
item.ids.right_button.text = f'More {i}'
item.ids.right_button.on_release = lambda widget=item.ids.right_button:self.on_click_right_button(widget) # it needs `widget=...` because created in `for`-loop
self.root.ids.scroll.add_widget(item)
def on_click_item(self, widget):
print('--- on_click_item ---')
print('wdiget.text:', widget.text, 'left_label.text:', widget.ids.left_label.text, 'right_button.text:', widget.ids.right_button.text)
def on_click_right_button(self, widget):
print('--- on_click_right_button ---')
print('wdiget.text:', widget.text)
print('widget.parent.parent:', widget.parent.parent)
print('widget.parent.parent.text:', widget.parent.parent.text)
MainApp().run()
I would like to position my TextInput (i.e. the field) to the left of the but I cannot do this:
I recommend rearranging your gui in kv scrpit.
Replace
Label:
...
TextInput:
...
with
BoxLayout:
orientation:'horizontal'
Label:
...
TextInput:
...
Answering the second question with code sample and help link (https://www.geeksforgeeks.org/python-textinput-in-kivy-using-kv-file/)
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.uix.textinput import TextInput
from kivy.uix.label import Label
class MyApp(App):
def build(self):
title = "Sample Layout not using kv file"
layout = BoxLayout(orientation='horizontal')
self.textinput = TextInput(text="")
self.textinput.bind(text=self.get_text)
self.btn1 = Button(text='Move text to label')
self.btn1.bind(on_press=self.get_text)
self.btn2 = Button(text='World')
self.lbl1 = Label(text="text goes here")
layout.add_widget(self.textinput)
layout.add_widget(self.btn1)
layout.add_widget(self.btn2)
layout.add_widget(self.lbl1)
return layout
def get_text(self, *args):
print(self.textinput.text)
self.lbl1.text = "You wrote " + self.textinput.text
if __name__ == '__main__':
MyApp().run()
I have the following Kivy app and I'm trying to change the text of a Label based on another widget's variable.
I mean, if the variable testing of the class TestApp changes, I want also the value of the variable text of the class TestLabel to change.
To do so, I've created a BooleanProperty in the TestLabel class that points to the testing variable of the TestApp class. The problem is that this callback is never executed despite being changing it each time I press the button.
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder
from kivy.properties import BooleanProperty
Builder.load_string('''
<MainApp>:
orientation: 'horizontal'
rows: 2
TestButton:
text: 'Change value'
on_release: self.change_value()
TestLabel:
''')
class TestLabel(Label):
testing = BooleanProperty()
def __init__(self, **kwargs):
super(TestLabel, self).__init__(**kwargs)
self.app = App.get_running_app()
self.testing = self.app.testing
self.bind(testing=self.changed_value)
def changed_value(self, _instance, newvalue):
self.text = str(newvalue)
class TestButton(Button):
def __init__(self, **kwargs):
super(TestButton, self).__init__(**kwargs)
self.app = App.get_running_app()
def change_value(self):
self.app.testing = not self.app.testing
class MainApp(BoxLayout):
pass
class TestApp(App):
testing = BooleanProperty(False)
def build(self):
return MainApp()
if __name__ == '__main__':
TestApp().run()
It is not necessary to create a testing property in TestLabel since when you do: self.bind(testing = self.changed_value) you are connecting the testing of TestLabel and not the testing of TestApp , so as it never changes testing after the bind then it never gets call the callback.
The bind has to be done using the object that has that property, and in your case the testing belongs to the App, so you must the App.
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder
from kivy.properties import BooleanProperty
Builder.load_string('''
<MainApp>:
orientation: 'horizontal'
rows: 2
TestButton:
text: 'Change value'
on_release: self.change_value()
TestLabel:
''')
class TestLabel(Label):
def __init__(self, **kwargs):
super(TestLabel, self).__init__(**kwargs)
self.app = App.get_running_app()
self.app.bind(testing=self.changed_value)
def changed_value(self, _instance, newvalue):
self.text = str(newvalue)
class TestButton(Button):
def __init__(self, **kwargs):
super(TestButton, self).__init__(**kwargs)
self.app = App.get_running_app()
def change_value(self):
self.app.testing = not self.app.testing
class MainApp(BoxLayout):
pass
class TestApp(App):
testing = BooleanProperty(False)
def build(self):
return MainApp()
if __name__ == '__main__':
TestApp().run()
I am just trying to get code working where I have two screens in a Python Kivy app that can switch back and forth, without using the .kv file stuff.
On this page: https://kivy.org/docs/api-kivy.uix.screenmanager.html, the second block of code from the top is what I am trying to accomplish, except I want to do it without the 'Builder.load_string("""' section, and instead just instantiate buttons normally.
Here is my attempt at doing so, except I can't get it to work:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.label import Label
from kivy.uix.button import Button
class MenuScreen(Screen):
def build(self):
def switchScreen():
root.manager.current = 'settings'
f = FloatLayout()
button1 = Button(text = "My settings button")
button2 = Button(text = "Back to menu", on_press = switchScreen)
f.add_widget(button1)
f.add_widget(button2)
class SettingsScreen(Screen):
def build(self):
def switchScreen():
root.manager.current = 'menu'
f = FloatLayout()
button1 = Button(text = "My settings button")
button2 = Button(text = "Back to menu", on_press = switchScreen)
f.add_widget(button1)
f.add_widget(button2)
sm = ScreenManager()
sm.add_widget(MenuScreen(name='menu'))
sm.add_widget(SettingsScreen(name='settings'))
class MainApp(App):
def build(self):
return sm
if __name__ == '__main__':
MainApp().run()
Running this code just creates a blank page that produces no errors.
Is there a way to designate it to draw a certain screen to begin with that I am missing? I'm not really sure where my issue is.
What you did wrong:
If you want to create Widget content from Python code you should place it inside Widget __init__ method, not build
You're creating a layout and then discarding it. You need to use self.add_widget(f) to actually use it after its creation
You're binding to your switchScreen method, so it needs to accept caller widget as an argument. Or you can simply use *args and not worry about it.
You're not in kv anymore, so there's no root. Use self instead.
Putting this all together:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.label import Label
from kivy.uix.button import Button
class MenuScreen(Screen):
def __init__(self, **kwargs):
super(MenuScreen, self).__init__(**kwargs)
def switchScreen(*args):
self.manager.current = 'settings'
f = FloatLayout()
button1 = Button(text = "My settings button")
button2 = Button(text = "Back to menu", on_press = switchScreen)
f.add_widget(button1)
f.add_widget(button2)
self.add_widget(f)
class SettingsScreen(Screen):
def __init__(self, **kwargs):
super(SettingsScreen, self).__init__(**kwargs)
def switchScreen(*args):
self.manager.current = 'menu'
f = FloatLayout()
button1 = Button(text = "My settings button")
button2 = Button(text = "Back to menu", on_press = switchScreen)
f.add_widget(button1)
f.add_widget(button2)
self.add_widget(f)
sm = ScreenManager()
sm.add_widget(MenuScreen(name='menu'))
sm.add_widget(SettingsScreen(name='settings'))
class MainApp(App):
def build(self):
return sm
if __name__ == '__main__':
MainApp().run()
Here is a basic sample that I am working with. The label displays as I would expect, but the text never changes, even though I do see the print statements in the console showing that the Clock.schedule_interval is ticking away. Any thoughts as to what have gone wrong???
Thank you and Happy New Year!
First the .kvlang file
<Demo>:
button_text: my_button
BoxLayout:
Label:
id: my_button
text: 'Initial Text!'
And my Python.
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import ObjectProperty, StringProperty
from kivy.clock import Clock
import random
class Demo(BoxLayout):
button_text = ObjectProperty
def change_text(self, dt):
self.button_text.text = str(random.randint(1, 10))
print('Should have changed button text to {}'.format(self.button_text.text))
def start(self):
Clock.schedule_interval(self.change_text, 10)
class TutorialApp(App):
def build(self):
foo = Demo()
foo.start()
return Demo()
if __name__ == "__main__":
TutorialApp().run()
You are missing parenthesis
button_text = ObjectProperty
change to
button_text = ObjectProperty(None) # Ha! :)
Also you should return foo and not create another Demo
def build(self):
foo = Demo()
foo.start()
#return Demo() change to...
return foo
Since the later Demo will not be updated...