How to implement for loop in .kv file - python-3.x

I have written a python code in python file(main.py) to create a kivy app that contains dynamically created labels which works fine.
Here is main.py file
main.py
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.gridlayout import GridLayout
class createLabels(GridLayout):
def __init__(self,**kwargs):
super().__init__(**kwargs)
self.cols=1
labels=[Label(text='Label '+str(i)) for i in range(5)]
[self.add_widget(label) for label in labels]
class DocApp(App):
def build(self):
return createLabels()
if __name__=="__main__":
DocApp().run()
However i would like to dynamically create labels similar to the one above using a kivy language file (.kv). I am not sure whether we can use lists and for statements in .kv file. I tried the solution mentioned in one of the similar type question but it didn't work.

You could use on_kv_post which runs when the kv class which you use on_kv_post is ready. And dynamically, like in push of buttons, is basically the same as in the example below.
from kivy.app import App
from kivy.lang import Builder
KV = '''
#: import Label kivy.uix.label.Label
GridLayout:
cols: 1
on_kv_post:
[self.add_widget(Label(text="Label " + str(i))) for i in range(9)]
'''
class TestApp(App):
def build(self):
return Builder.load_string(KV)
if __name__ == '__main__':
TestApp().run()

Related

how to print all textinputs values in a python/kivy app, added by a for cycle?

I add some TextInputs in a Python3/kivy app, using a for cycle. I'd need to get all updated values after clicking a Button:
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.textinput import TextInput
from kivy.uix.button import Button
class app(App):
def build(self):
self.box=BoxLayout(orientation='vertical')
for n in range(5):
self.box.add_widget(TextInput())
def doet(instance):
print('values: ')
#print all TextInputs values
self.box.add_widget(Button(text='DOET',on_press=doet))
return self.box
app().run()
def doet(instance):
print('values: ')
# for loop:
for t in instance.parent.children:
if isinstance(t, TextInput):
print(t.text)
# using list comprehension
print('\n'.join([t.text for t in instance.parent.children if isinstance(t, TextInput)]))

How to use strings in kivy

I want want to use strings from my main python file to the .kv file but don't know what commands to use. I want to put the string in the label text
from kivy.app import App
import kivy.uix.label
import kivy.uix.button
from kivy.uix.boxlayout import BoxLayout
string1 = "hi"
class TestApp(BoxLayout):
pass
class MyApp(App):
def build(self):
return TestApp()
if __name__ == '__main__':
MyApp().run()
<TestApp>
BoxLayout:
Label:
text: 'hi'
I tried searching all over the internet but couldn't find any solutions
I I figured it out. You should add a string property in your class to use that string

Python kivy RecursionError: maximum recursion depth exceeded in comparison

I am trying to create a simple app with kivy in python
but when i run this code i get following error
RecursionError: maximum recursion depth exceeded in comparison
import wikipedia
from kivy.app import App
from kivy.uix.popup import Popup
from kivy.uix.label import Label
from kivy.uix.gridlayout import GridLayout
from kivy.uix.textinput import TextInput
from kivy.uix.button import Button
class GridLayout(GridLayout):
def __init__(self, **kwargs):
super(GridLayout, self).__init__()
# Number of columns
self.cols = 1
# Second grid Layout
self.second_layout = GridLayout()
self.second_layout.cols = 2
# Creating a text field to show the result of entered query
self.query_result = TextInput(text='', size_hint_y=0.8)
self.second_layout.add_widget(self.query_result) # Adding query result on the screen
# Creating a text input field to get the query from user
self.query = TextInput(text='', multiline=False, hint_text="Enter your Query", size_hint_y=0.1, font_size=20)
self.second_layout.add_widget(self.query)
# Adding Second layout on the screen
self.add_widget(second_layout)
# Creating a submit button
self.submit_button = Button(text="Submit", size_hint_y=0.1, font_size=40, on_press=self.submit)
self.add_widget(self.submit_button)
def submit(self, instance):
try:
query_result_from_wikipedia = wikipedia.page(self.query.text).summary
self.query_result.text = query_result_from_wikipedia
except:
popup = Popup(title='Query Not Found',
content=Label(text='Try to Search Anything else'),
size_hint=(None, None), size=(400, 400))
popup.open()
class MyApp(App):
def build(self):
return GridLayout()
if __name__ == '__main__':
MyApp().run()
But when i remove the second gridlayout from it it runs without errors
The first problem is the name of your class. Don't name a class the same as its subclass:
class GridLayout(GridLayout):
is likely to cause problems. Just change it to something like:
class MyGridLayout(GridLayout):

how to reference kivy widget ids dynamically created using kv language through a for loop in main python file?

