Create Kivy widgets without using kv language? - python

How to create Kivy widgets without using kv language and .kv files? I am new to kivy. I usually use Tkinter, but i found out that Kivy is good for creating Android apps, so I am learning how to use it.
I know that Kivy widgets are made using .kv files, but i would like to create them like widgets in Tkinter.
# Creating widgets in tkinter:
# We'll assume tkinter is imported as tk
label_1 = tk.Label(text='Hello World', bg='white')
label_1.pack()
# Creating widgets using Kivy in .py file
label_1 = Label(text='Hello World') # eg. Not able to set color!
add_widget(label_1)
# Creating widgets using kv language
Label:
text: "Hello World"
color: 1,0,0,1
So, is there any way to make Kivy widgets completely in python? How could i set Kivy label color directly in python?
Thanks.

Here's an example of Kivy application without using kv lang:
from kivy.app import App
from kivy.uix.label import Label
class TestApp(App):
def build(self):
return Label(
text='Hello, world',
color=(1, 0, 0, 1)
)
TestApp().run()
Basically build method of kivy.app.App instance has return a main widget object, in this case a kivy.uix.Label instance. To have more complex widget you should create a subclass of some layout class and then add widgets using add_widget method.
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.boxlayout import BoxLayout
class TestWidget(BoxLayout):
def __init__(self, **args):
super(TestWidget, self).__init__(**args)
label = Label(
text='Hello, world',
color=(1, 0, 0, 1))
self.add_widget(label)
class TestApp(App):
def build(self):
return TestWidget()
TestApp().run()
I'd like to encourage you to use kv lang anyway, since it makes the code simplier.

It is completely possible to use python exclusively to write apps with kivy. I began using kivy about 6 month ago and quickly abandoned the kv files. I do not like "magical" code in the background making bindings. I know this is a preference thing and now that I know how the widgets and layouts work, it may be actually quicker to use the kv language. Things you need to do manually are keep handles between widgets throughout the widget tree and setup bindings using the kivy properties. There is a lot to learn but once you start getting it, the possibilities are endless. Most examples you find are very simple and I feel the documentation is very limited. I feel that if you are comfortable with python, you will actually learn more about how kivy works if you stay in python.
I'm marking Nykakin's answer as correct, but I just thought I'd share some details.

Related

kivy app runs without implementing the build() method

Was wondering why the Kivy code kept on showing me the same black window despite doing some updates on the kv file. Then noticed I had a typo on the buidl() method.
From the docs "...implementing its build() method so it returns a Widget instance (the root of your widget tree)
...", you have to implement the method.
Why does this code run and give the default black window?
# game.py
from kivy.app import App
from kivy.uix.widget import Widget
class Game(Widget):
pass
class GameApp(App):
def buidl(self):
return Game()
GameApp().run()
The kv file
#game.kv
<Game>:
canvas:
Color:
rgb: .5,.5, 1.0
Rectangle:
pos: 0,0
size: self.size
Running kivy 1.11.1 python 3.7
Kivy apps have a default build() method, which you can see here; it just returns an empty widget. Generally kivy has two methods to create the root widget tree, either through overriding build() or by defining a root widget in a kv file. For more information see the documentation on creating an application.
Your quote can be found in kivy basics, before your quoted sentence:
Creating a kivy application is as simple as:
I guess the authors decided to keep the basic tutorial easy and did not mention the default implementation of build, as it doesn't really do anything useful. They also omitted the kv way of defining the root widget; again I would guess to not overwhelm the reader in this first introduction.

Get children from kv file before it is applied

I have a kv file or string for example
KV = '''
<BoxLayout>
Label
Label
Button
MyButton
'''
and I would like to get children list like
['Label', 'Label', 'Button', 'MyButton']
before this kv string is applied (before Label, Button and MyButton instances created).
How to do this?
Can I use kivy.lang.Parser for that?
I suppose kivy Parser does something like that, but I didn’t figure out how to use it - the documentation is scarce on this topic, and the source code looks confusing.
I'm planning to create a widget event, named something like on_kv_pre.
You can use 'Builder.match_rule()` for your situation:
from kivy.lang import Builder
Builder.load_string('''
<BoxLayout>
Label
Label
Button
MyButton
''')
ret = Builder.match_rule_name('BoxLayout')
for child in ret[0].children:
print(child.name)
May be a bit more complicated for real rules, but maybe this can get you started.

Can I Use Tkinter window in Kivy as a sub-part of GUI?

