]> git.jsancho.org Git - blog.git/blob - posts/20180802-kivyforms.html
Merge branch 'master' into english
[blog.git] / posts / 20180802-kivyforms.html
1 title: Designing forms with Python and Kivy
2 date: 2018-08-03 13:43
3 tags: form, python, kivy, kivyforms
4 ---
5 <div>
6   <a href="images/form.jpg"><img src="images/form.jpg" alt="form" width="300" height="200" class="image-right" /></a>
7
8   <p>There are many libraries to create graphical interfaces with Python. For example, I tried with <a href="https://wxpython.org/">wxPython</a>, <a href="https://riverbankcomputing.com/software/pyqt/">PyQt</a> and <a href="https://kivy.org/">Kivy</a>. The latter is the one I liked the most for a number of reasons:</p>
9
10   <ul>
11     <li>It's multiplatform and works in GNU/Linux, Windows, OS X, Android, iOS and Raspberry Pi. I've only tried the first two, but I've been able to verify that it's designed for use with keyboard and mouse or with touch screens.</li>
12     <li>It's not based on the platforms native widgets but has its own, so the applications look the same on all platforms.</li>
13     <li>It's fast; the graphics engine works on OpenGL ES 2 and many parts are written with Cython.</li>
14     <li>You can design the interfaces directly with Python or using Kv language.</li>
15     <li>It's a relatively new project, and well maintained.</li>
16     <li>Good documentation and many examples.</li>
17   </ul>
18
19   <p>I'm working on an apps development framework, so I need developers to be able to design forms quickly, WYSIWYG way, and they can also include their own themes, colors, etc. Thanks to <a href="https://kivy.org/docs/guide/lang.html">Kv language</a>, this task is easier for me. It's something similar to QML in Qt, and allows to save compositions in text files that can be loaded later by the application, without having to modify any code.</p>
20
21   <p>For example, the <a href="https://kivy.org/">Kivy</a> <i>Hello World</i> would be:</p>
22
23   <pre>
24     # main.py file
25     from kivy.app import App
26
27     class TestApp(App):
28         pass
29
30     TestApp().run()
31
32     # test.kv file
33     Button:
34         text: 'Hello World'
35   </pre>
36
37   <p>To design the forms, I created a widget that provides a canvas, in which it's possible to add buttons, labels, text fields and things like that. The project is called <a href="https://gitlab.com/jsancho/kivyforms">KivyForms</a> and is currently beta. You can also watch a <a href="https://www.youtube.com/watch?v=512Jfl2CUdY">video with an example of using KivyForms</a>. The idea is that the widget has a powerful API to be integrated into any application that needs forms composition.</p>
38
39   <p>Look what the widget contains:</p>
40
41   <pre>
42     class FormCanvas(BoxLayout):
43         def __init__(self, *args, **kwargs):
44             super(FormCanvas, self).__init__(*args, **kwargs)
45
46             self._canvas = StackLayout(
47                 orientation='lr-tb',
48                 padding=[10, 10, 10, 10],
49                 spacing=[10, 10]
50             )
51             super(FormCanvas, self).add_widget(self._canvas)
52   </pre>
53
54   <p>FormCanvas is based on a Kivy BoxLayout, and has a StackLayout inside, where form widgets will be added. The StackLayout allows other widgets to stack without occupying the full size of the screen.</p>
55
56   <pre>
57     def add_widget(self, widget):
58         g = Grabbable(
59             height=self.widgets_height,
60             size_hint=self.widgets_size_hint
61         )
62         g.add_widget(widget)
63         self._canvas.add_widget(g)
64   </pre>
65
66   <p>Each time we add a widget, a <b>Grabbable</b> item is instantiated for containing the widget we want to add. It's this <b>Grabbable</b> item that we really add to the canvas. This allows us to select the widget and move it around the form to design the composition.</p>
67
68   <p>There is a <b>Destination</b> item to indicate where the widget will be placed when the drag operation ends.</p>
69   
70   <pre>
71     class Destination(Label):
72         def __init__(self, **kwargs):
73             super(Destination, self).__init__(**kwargs)
74             self.text = 'Widget goes here'
75             self.color = [1, 1, 0, 1]
76             with self.canvas.after:
77                 Color(1, 1, 0, 1)
78                 self.box = Line(dash_length=8, dash_offset=4)
79
80         def update_box(self):
81             self.box.points = [
82                 self.x, self.y,
83                 self.x, self.y + self.height,
84                 self.x + self.width, self.y + self.height,
85                 self.x + self.width, self.y,
86                 self.x, self.y
87             ]
88   </pre>
89
90   <p>This item, which is a simple label with dotted border, is very useful for the developer to be able to place widgets in the right place.</p>
91
92   <p>Finally, it's possible to export the composition to Kv language. KivyForms is in charge of filtering all the <b>Grabbable</b> items and the configuration needed for the design of the form, so we can save the composition directly to a file, ready to be used in our programs.</p>
93
94   <p><a href="https://gitlab.com/jsancho/kivyforms">KivyForms</a> is distributed under <a href="https://opensource.org/licenses/MIT">MIT license</a>. Although I prefer GPL licenses, in this case I have decided to use, for consistency, the same license as Kivy, so you are invited to collaborate on the project.</p>
95 </div>