Basic widgets – labels and buttons
In the last section, we used the Label
class, which is one of the multiple widgets that Kivy provides. You can think of widgets as interface blocks that we use to set up a GUI. Kivy has a complete set of widgets – buttons, labels, checkboxes, dropdowns, and many more. You can find them all in the API of Kivy under the package kivy.uix
(http://kivy.org/docs/api-kivy.html).
We are going to learn the basics of how to create our own personalized widget without affecting the default configuration of Kivy widgets. In order to do that, we will use inheritance to create the MyWidget
class in the widgets.py
file:
28.# File name: widgets.py 29. from kivy.app import App 30. from kivy.uix.widget import Widget 31. 32. class MyWidget(Widget): 33. pass 34. 35. class WidgetsApp(App): 36. def build(self): 37. return MyWidget() 38. 39. if __name__=="__main__": 40. WidgetsApp().run()
In line 32, we inherit from the base class Widget
and create the subclass MyWidget
. It is a general practice to create your own Widget
for your applications instead of using the Kivy classes directly, because we want to avoid applying our changes to all future instances of the widget Kivy class. In the case of our previous example (hello2.kv
), modifying the Label
class (line 26) would affect all of its future instances. In line 37, we instantiated MyWidget
instead of Label
directly (as we did in hello2.py
), so we can now distinguish between our widget (MyWidget
) and the Kivy widget (Widget
). The rest of the code is analogous to what we covered before.
The following is the corresponding Kivy language code (widgets.kv
):
41. # File name: widgets.kv 42. <MyWidget>: 43. Button: 44. text: 'Hello' 45. font_size: 32 46. color: .8,.9,0,1 47. pos: 0, 100 48. size: 100, 50 49. Button: 50. text: 'World!' 51. font_size: 32 52. color: .8,.9,0,1 53. pos: 100,0 54. size: 100, 50
Note that now we are using buttons instead of labels. Most of the basic widgets in Kivy work in similar ways. In fact, Button
is just a subclass of Label
that incorporates more properties such as background color.
Compare the notation of line 26 (<Label>:
) in hello2.kv
with line 43 (Button:
) of the preceding code (widgets.kv
). We used the rule class notation (<Class>:
) for the Label
(and MyWidget
) class, but a different notation (Instance:
) for Button
. In this way, we defined that MyWidget
has two instances of Button
(line 43 and 49).
Finally, we set the properties of the Button
instances. The font_size
property sets the size of the text. The color
property sets the text color and is specified in RGBA format (red, green, blue, and alpha/transparency). The properties size
and pos
set the size and position of the widget and consist of a pair of fixed coordinates (x for horizontal and y for vertical), the exact pixels on the window.
Tip
Note that the coordinate (0, 0) is located at the bottom-left corner, the Cartesian origin. Many other languages (including CSS) use the top-left corner as the (0, 0) coordinate, so take note!
The following screenshot shows the output of widgets.py
and widgets.kv
with some helpful annotations:
A couple of things can be improved in the previous code (widgets.kv
). First, there are some repeated properties for both buttons: pos
, color
, and font_size
. Instead of that, let's create our own Button
as we did with MyWidget
so it will be easy to keep the buttons' design consistent. Second, the fixed position is quite annoying because the widgets don't adjust when the screen is resized. Let's make it responsive to the screen size in the widgets2.kv
file:
55. # File name: widgets2.kv 56. <MyButton@Button>: 57. color: .8,.9,0,1 58. font_size: 32 59. size: 100, 50 60. 61. <MyWidget>: 62. MyButton: 63. text: 'Hello' 64. pos: root.x, root.top - self.height 65. MyButton: 66. text: 'World!' 67. pos: root.right - self.width, root.y
In this code (widgets2.kv
), we create (<MyButton@Button>:
) and customize the MyButton
class (lines 56 to 59) and instances (line 62 to 67). Note the differences in the manner we defined MyWidget
and MyButton
.
Note
Because we did not define the MyButton
base class in widgets.py
as we did with MyWidget
(line 32 of widgets.py
), we have to specify @Class
in the Kivy language rule (line 56). In the MyWidget
class case, we also needed to define its class from the Python side because we instantiated it directly (line 37 of widgets.py
).
In this example, each Button
class's position is responsive in the sense that they are always in the corners of the screen, no matter what the window size is. In order to achieve that, we need to use two internal variables – self
and root
. You might be familiar with the variable self
. As you have probably guessed, it is just a reference to the Widget
itself. For example, self.height
(line 64) has a value of 50
because that is the height of that particular MyButton
class. The variable root
is a reference to the Widget
class at the top of the hierarchy. For example, the root.x
(line 64) has a value of 0
because that is the position in X-axis of the MyWidget
instance created on line 37 of widgets.py
.
MyWidget
uses all of the window's space by default; therefore, the origin is (0, 0). The x
and y
and width
and height
are also widget properties, which we can use to disjoint pos
and size
respectively.
Fixed coordinates are still a laborious way to organize widgets and elements in the window. Let's move on to something smarter – layouts.