I want to ask the user for a number, then display that amount of widgets.
This is how I do it:
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.gridlayout import GridLayout
class MainApp(App):
def build(self):
return List()
class List(GridLayout):
def __init__(self, **kwargs):
super(List, self).__init__(**kwargs)
self.cols = 1
user_input = 3 # Just an example
for i in range(user_input):
label = Label(text="Widget number {}:".format(i + 1))
self.add_widget(label)
if __name__ == "__main__":
app = MainApp()
app.run()
The problem is: the point of "kivy language" is to keep the logic in the .py file, and the design in the .kv file.
Is there any way I can keep the design only in .kv file, while doing this (having a for loop)?
(I'm new to kivy, sorry if I'm asking a simple question. :) )
Definitely, you can.
The KV file is used primarily to design the looks while the login part of a program is handled by the PY file.
.kv file
<classname>:
Button:
text:'click me'
on_release: root.function_to_call_from_py_file()
.py file
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.gridlayout import GridLayout
class List(GridLayout):
def function_to_call_from_py_file(self):
print('This function is called')
class MainApp(App):
def build(self):
return List()
if __name__ == "__main__":
app = MainApp()
app.run()
Related
This is the .py file:
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.scrollview import ScrollView
from kivy.uix.stacklayout import StackLayout
class Stack(StackLayout):
def __init__(self,**kwargs):
super().__init__(**kwargs)
for i in range(0,100):
b1 = Button(text=str(i+1),size_hint=(.1,.1))
self.add_widget(b1)
class ScrollView(ScrollView):
pass
class GameApp(App):
def build(self):
return Stack()
GameApp().run()
And this is the .kV file:
<ScrollView>:
Stack:
size_hint:1,None
height:4000
In the output I am getting the buttons but I am unable to scroll.
Hello if you are new please check this link for beginners guide.
The ScrollView only works if you put 1 widget on it with specific adjustments to size ofcourse.
Instead of this line
return stack()
You must return the scrollview widget and add the stack() layout on top. Even better you can modify your code like so
For .py
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.scrollview import ScrollView
from kivy.uix.stacklayout import StackLayout
from kivy.uix.screenmanager import Screen
class MainScreen(Screen):
pass
class Stack(StackLayout):
def __init__(self,**kwargs):
super().__init__(**kwargs)
for i in range(0,100):
b1 = Button(text=str(i+1),size_hint=(.1,.1))
self.add_widget(b1)
class GameApp(App):
def build(self):
return MainScreen()
GameApp().run()
.kv
<MainScreen>:
ScrollView:
do_scroll_y: True
do_scroll_y: False
Stack:
size_hint:1,None
height:4000
I did not test the code but thats the logic of how the code can be. The rest you can check here
In order to understand the logic behind Kivy kv language, I'm trying to rewrite a minimal application by replacing the automatic load of a kv file by a call to Builder.load_string().
Here's my starting point (source: examples 1-2, 1-3): two files, weather.py and weather.kv :
weather.py:
from kivy.app import App
class WeatherApp(App):
pass
if __name__ == '__main__':
WeatherApp().run()
and weather.kv:
Label:
text: "Hello World"
Up to there, everything's alright
.
But if I try to load manually the kv stuff, I just get a black screen (and no error message). My code:
from kivy.app import App
from kivy.lang import Builder
KV = '''
Label
text: "Hello World"
'''
Builder.load_string(KV)
class WeatherApp(App):
pass
if __name__ == '__main__':
WeatherApp().run()
I'm obviously missing something here, but what ? Any help would be appreciated !
When you create a .kv there are basic but strict rules, among them there can only be one toplevel, the toplevel is identified because it does not have "<>", besides for the App to recognize it it must have the same name of the application in lowercase, in your case the .kv is called weather.kv and the WeatherApp app. But the above does not happen if you use Builder, in the case that the .kv has a root as it is in your case Builder.load_string() returns it so you must return it in the build method of the App:
from kivy.app import App
from kivy.lang import Builder
KV = '''
Label:
text: "Hello World"
'''
root = Builder.load_string(KV)
class WeatherApp(App):
def build(self):
return root
if __name__ == '__main__':
WeatherApp().run()
I have simple code for kivy, on W10 runs without problem. It falls down during loading in kivy launcher. Problem is without message.
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.uix.button import Button
class View(BoxLayout):
def __init__(self):
super().__init__()
self.text = "No text"
but = Button(text = "Press",on_press = self.show)
self.add_widget(but)
self.lbl = Label()
self.add_widget(self.lbl)
def show(self,obj):
self.lbl.text = self.text
pass
class MyPaintApp(App):
def build(self):
return View()
if __name__ == '__main__':
MyPaintApp().run()
It does not run because you call super wrong.
As kivy launcher uses python 2, you need to pass your class (View) and the instance (self) to super.
You need to edit your class like this:
class View(BoxLayout):
def __init__(self,**kwargs):
super(View,self).__init__(**kwargs)
in every failure in kivy launcher, there is a '.kivy/log' directory inside the project directory that has a full log. you could find all the problem there.
I have a basic text input box with some text in it. When the user attempts to copy the text, I want to execute a function that modifies the text first then returns it. An on_copy event would be perfect. However, I do not see an obvious way to do this in Kivy.
You can create TextInput subclass that overrides the copy() method:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.textinput import TextInput
from kivy.clock import Clock
Builder.load_string("""
<MyWidget>:
MyTextInput:
MyTextInput:
""")
class MyTextInput(TextInput):
def copy(self, data=''):
# wrap copied text with ---
if data:
data = "--- {} ---".format(data)
else:
data = "--- {} ---".format(self.selection_text)
return super(MyTextInput, self).copy(data)
class MyWidget(BoxLayout):
pass
class ClientApp(App):
def build(self):
return MyWidget()
if __name__ == '__main__':
ClientApp().run()
You should probably override cut() method too.
I want to make a simple program that is just showing definitions that are stored in text file.One label and button to show next definition. I try to do it with documentation but i cannot find how to load text into label. Can someone show me to some good resources or code samples ?
My code for now (i want to build in on top of example from kivy website):
import kivy
kivy.require('1.9.0')
from kivy.app import App
from kivy.uix.label import Label
class MyApp(App):
def build(self):
return Label(text = 'Hello world')
if __name__ == '__main__':
MyApp().run()
The easiest way to update widgets in the UI are by binding to their properties. This can be done in code, but the real power of kivy in my opinion comes from using it's declarative UI language. Using kv, you get automatic binding.
Here is a quick example of what you might do:
from kivy.app import App
from kivy.lang import Builder
from kivy.properties import StringProperty
kv = '''
BoxLayout:
orientation: 'vertical'
Label:
text: app.text
Button:
text: 'click me'
on_press: app.clicked()
'''
class MyApp(App):
text = StringProperty("hello world")
def build(self):
return Builder.load_string(kv)
def clicked(self):
self.text = "clicked!"
if __name__ == '__main__':
MyApp().run()
In the kv description of the UI, you tell kivy that you want the text on the Label to be bound to a StringProperty on the app which you defined on the class. The auto-binding means that anytime you set a value to that property (like in the clicked function), the UI will update with the new value automatically.