I am new to kivy and Tkinter.
I want to use kivy as my root (main) GUI. But I also want to add Tkinker in it as a sub-part.
is it possible to integrate (fix) tkinter window in kivy GUI as sub part ???
example :
kivy code :
from kivy.app import App
from kivy.uix.image import Image
class MyApp(App):
def build(self):
return Image(source="./Logo.png")
MyApp().run()
kivy output :
Tkinter code :
import tkinter
window = tkinter.Tk()
window.title("GUI")
tkinter.Label(window, text = "Username").grid(row = 0)
tkinter.Entry(window).grid(row = 0, column = 1)
tkinter.Label(window, text = "Password").grid(row = 1)
tkinter.Entry(window).grid(row = 1, column = 1)
tkinter.Checkbutton(window, text = "Keep Me Logged In").grid(columnspan = 2)
window.mainloop()
tkinter output :
expected output :
I tried to integrate both code, but it execute one after another.
any way to add tkinter window in kivy GUI.
It's not possible to kivy window load tk. But you can try make as two programs with statick positions (but that is hardway), or just see how to write all code in one framework
It probably is possible to run Kivy in an opengl context within a tkinter window, but there's no support for this and you'd have to write a fair amount of code to get it to work. Essentially you'd need to write a tkinter backend provider for the Kivy window.
I wouldn't recommend this, it would be much easier to do everything within one framework.

Using external .kv file vs doing things internally?

I have noticed that most examples I foind online don't have an external .kv file. They define all the instances internally. However they also say that having an external .kv file is a good practice. Which is better to do? If having external .kvfiles are better, then how am I supposed to use the code which uses internal code and turn it into external .kv files?
For example, doing this ->
from kivy.app import App
from kivy.uix.scatter import Scatter
from kivy.uix.label import Label
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.textinput import TextInput
from kivy.uix.boxlayout import BoxLayout
class TutorialApp(App):
def build(self):
b = BoxLayout(orientation='vertical')
t = TextInput(font_size=150,
size_hint_y=None,
height=200,
text='default')
f = FloatLayout()
s = Scatter()
l = Label(text='default',
font_size=150)
t.bind(text=l.setter('text'))
f.add_widget(s)
s.add_widget(l)
b.add_widget(t)
b.add_widget(f)
return b
if __name__ == "__main__":
TutorialApp().run()
Instead of-
<ScatterTextWidget>:
orientation: 'vertical'
TextInput:
id: my_textinput
font_size: 150
size_hint_y: None
height: 200
text: 'default'
FloatLayout:
Scatter:
Label:
text: my_textinput.text
font_size: 150
"Internal" usage of kv is through Builder class, which allows you even to load external file. Those examples are worded in a Builder.load_string(...) way because it's way simpler to have a small example in one place in one file.
How to convert it to the external one? Simple, copy&paste the string from Builder.load_string() into a separate .kv file with a name of your class that inherits from App(your main class with build()) and that's it. It'll load the same thing from the external file.
Why it's better or worse? Isn't any of that actually. It's like comparing "java" and python style i.e. either putting everything out of your file and having basically this construction a'la java, where the main file contains this:
class This(something):
SpecialClass.doThis()
AnotherClass.doThat()
and other classes(or different things) are in separate files. Or this construction:
class Special(...):
...
class Another(...):
...
class This(something):
Special.do_this()
Another.do_that()
Both of them are useful and you'll find yourself working with a mix between them. It's about transparency and clearness of your code, but maybe you don't want to have a hundred of files... or a 2MB main.py, pretty much compromise of how do you decide to code.
Edit:
The python vs kv is a funny "fight", but except a for(and while?) loop you can pretty much do everything necessary inside kv in such an easy way! Kv is here to make writing easier e.g. remove too much stuff like add_widget() or basically making an empty class just to rename a widget or to change its size for using it in one place.
With python in a 500line file without kv you won't do that much as with 100 extra lines in kv. The documentation has important parts in python and maybe it's even targeted for users who can't/don't want to use kv. Also this and all examples highly depend on the author of an example and that particular part of the docs.
Which returns me back to the java vs python style of coding I mentioned before. It's pointless to do complicated stuff just because you think it'll feel/look better if you can do it cleaner and more readable i.e. don't just go one way if you have a tool that increase your speed of coding exponentially. Find the middle way.

Associating Screens with GridLayout classes in kivy

I've created a ScreenManager, and created several Screen instances for that ScreenManager.
I'd like each Screen to display a GridLayout class. For example, let's say you have:
class MainScreen(Screen):
...
class MainLayout(GridLayout):
...
When MainScreen is the active screen, I'd like MainLayout to be shown.
Is there a way to do this purely in python (i.e. without markup)? Thank you.
Is there a way to do this purely in python (i.e. without markup)? Thank you.
You never need to use kivy language (I assume that's what you mean by markup), though it's highly recommended where possible because it makes lots of stuff easier.
Nonetheless, to actually answer your question, all you have to do is add your gridlayout widget to your screen widget, something like
mainscreen = MainScreen()
mainlayout = MainLayout()
mainscreen.add_widget(mainlayout)
Then when you set the current screen in your screenmanager to be mainscreen, you should see the GridLayout.
Edit: In case it's unclear, this is in general the way you add widgets to other widgets. When you see an example in kv language like
<MyScreen>:
GridLayout:
...
...ultimately that gets translated to something much like the above example code - an instance of MyScreen is created and a GridLayout is added to it with add_widget.

Categories