I have dynamically created textinput widgets in a .kv file using kv language. However i would like to set the text in main python file using a for loop by referencing their ids.
I have written the following code:
main.py
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.widget import Widget
class setText(Widget):
def __init__(self,**kwargs):
super().__init__(**kwargs)
texts=['txtip1','txtip2']
IDS=self.ids.keys()
for i in range(IDS):
self.ids[IDS[i]].text=texts[i]
class DocApp(App):
def build(self):
return Builder.load_file("docapp\Doc.kv")
return setText()
if __name__=="__main__":
DocApp().run()
Doc.kv
# File: docapp.py
#: import TextInput kivy.uix.textinput.TextInput
GridLayout:
cols:1
on_kv_post:
[self.add_widget(TextInput(id=str(i))) for i in range(2)]
I have searched through other questions but couldn't find suitable solution. Please help
The problem in your code, is that id only works in the kv syntax.
So you need to reference your widgets some other way.
In case you need to do it that way, dynamically adding in kv and accessing in a loop in python, you could try something like the example below.
The text will change after 5 seconds in this case. If you know that the only children of this gridlayout will be the widgets you want to access, you might as well just iterate the children.
from kivy.app import App
from kivy.lang import Builder
from kivy.clock import Clock
KV = """
#: import TextInput kivy.uix.textinput.TextInput
GridLayout:
cols:1
on_kv_post:
for i in range(2): app.dynamic_widgets.append(TextInput())
for wid in app.dynamic_widgets: self.add_widget(wid)
"""
class DocApp(App):
dynamic_widgets = []
def build(self):
Clock.schedule_once(self.set_text, 5)
return Builder.load_string(KV)
def set_text(self, dt):
texts=['txtip1','txtip2']
for text, wid in zip(texts, self.dynamic_widgets):
wid.text = text
if __name__=="__main__":
DocApp().run()
Now if you remove one of the widgets, you probably want to remove it from the list also.
You can create the TextInput widgets dynamically in kv by creating the kv dynamically. Here is a modification of your code that does that:
from kivy.app import App
from kivy.clock import Clock
from kivy.lang import Builder
class DocApp(App):
def build(self):
# schedule the call to add the texts
Clock.schedule_once(self.setText)
# return the root widget from the kvString
return layoutRoot
def setText(self, dt):
texts=['txtip1','txtip2']
IDS=self.root.ids.keys()
i = 0
for id in IDS:
self.root.ids[id].text=texts[i]
i += 1
if __name__=="__main__":
# Create the kv string here
kvString = '''
GridLayout:
cols:1
'''
for i in range(2):
kvString += ' TextInput:\n' + ' id: ' + str(i) + '\n'
# Load the kv string
layoutRoot = Builder.load_string(kvString)
# and finally, run the App
DocApp().run()
I have eliminated the setText class (assuming it was only a holder for the setText method), and placed that method in the App. The Clock.schedule_once() schedules the call to setText to happen after the App has been created.

Python Kivy Panel Header unable to render content from class

I am trying to create a simple TabbedPanel with 4 tabs. I want each tab to render the widgets from 4 classes. Kivy seems to not be rendering this simple Label. I want to do this with the libraries and not by creating a .kv file and importing it with Builder.load_file(file). In the code I provided, I only show the default_tab. Thanks in advance.
import kivy
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput
from kivy.uix.gridlayout import GridLayout
from kivy.uix.tabbedpanel import TabbedPanel, TabbedPanelHeader
kivy.require('1.10.1')
class DeployScreen(GridLayout):
def __init__(self, **kwargs):
super(DeployScreen, self).__init__(**kwargs)
self.cols = 1
self.add_widget(Label(text='Deploy'))
return(None)
class NucleusPanel(TabbedPanel):
tab_pos = "top_left"
nuc_panel = TabbedPanel()
nuc_panel.default_tab_text = "Deploy"
nuc_panel.default_tab_content = DeployScreen()
class NucleusApp(App):
def build(self):
return(NucleusPanel())
if __name__ == "__main__":
NucleusApp().run()
Add a constructor for class NucleusPanel()
main.py
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.gridlayout import GridLayout
from kivy.uix.tabbedpanel import TabbedPanel
class DeployScreen(GridLayout):
def __init__(self, **kwargs):
super(DeployScreen, self).__init__(**kwargs)
self.cols = 1
self.add_widget(Label(text='Deploy'))
class NucleusPanel(TabbedPanel):
def __init__(self, **kwargs):
super(NucleusPanel, self).__init__(**kwargs)
self.tab_pos = "top_left"
self.default_tab_text = "Deploy"
self.default_tab_content = DeployScreen()
class NucleusApp(App):
def build(self):
return NucleusPanel()
if __name__ == "__main__":
NucleusApp().run()
Output

Resources