12
I Use This!
Moderate Activity

News

Analyzed 1 day ago. based on code collected 1 day ago.
Posted almost 5 years ago by Alexander Taylor
This ZDNet article was published a few days ago about how “Python apps might soon be running on Android”. It summarises some recent developments in Android support for CPython, but disappointingly it’s highly misleading about some key points. In particular the article states that “apps written in Python may …
Posted almost 5 years ago by Alexander Taylor
This ZDNet article was published a few days ago about how "Python apps might soon be running on Android". It summarises some recent developments in Android support for CPython, but disappointingly it’s highly misleading about some key p...
Posted over 5 years ago by Alexander Taylor
This post collates various resources for getting started with the Kivy graphical framework for Python. Installation Follow the official installation documentation. Introductory resources Official Kivy docs The official Kivy “Getting Started” ... [More] pages. These cover general introductory concepts, but are a bit eclectic. Kivy’s official Pong game tutorial Kivy’s … [Less]
Posted over 5 years ago by Alexander Taylor
This post collates various resources for getting started with the Kivy graphical framework for Python. Installation Follow the official installation documentation. Introductory resources Official Kivy docs The official Kivy "Getting ...
Posted over 5 years ago by Alexander Taylor
This is number 9 in a series of introductory Kivy tutorials. Central themes: Passing data between widgets, creating Kivy properties This tutorial directly follows on from the previous, so start by retrieving the previous code, as below: main.py: from kivy.app import App from kivy.uix.boxlayout import BoxLayout …
Posted over 5 years ago by Alexander Taylor
This is number 9 in a series of introductory Kivy tutorials. Central themes: Passing data between widgets, creating Kivy properties This tutorial directly follows on from the previous, so start by retrieving the previous code, as below: main.py: from ... [More] kivy.app import App from kivy.uix.boxlayout import BoxLayout from kivy.uix.slider import Slider from kivy.uix.boxlayout import BoxLayout from kivy.uix.label import Label from kivy.uix.slider import Slider from kivy.uix.widget import Widget from kivy.graphics import Rectangle, Color, Line from random import random class DrawingWidget(Widget): def on_touch_down(self, touch): super(DrawingWidget, self).on_touch_down(touch) if not self.collide_point(*touch.pos): return with self.canvas: Color(random(), random(), random()) self.line = Line(points=[touch.pos[0], touch.pos[1]], width=2) def on_touch_move(self, touch): if not self.collide_point(*touch.pos): return self.line.points = self.line.points + [touch.pos[0], touch.pos[1]] class Interface(BoxLayout): pass class DrawingApp(App): def build(self): root_widget = Interface() return root_widget DrawingApp().run() drawing.kv: <DrawingWidget>: canvas: Color: rgba: 1, 1, 1, 1 Rectangle: pos: self.pos size: self.size <ColourSlider@Slider>: min: 0 max: 1 value: 0.5 size_hint_y: None height: 50 <Interface>: orientation: 'vertical' DrawingWidget: ColourSlider: id: red_slider ColourSlider: id: green_slider ColourSlider: id: blue_slider BoxLayout: orientation: 'horizontal' size_hint_y: None height: 50 Label: text: 'output colour:' Widget: canvas: Color: rgb: red_slider.value, green_slider.value, blue_slider.value Rectangle: size: self.size pos: self.pos With this code, you should still be able to draw in the DrawingWidget region of the app interface, but the lines still have a random colour each time. Our final task is to make the lines use the colour selected via the sliders. Let’s start by reassessing where the app’s state should be held. For a start, we need to store somewhere the target colour for the lines. It’s natural to put this inside the DrawingWidget, since this class is what does the drawing and needs to know what colour to use. The best way to store this data is to use a Kivy property of our own. We’ve made use of many Kivy properties of other widgets already, but this time there isn’t one already created to hold the colour, so it’s time to create one. Change the DrawingWidget code as follows: from kivy.properties import ListProperty class DrawingWidget(Widget): target_colour_rgb = ListProperty([0, 0, 0]) def on_touch_down(self, touch): super(DrawingWidget, self).on_touch_down(touch) if not self.collide_point(*touch.pos): return with self.canvas: Color(random(), random(), random()) self.line = Line(points=[touch.pos[0], touch.pos[1]], width=2) def on_touch_move(self, touch): if not self.collide_point(*touch.pos): return self.line.points = self.line.points + [touch.pos[0], touch.pos[1]] That’s all it takes to define a new Kivy property, and it automatically has all the behaviour you’ve seen so far. For instance, if you change the target_colour_rgb of a DrawingWidget instance, an event is automatically dispatched. In fact because this is a ListProperty an event will be dispatched even if we just change the value of an item of the list! There are other types of Kivy property for ensuring correct event dispatching with different types of object (list, dict, int/float, generic objects etc.), which you can find in the documentation. Note: It may look a little strange that we’ve defined the property at the class level (no reference to self.target_colour_rgb), and it is clearly a ListProperty and not an actual list so how does accessing its values work? The answer is that Kivy properties are descriptors, which are defined at the class level but here are coded to behave like normal lists/ints/whatever when accessed from a class instance. You don’t need to worry about these details, just consider the properties as normal attributes of your objects when accessing them. As an example of what that really means, lets hook up the property to change so that we can respond to these events. Change your kv file rule to read as follows: <Interface>: orientation: 'vertical' DrawingWidget: target_colour_rgb: red_slider.value, green_slider.value, blue_slider.value # <- new line ColourSlider: id: red_slider ColourSlider: id: green_slider ColourSlider: id: blue_slider BoxLayout: orientation: 'horizontal' size_hint_y: None height: 50 Label: text: 'output colour:' Widget: canvas: Color: rgb: red_slider.value, green_slider.value, blue_slider.value Rectangle: size: self.size pos: self.pos Note that the only new line here sets the value of target_colour_rgb based on the values of the sliders. We’re once again taking advantage of automatic kv event binding: whenever any of red_slider.value, green_slider.value or blue_slider.value changes then this line will be re-evaluated to update target_colour_rgb. We can add some code to prove that it’s working, via a new method in the DrawingWidget class: def on_target_colour_rgb(self, instance, value): print(f"target_colour_rgb changed to {self.target_colour_rgb}") A method with this name will be called automatically whenever the target_colour_rgb property changes - this is another handy feature of Kivy event dispatching, instead of binding explicitly this default event method is always available. You can consider that code something like self.bind(target_colour_rgb=self.on_target_colour_rgb) has been automatically run to create the event binding. Now, run the application and move the values of the sliders. You should see code printed in your terminal every time a slider moves, because every movement updates the value of target_colour_rgb: target_colour_rgb changed to [0.20853658536585365, 0.6012195121951219, 0.4573170731707317] target_colour_rgb changed to [0.20853658536585365, 0.6012195121951219, 0.4585365853658537] target_colour_rgb changed to [0.20853658536585365, 0.6012195121951219, 0.45975609756097563] Note: The colour changes in this example are very small because you’re getting an update every time the slider moves even a single pixel! The final step is to make the DrawingWidget use this target colour for the next line it draws. For this we just have to update the on_touch_down method: def on_touch_down(self, touch): super(DrawingWidget, self).on_touch_down(touch) if not self.collide_point(*touch.pos): return with self.canvas: Color(*self.target_colour_rgb) # <- this line changed self.line = Line(points=[touch.pos[0], touch.pos[1]], width=2) That’s all there is to it! When we make the new Color instruction for the new line, we pass in the current value of our property instead of selecting random values. Run the app now and every line should match your currently selected colour: For a further example, let’s add a similar method to set the Line width. Again, we add a Kivy property to DrawingWidget: from kivy.properties import ListProperty, NumericProperty class DrawingWidget(Widget): target_colour_rgb = ListProperty([0, 0, 0]) target_width_px = NumericProperty(0) Then in the kv rule we add a Slider to select the width, and connect it to the property: <Interface>: orientation: 'vertical' DrawingWidget: target_colour_rgb: red_slider.value, green_slider.value, blue_slider.value target_width_px: width_slider.value ColourSlider: id: red_slider ColourSlider: id: green_slider ColourSlider: id: blue_slider BoxLayout: orientation: 'horizontal' size_hint_y: None height: 50 Label: text: 'output colour:' Widget: canvas: Color: rgb: red_slider.value, green_slider.value, blue_slider.value Rectangle: size: self.size pos: self.pos BoxLayout: orientation: 'horizontal' size_hint_y: None height: 50 Label: text: "width: {}".format(width_slider.value) Slider: id: width_slider min: 2 max: 10 value: 2 And finally, update the DrawingWidget.on_touch_down to use the currently-selected width for the new Line instruction: def on_touch_down(self, touch): super(DrawingWidget, self).on_touch_down(touch) if not self.collide_point(*touch.pos): return with self.canvas: Color(*self.target_colour_rgb) self.line = Line(points=[touch.pos[0], touch.pos[1]], width=self.target_width_px) Note: I’ve added not just a single Slider, but a new BoxLayout to the kv rule, in order to display a Label indicating what the slider is for. Notice how, consistent with everything so far, the Label automatically updates to always show the current value of the Slider. Run the app and try the drawing. You should now be able to control both the colour and width of every line: With that, the application is fully connected together. We have a UI element for drawing, alongside extra elements for controlling the details of the lines, with data passed around using Kivy properties. These basic ideas are at the heart of all Kivy applications. This would be a good time to experiment. Try adding or removing widgets, and maybe adding more customisation to the lines. Full code main.py: from kivy.app import App from kivy.uix.boxlayout import BoxLayout from kivy.uix.slider import Slider from kivy.uix.boxlayout import BoxLayout from kivy.uix.label import Label from kivy.uix.slider import Slider from kivy.uix.widget import Widget from kivy.graphics import Rectangle, Color, Line from kivy.properties import ListProperty, NumericProperty from random import random class DrawingWidget(Widget): target_colour_rgb = ListProperty([0, 0, 0]) target_width_px = NumericProperty(0) def on_touch_down(self, touch): super(DrawingWidget, self).on_touch_down(touch) if not self.collide_point(*touch.pos): return with self.canvas: Color(*self.target_colour_rgb) self.line = Line(points=[touch.pos[0], touch.pos[1]], width=self.target_width_px) def on_touch_move(self, touch): if not self.collide_point(*touch.pos): return self.line.points = self.line.points + [touch.pos[0], touch.pos[1]] def on_target_colour_rgb(self, instance, value): print(f"target_colour_rgb changed to {self.target_colour_rgb}") class Interface(BoxLayout): pass class DrawingApp(App): def build(self): root_widget = Interface() return root_widget DrawingApp().run() drawing.kv: <DrawingWidget>: canvas: Color: rgba: 1, 1, 1, 1 Rectangle: pos: self.pos size: self.size <ColourSlider@Slider>: min: 0 max: 1 value: 0.5 size_hint_y: None height: 50 <Interface>: orientation: 'vertical' DrawingWidget: target_colour_rgb: red_slider.value, green_slider.value, blue_slider.value target_width_px: width_slider.value ColourSlider: id: red_slider ColourSlider: id: green_slider ColourSlider: id: blue_slider BoxLayout: orientation: 'horizontal' size_hint_y: None height: 50 Label: text: 'output colour:' Widget: canvas: Color: rgb: red_slider.value, green_slider.value, blue_slider.value Rectangle: size: self.size pos: self.pos BoxLayout: orientation: 'horizontal' size_hint_y: None height: 50 Label: text: "width: {:.1f}".format(width_slider.value) Slider: id: width_slider min: 2 max: 10 value: 2 [Less]
Posted over 5 years ago by Alexander Taylor
Central themes: Event binding and canvas instructions in kv language This tutorial directly follows on from the previous, so start by retrieving the previous code, as below: main.py: from kivy.app import App from kivy.uix.boxlayout import BoxLayout ... [More] from kivy.uix.slider import Slider from kivy.uix.boxlayout import BoxLayout from kivy.uix.label import Label from kivy.uix.slider import Slider from kivy.uix.widget import Widget from kivy.graphics import Rectangle, Color, Line from random import random class DrawingWidget(Widget): def __init__(self): super(DrawingWidget, self).__init__() with self.canvas: Color(1, 1, 1, 1) self.rect = Rectangle(size=self.size, pos=self.pos) self.bind(pos=self.update_rectangle, size=self.update_rectangle) def update_rectangle(self, instance, value): self.rect.pos = self.pos self.rect.size = self.size def on_touch_down(self, touch): super(DrawingWidget, self).on_touch_down(touch) if not self.collide_point(*touch.pos): return with self.canvas: Color(random(), random(), random()) self.line = Line(points=[touch.pos[0], touch.pos[1]], width=2) def on_touch_move(self, touch): if not self.collide_point(*touch.pos): return self.line.points = self.line.points + [touch.pos[0], touch.pos[1]] class Interface(BoxLayout): pass class DrawingApp(App): def build(self): root_widget = Interface() return root_widget DrawingApp().run() drawing.kv: <Interface>: orientation: 'vertical' DrawingWidget: Slider: min: 0 max: 1 value: 0.5 size_hint_y: None height: 80 Slider: min: 0 max: 1 value: 0.5 size_hint_y: None height: 80 Slider: min: 0 max: 1 value: 0.5 size_hint_y: None height: 80 BoxLayout: orientation: 'horizontal' size_hint_y: None height: 80 Label: text: 'output colour:' Widget: The first thing to do is draw the coloured Rectangle that the final Widget uses to display an output colour, and for this we need to know how to draw canvas instructions in kv language. The syntax is as below: Widget: canvas: Color: rgb: 0, 1, 0 # using a fixed colour for now Rectangle: size: self.size pos: self.pos Run the code, and you’ll see another of kv language’s most important features; automatic event binding. In the original Python code of tutorial 7 we needed an extra .bind(...) call to make the be updated to always be placed within its Widget. In kv language this is not necessary, the dependency on self.size and self.pos is automatically detected, and a binding automatically created! This is also the generic syntax for canvas instructions; first add canvas: (or canvas.before or canvas.after), then, indent by 4 spaces, and add canvas instructions much like you would Widgets. However, note that canvas instructions are not widgets. The only thing now missing from the original Python interface implementation in tutorial 7 is having the Sliders automatically update the output colour rectangle. Change the : rule to the following: <Interface>: orientation: 'vertical' DrawingWidget: Slider: id: red_slider min: 0 max: 1 value: 0.5 size_hint_y: None height: 80 Slider: id: green_slider min: 0 max: 1 value: 0.5 size_hint_y: None height: 80 Slider: id: blue_slider min: 0 max: 1 value: 0.5 size_hint_y: None height: 80 BoxLayout: orientation: 'horizontal' size_hint_y: None height: 80 Label: text: 'output colour:' Widget: canvas: Color: rgb: red_slider.value, green_slider.value, blue_slider.value Rectangle: size: self.size pos: self.pos There are actually only two changes here; we gave each Slider an id declaration, and in the canvas Color referred to the sliders with this name. Giving a widget an id is just like naming it in Python so that you can refer to it elsewhere. Thanks to kv’s automatic binding, this is all we need to do to have the Color update automatically whenever a slider value changes. Run the code, and you should see that things work exactly as they did in the original Python interface. We can finish this tutorial with a couple of extra kv conveniences. First, just as we added an automatically updating Rectangle in the Widget kv, we can do the same for the background of the DrawingWidget. Delete the __init__ and update_rectangle methods in the Python DrawingWidget code, and add a new rule in the kv file: <DrawingWidget>: canvas: Color: rgba: 1, 1, 1, 1 Rectangle: pos: self.pos size: self.size Second, you might have noticed that there’s a lot of code duplication in each of the Slider rules - we set the same min, max, initial value`, ``size_hint_y` and height for every one. As is normal in Python, it would be natural to abstract this in a new class, so as to set each value only once. You can probably already see how to do this with what we’ve learned so far (make a new class YourSlider(Slider): in the Python and add a new : rule in the kv), but I’ll note that you can even do this entirely in kv: <ColourSlider@Slider>: min: 0 max: 1 value: 0.5 size_hint_y: None height: 80 <Interface>: orientation: 'vertical' DrawingWidget: ColourSlider: id: red_slider ColourSlider: id: green_slider ColourSlider: id: blue_slider BoxLayout: orientation: 'horizontal' size_hint_y: None height: 80 Label: text: 'output colour:' Widget: canvas: Color: rgb: red_slider.value, green_slider.value, blue_slider.value Rectangle: size: self.size pos: self.pos The new : rule defines a dynamic class, a Python class kv rule without a corresponding Python code definition. This is convenient if you want to do something repeatedly only in kv, and never access it from Python. At this point, we’ve reached feature parity with the original Python code, and seen all the basics of kv language. In the next tutorial we’ll finish off the original purpose of all these sliders; letting the user set the colour of line that is drawn by the DrawingWidget. Full code main.py: from kivy.app import App from kivy.uix.boxlayout import BoxLayout from kivy.uix.slider import Slider from kivy.uix.boxlayout import BoxLayout from kivy.uix.label import Label from kivy.uix.slider import Slider from kivy.uix.widget import Widget from kivy.graphics import Rectangle, Color, Line from random import random class DrawingWidget(Widget): def on_touch_down(self, touch): super(DrawingWidget, self).on_touch_down(touch) if not self.collide_point(*touch.pos): return with self.canvas: Color(random(), random(), random()) self.line = Line(points=[touch.pos[0], touch.pos[1]], width=2) def on_touch_move(self, touch): if not self.collide_point(*touch.pos): return self.line.points = self.line.points + [touch.pos[0], touch.pos[1]] class Interface(BoxLayout): pass class DrawingApp(App): def build(self): root_widget = Interface() return root_widget DrawingApp().run() drawing.kv: <DrawingWidget>: canvas: Color: rgba: 1, 1, 1, 1 Rectangle: pos: self.pos size: self.size <ColourSlider@Slider>: min: 0 max: 1 value: 0.5 size_hint_y: None height: 80 <Interface>: orientation: 'vertical' DrawingWidget: ColourSlider: id: red_slider ColourSlider: id: green_slider ColourSlider: id: blue_slider BoxLayout: orientation: 'horizontal' size_hint_y: None height: 80 Label: text: 'output colour:' Widget: canvas: Color: rgb: red_slider.value, green_slider.value, blue_slider.value Rectangle: size: self.size pos: self.pos [Less]
Posted over 5 years ago by Alexander Taylor
This is number 8 in a series of introductory Kivy tutorials. Central themes: Event binding and canvas instructions in kv language This tutorial directly follows on from the previous, so start by retrieving the previous code, as below: main.py: from kivy.app import App from kivy.uix.boxlayout import …
Posted over 5 years ago by Alexander Taylor
This is number 7 in a series of introductory Kivy tutorials. Central themes: kv language, building a gui, integration with Python The goal of this tutorial will be to build up a simple gui around the DrawingWidget built in the last two tutorials. A nice simple goal would be to …
Posted over 5 years ago by Alexander Taylor
Central themes: kv language, building a gui, integration with Python The goal of this tutorial will be to build up a simple gui around the DrawingWidget built in the last two tutorials. A nice simple goal would be to let the user select the colour of ... [More] the lines. Kivy actually has a ColorPicker Widget for this purpose (see the documentation), but we’ll skip that for now in order to continue demonstrating Kivy widget construction. Note Since all Kivy widgets are built out of other Widgets and canvas instructions, you might like to think about how you’d build the ColorPicker from scratch. Let’s start with the code from last time, minus the now-unnecessary red Rectangle: from kivy.app import App from kivy.uix.boxlayout import BoxLayout from kivy.uix.slider import Slider from kivy.uix.widget import Widget from kivy.graphics import Rectangle, Color, Line from random import random class DrawingWidget(Widget): def __init__(self): super(DrawingWidget, self).__init__() with self.canvas: Color(1, 1, 1, 1) self.rect = Rectangle(size=self.size, pos=self.pos) self.bind(pos=self.update_rectangle, size=self.update_rectangle) def update_rectangle(self, instance, value): self.rect.pos = self.pos self.rect.size = self.size def on_touch_down(self, touch): super(DrawingWidget, self).on_touch_down(touch) with self.canvas: Color(random(), random(), random()) self.line = Line(points=[touch.pos[0], touch.pos[1]], width=2) def on_touch_move(self, touch): self.line.points = self.line.points + [touch.pos[0], touch.pos[1]] class DrawingApp(App): def build(self): root_widget = DrawingWidget() return root_widget DrawingApp().run() I’ll demonstrate adding the new gui components in two ways; first in pure Python as has been demonstrated in previous tutorials, and second using kv language instead. So, here’s a Python implementation of the new features we want, beginning with importing the Widget classes we’ll need: from kivy.uix.boxlayout import BoxLayout from kivy.uix.label import Label from kivy.uix.slider import Slider Slider is a previously-unseen Widget displaying a draggable marker. We’ll be using a Slider for each primary colour (red, blue, green), and using this to set the Color when a Line is drawn. We can now update the build method of DrawingApp, replacing the root widget and adding the new gui components: class DrawingApp(App): def build(self): root_widget = BoxLayout(orientation='vertical') drawing_widget = DrawingWidget() red_slider = Slider(min=0, max=1, value=0.5, size_hint_y=None, height=80) green_slider = Slider(min=0, max=1, value=0.5, size_hint_y=None, height=80) blue_slider = Slider(min=0, max=1, value=0.5, size_hint_y=None, height=80) colour_row = BoxLayout(orientation='horizontal', size_hint_y=None, height=80) colour_label = Label(text='output colour:') colour_widget = Widget() # We draw a Rectangle on colour_widget exactly the same way as # with DrawingWidget, just without making a new class with colour_widget.canvas: output_colour = Color(red_slider.value, green_slider.value, blue_slider.value) output_rectangle = Rectangle() def update_colour_widget_rect(instance, value): output_rectangle.pos = colour_widget.pos output_rectangle.size = colour_widget.size colour_widget.bind(pos=update_colour_widget_rect, size=update_colour_widget_rect) def update_colour_widget_colour(instance, value): output_colour.rgb = (red_slider.value, green_slider.value, blue_slider.value) red_slider.bind(value=update_colour_widget_colour) green_slider.bind(value=update_colour_widget_colour) blue_slider.bind(value=update_colour_widget_colour) root_widget.add_widget(drawing_widget) root_widget.add_widget(red_slider) root_widget.add_widget(green_slider) root_widget.add_widget(blue_slider) root_widget.add_widget(colour_row) colour_row.add_widget(colour_label) colour_row.add_widget(colour_widget) return root_widget This is a lot of code to drop all at once, but read it carefully and you’ll see that it’s only the same concepts already introduced: we instantiate Widgets, add them to one another, and create bindings so that things automatically happen when Kivy properties are changed. In this case, we make use of the value Kivy property of the Slider widget, which gives its current value (changing automatically when the slider is moved). Run the code and you should see something like the image below. You can update the colour in the bottom right by moving the sliders. Cool. A problem now becoming obvious is that all this code is kind of verbose, and also it can be a little unclear what is happening - Widget instantiation is in a different place to where the Widgets are added to one another, which is different again to where their events are bound. You can mitigate this with a careful app structure and following whatever coding conventions you like, but some of it is unavoidable given how Python works. It’s for this reason that Kivy comes with kv language, a simple but powerful language specifically designed for creating Kivy widget trees. If learning a new language sounds worrying…don’t be concerned! Kv doesn’t have much special syntax and is targeted specifically at Kivy widgets, and much of the code you write is actually normal Python (we’ll see that soon). All of the kv language stuff discussed below is documented on the Kivy website; I’ll cover the basics, but you can find more information there. First, get rid of all the Python code from above, and replace the root widget return with the following: class Interface(BoxLayout): pass class DrawingApp(App): def build(self): root_widget = Interface() return root_widget kv language works by writing rules for Widget classes, which will be automatically applied every time you instantiate one. We can use kv for almost everything added to the app so far, but this time we’ll construct the gui step by step to see how each part is added with the new kv syntax. We’ll be writing a kv rule for the new Interface class. To start using kv language, write the following code in a file named drawing.kv. This name comes from the name of the App class, minus the App at the end if present, and in lowercase (e.g. if you named your App MySuperKivyApp you’d need to name the file mysuperkivy.kv). This is only necessary if you want the file to be automatically loaded, you can also load files or string manually. Our first kv code is: <Interface>: orientation: 'vertical' Label: text: 'label added with kv' font_size: 50 Run the code again, and you should see the a Label with the given text, as the kv file is automatically loaded and its rule applied. This demonstrates the core rules of kv syntax. A kv rule is created with the : syntax. You can make a rule for any widget, including built in ones (Kivy internally has a large kv file), and if you make multiple rules for the same Widget then all of them are applied one by one. Below the rule creation, we indent by 4 spaces and define values for Kivy properties of the widget, and add child widgets. Lines like orientation: 'vertical' set Kivy properties just like we did previously in the Python code. Note that everything to the right of the colon is normal Python code - that doesn’t matter here, but for instance we could equally well write orientation: ''.join(['v', 'e', 'r', 't', 'i', 'c', 'a', 'l']) and it would be exactly the same. You can set any Kivy property of a widget in this way, finding the available options in the documentation as previously discussed. We can also add child widgets by writing the widget name with a colon, then indenting by a further 4 spaces, as is done here with the Label. After this you can keep going as deep as you like, setting properties or adding more child widgets. We can use these pieces of syntax to construct the previous Python interface entirely in kv: <Interface>: orientation: 'vertical' DrawingWidget: Slider: min: 0 max: 1 value: 0.5 size_hint_y: None height: 80 Slider: min: 0 max: 1 value: 0.5 size_hint_y: None height: 80 Slider: min: 0 max: 1 value: 0.5 size_hint_y: None height: 80 BoxLayout: orientation: 'horizontal' size_hint_y: None height: 80 Label: text: 'output colour:' Widget: This hasn’t yet set up the event binding, but the full widget tree has been constructed entirely using the kv syntax described above. The immediate advantage of this is that kv language directly expresses the widget tree - there are no longer separate steps for instantiating Widgets, setting their properties and adding them to one another. Instead, you get to see everything at once. This gui doesn’t yet have the behaviour of the Python one (i.e. having the sliders control output colour), but in the interest of keeping these tutorials relatively short, I’ll stop here for now. In the next tutorial will see how kv language also makes event binding very easy. Full code main.py: from kivy.app import App from kivy.uix.boxlayout import BoxLayout from kivy.uix.slider import Slider from kivy.uix.boxlayout import BoxLayout from kivy.uix.label import Label from kivy.uix.slider import Slider from kivy.uix.widget import Widget from kivy.graphics import Rectangle, Color, Line from random import random class DrawingWidget(Widget): def __init__(self): super(DrawingWidget, self).__init__() with self.canvas: Color(1, 1, 1, 1) self.rect = Rectangle(size=self.size, pos=self.pos) self.bind(pos=self.update_rectangle, size=self.update_rectangle) def update_rectangle(self, instance, value): self.rect.pos = self.pos self.rect.size = self.size def on_touch_down(self, touch): super(DrawingWidget, self).on_touch_down(touch) if not self.collide_point(*touch.pos): return with self.canvas: Color(random(), random(), random()) self.line = Line(points=[touch.pos[0], touch.pos[1]], width=2) def on_touch_move(self, touch): if not self.collide_point(*touch.pos): return self.line.points = self.line.points + [touch.pos[0], touch.pos[1]] class Interface(BoxLayout): pass class DrawingApp(App): def build(self): root_widget = Interface() return root_widget DrawingApp().run() drawing.kv: <Interface>: orientation: 'vertical' DrawingWidget: Slider: min: 0 max: 1 value: 0.5 size_hint_y: None height: 80 Slider: min: 0 max: 1 value: 0.5 size_hint_y: None height: 80 Slider: min: 0 max: 1 value: 0.5 size_hint_y: None height: 80 BoxLayout: orientation: 'horizontal' size_hint_y: None height: 80 Label: text: 'output colour:' Widget: [Less]