mirror of https://github.com/kivy/kivy.git
754 lines
26 KiB
ReStructuredText
754 lines
26 KiB
ReStructuredText
.. _widgets:
|
|
|
|
Widgets
|
|
=======
|
|
|
|
.. |size_hint| replace:: :attr:`~kivy.uix.widget.Widget.size_hint`
|
|
.. |pos_hint| replace:: :attr:`~kivy.uix.widget.Widget.pos_hint`
|
|
.. |size_hint_x| replace:: :attr:`~kivy.uix.widget.Widget.size_hint_x`
|
|
.. |size_hint_y| replace:: :attr:`~kivy.uix.widget.Widget.size_hint_y`
|
|
.. |pos| replace:: :attr:`~kivy.uix.widget.Widget.pos`
|
|
.. |size| replace:: :attr:`~kivy.uix.widget.Widget.size`
|
|
.. |width| replace:: :attr:`~kivy.uix.widget.Widget.width`
|
|
.. |height| replace:: :attr:`~kivy.uix.widget.Widget.height`
|
|
.. |children| replace:: :attr:`~kivy.uix.widget.Widget.children`
|
|
.. |parent| replace:: :attr:`~kivy.uix.widget.Widget.parent`
|
|
.. |x| replace:: :attr:`~kivy.uix.widget.Widget.x`
|
|
.. |y| replace:: :attr:`~kivy.uix.widget.Widget.y`
|
|
.. |left| replace:: :attr:`~kivy.uix.widget.Widget.left`
|
|
.. |top| replace:: :attr:`~kivy.uix.widget.Widget.top`
|
|
.. |center_x| replace:: :attr:`~kivy.uix.widget.Widget.center_x`
|
|
.. |center_y| replace:: :attr:`~kivy.uix.widget.Widget.center_y`
|
|
.. |orientation| replace:: :attr:`~kivy.uix.boxlayout.BoxLayout.orientation`
|
|
.. |Widget| replace:: :class:`~kivy.uix.widget.Widget`
|
|
.. |Button| replace:: :class:`~kivy.uix.button.Button`
|
|
.. |Image| replace:: :class:`~kivy.uix.image.Image`
|
|
.. |Canvas| replace:: :class:`~kivy.graphics.Canvas`
|
|
.. |ListProperty| replace:: :class:`~kivy.properties.ListProperty`
|
|
.. |ObjectProperty| replace:: :class:`~kivy.properties.ObjectProperty`
|
|
.. |ReferenceListProperty| replace:: :class:`~kivy.properties.ReferenceListProperty`
|
|
.. |Layout| replace:: :mod:`~kivy.uix.layout`
|
|
.. |RelativeLayout| replace:: :mod:`~kivy.uix.relativelayout`
|
|
.. |BoxLayout| replace:: :mod:`~kivy.uix.boxlayout`
|
|
.. |FloatLayout| replace:: :mod:`~kivy.uix.floatlayout`
|
|
.. |GridLayout| replace:: :mod:`~kivy.uix.gridlayout`
|
|
.. |StackLayout| replace:: :mod:`~kivy.uix.stacklayout`
|
|
.. |AnchorLayout| replace:: :mod:`~kivy.uix.anchorlayout`
|
|
.. |add_widget| replace:: :meth:`~kivy.uix.widget.Widget.add_widget`
|
|
.. |remove_widget| replace:: :meth:`~kivy.uix.widget.Widget.remove_widget`
|
|
|
|
Introduction to Widget
|
|
----------------------
|
|
|
|
A |Widget| is the base building block of GUI interfaces in Kivy.
|
|
It provides a |Canvas| that can be used to draw on screen. It receives events
|
|
and reacts to them. For a in-depth explanation about the |Widget| class,
|
|
look at the module documentation.
|
|
|
|
Manipulating the Widget tree
|
|
----------------------------
|
|
|
|
Widgets in Kivy are organized in trees. Your
|
|
application has a `root widget`, which usually has |children| that can have
|
|
|children| of their own. Children of a widget are represented as the |children|
|
|
attribute, a Kivy |ListProperty|.
|
|
|
|
The widget tree can be manipulated with the following methods:
|
|
|
|
- :meth:`~kivy.uix.widget.Widget.add_widget`: add a widget as a child
|
|
- :meth:`~kivy.uix.widget.Widget.remove_widget`: remove a widget from the
|
|
children list
|
|
- :meth:`~kivy.uix.widget.Widget.clear_widgets`: remove all children from a
|
|
widget
|
|
|
|
For example, if you want to add a button inside a BoxLayout, you can do::
|
|
|
|
layout = BoxLayout(padding=10)
|
|
button = Button(text='My first button')
|
|
layout.add_widget(button)
|
|
|
|
The button is added to layout: the button's parent property will be set to layout;
|
|
the layout will have the button added to its children list. To remove the button
|
|
from the layout::
|
|
|
|
layout.remove_widget(button)
|
|
|
|
With removal, the button's parent property will be set to None, and the layout
|
|
will have button removed from its children list.
|
|
|
|
If you want to clear all the children inside a widget, use
|
|
:meth:`~kivy.uix.widget.Widget.clear_widgets` method::
|
|
|
|
layout.clear_widgets()
|
|
|
|
.. warning::
|
|
|
|
Never manipulate the children list yourself, unless you really know what you
|
|
are doing. The widget tree is associated with a graphic tree. For example, if you
|
|
add a widget into the children list without adding its canvas to the
|
|
graphics tree, the widget will be a child, yes, but nothing will be drawn
|
|
on the screen. Moreover, you might have issues on further calls of
|
|
add_widget, remove_widget and clear_widgets.
|
|
|
|
Traversing the Tree
|
|
-------------------
|
|
|
|
The Widget class instance's :data:`~kivy.uix.widget.Widget.children` list property
|
|
contains all the children. You can easily traverse the tree by doing::
|
|
|
|
root = BoxLayout()
|
|
# ... add widgets to root ...
|
|
for child in root.children:
|
|
print(child)
|
|
|
|
However, this must be used carefuly. If you intend to modify the children list
|
|
with one of the methods shown in the previous section, you must use a copy of
|
|
the list like this::
|
|
|
|
for child in root.children[:]:
|
|
# manipulate the tree. For example here, remove all widgets that have a
|
|
# width < 100
|
|
if child.width < 100:
|
|
root.remove_widget(child)
|
|
|
|
Widgets don't influence the size/pos of their children by default. The
|
|
|pos| attribute is the absolute position in screen co-ordinates (unless, you
|
|
use the |RelativeLayout|. More on that later) and |size|, is an absolute size.
|
|
|
|
Widgets Z Index
|
|
---------------
|
|
|
|
The order of drawing widgets is based on position in
|
|
the widget tree. The last widget's canvas is drawn last (on top of everything
|
|
else inside its parent). add_widget takes a `index` parameter::
|
|
|
|
root.add_widget(widget, index)
|
|
|
|
for setting the z-index.
|
|
|
|
Organize with Layouts
|
|
---------------------
|
|
|
|
|Layout| is a special kind of widget that controls the size and position of
|
|
its children. There are different kinds of layouts, allowing for different
|
|
automatic organization of their children. Layouts use |size_hint| and |pos_hint|
|
|
properties to determine the |size| and |pos| of their |children|.
|
|
|
|
**BoxLayout**:
|
|
Arranges widgets in an adjacent manner (either vertically or horizontally) manner,
|
|
to fill all the space. The size_hint property of children can be used to change
|
|
proportions allowed to each child, or set fixed size for some of them.
|
|
|
|
.. only:: html
|
|
|
|
.. image:: ../images/boxlayout.gif
|
|
:align: left
|
|
.. image:: ../images/gridlayout.gif
|
|
:align: right
|
|
.. image:: ../images/stacklayout.gif
|
|
:align: left
|
|
.. image:: ../images/anchorlayout.gif
|
|
:align: right
|
|
.. image:: ../images/floatlayout.gif
|
|
|
|
.. only:: latex
|
|
|
|
.. image:: ../images/boxlayout.png
|
|
.. image:: ../images/gridlayout.png
|
|
.. image:: ../images/stacklayout.png
|
|
.. image:: ../images/anchorlayout.png
|
|
.. image:: ../images/floatlayout.png
|
|
|
|
|
|
**GridLayout**:
|
|
Arranges widgets in a grid. You must specify at least one dimension of the
|
|
grid so kivy can compute the size of the elements and how to arrange them.
|
|
|
|
**StackLayout**:
|
|
Arranges widgets adjacent to one another, but with a set size in one of the
|
|
dimensions, without trying to make them fit within the entire space. This is
|
|
useful to display children of the same predefined size.
|
|
|
|
**AnchorLayout**:
|
|
A simple layout only caring about children positions. It allows putting the
|
|
children at a position relative to a border of the layout.
|
|
`size_hint` is not honored.
|
|
|
|
**FloatLayout**:
|
|
Allows placing children with arbitrary locations and size, either absolute or
|
|
relative to the layout size. Default size_hint (1, 1) will make every child
|
|
the same size as the whole layout, so you probably want to change this value
|
|
if you have more than one child. You can set size_hint to (None, None) to use
|
|
absolute size with `size`. This widget honors `pos_hint` also, which as a dict
|
|
setting position relative to layout position.
|
|
|
|
**RelativeLayout**:
|
|
Behaves just like FloatLayout, except children positions are relative to layout
|
|
position, not the screen.
|
|
|
|
Examine the documentation of the individaul layouts for a more in-depth
|
|
understanding.
|
|
|
|
|size_hint| and |pos_hint|:
|
|
|
|
- |FloatLayout|
|
|
- |BoxLayout|
|
|
- |GridLayout|
|
|
- |StackLayout|
|
|
- |RelativeLayout|
|
|
- |AnchorLayout|
|
|
|
|
|size_hint| is a |ReferenceListProperty| of
|
|
|size_hint_x| and |size_hint_y|. It excepts values from `0` to `1` or `None`
|
|
and defaults to `(1, 1)`. This signifies that if the widget is in a layout,
|
|
the layout will allocate it as much place as possible in both directions
|
|
(relative to the layouts size).
|
|
|
|
Setting |size_hint| to (0.5, 0.8), for example, will make the widget 50% the
|
|
width and 80% the height of available size for the |widget| inside a |layout|.
|
|
|
|
Consider the following example:
|
|
|
|
.. code-block:: kv
|
|
|
|
BoxLayout:
|
|
Button:
|
|
text: 'Button 1'
|
|
# default size_hint is 1, 1, we don't need to specify it explicitly
|
|
# however it's provided here to make things clear
|
|
size_hint: 1, 1
|
|
|
|
load kivy catalog::
|
|
|
|
cd $KIVYDIR/examples/demo/kivycatalog
|
|
python main.py
|
|
|
|
Replace $KIVYDIR with the directory of your installation of Kivy. Click on the
|
|
button labeled `Box Layout` from the left. Now paste the code from above into
|
|
the editor panel on the right.
|
|
|
|
.. image:: images/size_hint[B].jpg
|
|
|
|
As you can see from the image above, the `Button` takes up 100% of the layout
|
|
|size|.
|
|
|
|
Changing the |size_hint_x|/|size_hint_y| to .5 will make the |widget| take 50%
|
|
of the |layout| |width|/|height|.
|
|
|
|
.. image:: images/size_hint[b_].jpg
|
|
|
|
You can see here that, although we specify |size_hint_x| and |size_hint_y| both
|
|
to be .5, only |size_hint_x| seems to be honored. That is because |BoxLayout|
|
|
controls the |size_hint_y| when |orientation| is `vertical` and |size_hint_x|
|
|
when |orientation| is 'horizontal'. The controlled dimension's size is calculated depending
|
|
upon the total no. of |children| in the |BoxLayout|. In this example, one child has
|
|
|size_hint_y| controlled (.5/.5 = 1). Thus, the widget takes 100% of the parent
|
|
layout's height.
|
|
|
|
Let's add another |Button| to the |layout| and see what happens.
|
|
|
|
.. image:: images/size_hint[bb].jpg
|
|
|
|
|BoxLayout| by its very nature divides the available space between its
|
|
|children| equally. In our example, the proportion is 50-50, because we have two
|
|
|children|. Let's use size_hint on one of the children and see the results.
|
|
|
|
.. image:: images/size_hint[oB].jpg
|
|
|
|
If a child specifies |size_hint|, this specifies how much space the |Widget|
|
|
will take out of the |size| given to it by the |BoxLayout|. In our example, the
|
|
first |Button| specifies .5 for |size_hint_x|. The space for the widget is
|
|
calculated like so::
|
|
|
|
first child's size_hint devided by
|
|
first child's size_hint + second child's size_hint + ...n(no of children)
|
|
|
|
.5/(.5+1) = .333...
|
|
|
|
The rest of the BoxLayout's |width| is divided among the rest of the |children|.
|
|
In our example, this means the second |Button| takes up 66.66% of the |layout|
|
|
|width|.
|
|
|
|
Experiment with |size_hint| to get comfortable with it.
|
|
|
|
If you want to control the absolute |size| of a |Widget|, you can set
|
|
|size_hint_x|/|size_hint_y| or both to `None` so that the widget's |width| and or
|
|
|height| attributes will be honored.
|
|
|
|
|pos_hint| is a dict, which defaults to empty. As for |size_hint|, layouts honor
|
|
|pos_hint| differently, but generally you can add values to any of the |pos|
|
|
attributes (|x|, |y|, |left|, |top|, |center_x|, |center_y|) to have the
|
|
|Widget| positioned relative to its |parent|.
|
|
|
|
Let's experiment with the following code in kivycatalog to understand |pos_hint|
|
|
visually:
|
|
|
|
.. code-block:: kv
|
|
|
|
FloatLayout:
|
|
Button:
|
|
text: "We Will"
|
|
pos: 100, 100
|
|
size_hint: .2, .4
|
|
Button:
|
|
text: "Wee Wiill"
|
|
pos: 200, 200
|
|
size_hint: .4, .2
|
|
|
|
Button:
|
|
text: "ROCK YOU!!"
|
|
pos_hint: {'x': .3, 'y': .6}
|
|
size_hint: .5, .2
|
|
|
|
This gives us:
|
|
|
|
.. image:: images/pos_hint.jpg
|
|
|
|
As with |size_hint|, you should experiment with |pos_hint| to
|
|
understand the effect it has on the widget positions.
|
|
|
|
.. _adding_widget_background:
|
|
|
|
Adding a Background to a Layout
|
|
-------------------------------
|
|
|
|
One of the frequently asked questions about layouts is:::
|
|
|
|
"How to add a background image/color/video/... to a Layout"
|
|
|
|
Layouts by their nature have no visual representation: they have no canvas
|
|
instructions by default. However you can add canvas instructions to a layout
|
|
instance easily, as with adding a colored background:
|
|
|
|
In Python::
|
|
|
|
with layout_instance.canvas.before:
|
|
Color(rgba(0, 1, 0, 1)) # green; colors range from 0-1 instead of 0-255
|
|
self.rect = Rectangle(
|
|
size=layout_instance.size,
|
|
pos=layout_instance.pos)
|
|
|
|
Unfortunately, this will only draw a rectangle at the layout's initial position
|
|
and size. To make sure the rect is drawn inside the layout, when layout size/pos
|
|
changes, we need to listen to any changes and update the rectangle size and pos
|
|
like so::
|
|
|
|
# listen to size and position changes
|
|
layout_instance.bind(
|
|
size=self._update_rect,
|
|
pos=self._update_rect)
|
|
|
|
...
|
|
def _update_rect(self, instance, value):
|
|
self.rect.pos = instance.pos
|
|
self.rect.size = instance.size
|
|
|
|
In kv:
|
|
|
|
.. code-block:: kv
|
|
|
|
...
|
|
...
|
|
FloatLayout:
|
|
canvas.before:
|
|
Color:
|
|
rgba: 0, 1, 0, 1
|
|
Rectangle:
|
|
# self here refers to the widget i.e BoxLayout
|
|
pos: self.pos
|
|
size: self.size
|
|
|
|
The kv declaration sets an implicit binding: the last two kv lines ensure that
|
|
the |pos| and |size| values of the rectangle will update when the |pos| of the
|
|
|FloatLayout| changes.
|
|
|
|
Now we put the snippets above into the shell of Kivy App.
|
|
|
|
Pure Python way::
|
|
|
|
from kivy.app import App
|
|
from kivy.graphics import Color, Rectangle
|
|
from kivy.uix.floatlayout import FloatLayout
|
|
from kivy.uix.button import Button
|
|
|
|
|
|
class RootWidget(FloatLayout):
|
|
|
|
def __init__(self, **kwargs):
|
|
# make sure we aren't overriding any important functionality
|
|
super(RootWidget, self).__init__(**kwargs)
|
|
|
|
# let's add a Widget to this layout
|
|
self.add_widget(
|
|
Button(
|
|
text="Hello World",
|
|
size_hint= (.5, .5),
|
|
pos_hint={'center_x':.5,
|
|
'center_y':.5}))
|
|
|
|
|
|
class MainApp(App):
|
|
|
|
def build(self):
|
|
self.root = root = RootWidget()
|
|
root.bind(
|
|
size=self._update_rect,
|
|
pos=self._update_rect)
|
|
with root.canvas.before:
|
|
Color(0, 1, 0, 1) # green; colors range from 0-1 not 0-255
|
|
self.rect = Rectangle(
|
|
size=root.size,
|
|
pos=root.pos)
|
|
return root
|
|
|
|
def _update_rect(self, instance, value):
|
|
self.rect.pos = instance.pos
|
|
self.rect.size = instance.size
|
|
|
|
if __name__ == '__main__':
|
|
MainApp().run()
|
|
|
|
Using the kv Language::
|
|
|
|
from kivy.app import App
|
|
from kivy.lang import Builder
|
|
|
|
|
|
root = Builder.load_string('''
|
|
FloatLayout:
|
|
canvas.before:
|
|
Color:
|
|
rgba: 0, 1, 0, 1
|
|
Rectangle:
|
|
# self here refers to the widget i.e FloatLayout
|
|
pos: self.pos
|
|
size: self.size
|
|
Button:
|
|
text: 'Hello World!!'
|
|
size_hint: .5, .5
|
|
pos_hint: {'center_x':.5, 'center_y': .5}
|
|
''')
|
|
|
|
class MainApp(App):
|
|
|
|
def build(self):
|
|
return root
|
|
|
|
if __name__ == '__main__':
|
|
MainApp().run()
|
|
|
|
Both of the Apps should look something like this:
|
|
|
|
.. image:: images/layout_background.png
|
|
|
|
**To add a color to the background of a **custom layouts rule/class** **
|
|
|
|
The way we add background to the layout's instance can quickly become
|
|
cumbersome if we need to use multiple layouts. To help with this, override
|
|
the Layout class with your own layout, and add a background
|
|
within the class of the layout class itself.
|
|
|
|
Using Python::
|
|
|
|
from kivy.app import App
|
|
from kivy.graphics import Color, Rectangle
|
|
from kivy.uix.boxlayout import BoxLayout
|
|
from kivy.uix.floatlayout import FloatLayout
|
|
from kivy.uix.image import AsyncImage
|
|
from kivy.uix.button import Button
|
|
|
|
|
|
class RootWidget(BoxLayout):
|
|
pass
|
|
|
|
class CustomLayout(FloatLayout):
|
|
|
|
def __init__(self, **kwargs):
|
|
# make sure we aren't overriding any important functionality
|
|
super(CustomLayout, self).__init__(**kwargs)
|
|
|
|
with self.canvas.before:
|
|
Color(0, 1, 0, 1) # green; colors range from 0-1 instead of 0-255
|
|
self.rect = Rectangle(
|
|
size=self.size,
|
|
pos=self.pos)
|
|
|
|
self.bind(
|
|
size=self._update_rect,
|
|
pos=self._update_rect)
|
|
|
|
def _update_rect(self, instance, value):
|
|
self.rect.pos = instance.pos
|
|
self.rect.size = instance.size
|
|
|
|
|
|
class MainApp(App):
|
|
|
|
def build(self):
|
|
root = RootWidget()
|
|
c = CustomLayout()
|
|
root.add_widget(c)
|
|
c.add_widget(AsyncImage(source="http://www.everythingzoomer.com/wp-content/uploads/2013/01/Monday-joke-289x277.jpg",
|
|
size_hint= (1, .5),
|
|
pos_hint={'center_x':.5, 'center_y':.5}))
|
|
root.add_widget(AsyncImage(source='http://www.stuffistumbledupon.com/wp-content/uploads/2012/05/Have-you-seen-this-dog-because-its-awesome-meme-puppy-doggy.jpg'))
|
|
c = CustomLayout()
|
|
c.add_widget(AsyncImage(source="http://www.stuffistumbledupon.com/wp-content/uploads/2012/04/Get-a-Girlfriend-Meme-empty-wallet.jpg",
|
|
size_hint= (1, .5),
|
|
pos_hint={'center_x':.5, 'center_y':.5}))
|
|
root.add_widget(c)
|
|
return root
|
|
|
|
if __name__ == '__main__':
|
|
MainApp().run()
|
|
|
|
Using the kv Language::
|
|
|
|
from kivy.app import App
|
|
from kivy.uix.floatlayout import FloatLayout
|
|
from kivy.uix.boxlayout import BoxLayout
|
|
from kivy.lang import Builder
|
|
|
|
|
|
Builder.load_string('''
|
|
<CustomLayout>
|
|
canvas.before:
|
|
Color:
|
|
rgba: 0, 1, 0, 1
|
|
Rectangle:
|
|
pos: self.pos
|
|
size: self.size
|
|
|
|
<RootWidget>
|
|
CustomLayout:
|
|
AsyncImage:
|
|
source: 'http://www.everythingzoomer.com/wp-content/uploads/2013/01/Monday-joke-289x277.jpg'
|
|
size_hint: 1, .5
|
|
pos_hint: {'center_x':.5, 'center_y': .5}
|
|
AsyncImage:
|
|
source: 'http://www.stuffistumbledupon.com/wp-content/uploads/2012/05/Have-you-seen-this-dog-because-its-awesome-meme-puppy-doggy.jpg'
|
|
CustomLayout
|
|
AsyncImage:
|
|
source: 'http://www.stuffistumbledupon.com/wp-content/uploads/2012/04/Get-a-Girlfriend-Meme-empty-wallet.jpg'
|
|
size_hint: 1, .5
|
|
pos_hint: {'center_x':.5, 'center_y': .5}
|
|
''')
|
|
|
|
class RootWidget(BoxLayout):
|
|
pass
|
|
|
|
class CustomLayout(FloatLayout):
|
|
pass
|
|
|
|
class MainApp(App):
|
|
|
|
def build(self):
|
|
return RootWidget()
|
|
|
|
if __name__ == '__main__':
|
|
MainApp().run()
|
|
|
|
|
|
Both of the Apps should look something like this:
|
|
|
|
.. image:: images/custom_layout_background.png
|
|
|
|
Defining the background in the custom layout class, assures that it will be used
|
|
in every instance of CustomLayout.
|
|
|
|
Now, to add an image or color to the background of a built-in Kivy layout,
|
|
**globally**, we need to override the kv rule for the layout in question.
|
|
Consider GridLayout::
|
|
|
|
<GridLayout>
|
|
canvas.before:
|
|
Color:
|
|
rgba: 0, 1, 0, 1
|
|
BorderImage:
|
|
source: '../examples/widgets/sequenced_images/data/images/button_white.png'
|
|
pos: self.pos
|
|
size: self.size
|
|
|
|
Then, when we put this snippet into a Kivy app::
|
|
|
|
from kivy.app import App
|
|
from kivy.uix.floatlayout import FloatLayout
|
|
from kivy.lang import Builder
|
|
|
|
|
|
Builder.load_string('''
|
|
<GridLayout>
|
|
canvas.before:
|
|
BorderImage:
|
|
# BorderImage behaves like the CSS BorderImage
|
|
border: 10, 10, 10, 10
|
|
source: '../examples/widgets/sequenced_images/data/images/button_white.png'
|
|
pos: self.pos
|
|
size: self.size
|
|
|
|
<RootWidget>
|
|
GridLayout:
|
|
size_hint: .9, .9
|
|
pos_hint: {'center_x': .5, 'center_y': .5}
|
|
rows:1
|
|
Label:
|
|
text: "I don't suffer from insanity, I enjoy every minute of it"
|
|
text_size: self.width-20, self.height-20
|
|
valign: 'top'
|
|
Label:
|
|
text: "When I was born I was so surprised; I didn't speak for a year and a half."
|
|
text_size: self.width-20, self.height-20
|
|
valign: 'middle'
|
|
halign: 'center'
|
|
Label:
|
|
text: "A consultant is someone who takes a subject you understand and makes it sound confusing"
|
|
text_size: self.width-20, self.height-20
|
|
valign: 'bottom'
|
|
halign: 'justify'
|
|
''')
|
|
|
|
class RootWidget(FloatLayout):
|
|
pass
|
|
|
|
class MainApp(App):
|
|
|
|
def build(self):
|
|
return RootWidget()
|
|
|
|
if __name__ == '__main__':
|
|
MainApp().run()
|
|
|
|
The result should look something like this:
|
|
|
|
.. image:: images/global_background.png
|
|
|
|
As we are overriding the rule of the class GridLayout, any use of this
|
|
class in our app will display that image.
|
|
|
|
How about an **Animated background**?
|
|
|
|
You can set the drawing instructions like Rectangle/BorderImage/Ellipse/... to
|
|
use a particular texture::
|
|
|
|
Rectangle:
|
|
texture: reference to a texture
|
|
|
|
We use this to display an animated background::
|
|
|
|
from kivy.app import App
|
|
from kivy.uix.floatlayout import FloatLayout
|
|
from kivy.uix.gridlayout import GridLayout
|
|
from kivy.uix.image import Image
|
|
from kivy.properties import ObjectProperty
|
|
from kivy.lang import Builder
|
|
|
|
|
|
Builder.load_string('''
|
|
<CustomLayout>
|
|
canvas.before:
|
|
BorderImage:
|
|
# BorderImage behaves like the CSS BorderImage
|
|
border: 10, 10, 10, 10
|
|
texture: self.background_image.texture
|
|
pos: self.pos
|
|
size: self.size
|
|
|
|
<RootWidget>
|
|
CustomLayout:
|
|
size_hint: .9, .9
|
|
pos_hint: {'center_x': .5, 'center_y': .5}
|
|
rows:1
|
|
Label:
|
|
text: "I don't suffer from insanity, I enjoy every minute of it"
|
|
text_size: self.width-20, self.height-20
|
|
valign: 'top'
|
|
Label:
|
|
text: "When I was born I was so surprised; I didn't speak for a year and a half."
|
|
text_size: self.width-20, self.height-20
|
|
valign: 'middle'
|
|
halign: 'center'
|
|
Label:
|
|
text: "A consultant is someone who takes a subject you understand and makes it sound confusing"
|
|
text_size: self.width-20, self.height-20
|
|
valign: 'bottom'
|
|
halign: 'justify'
|
|
''')
|
|
|
|
class CustomLayout(GridLayout):
|
|
|
|
background_image = ObjectProperty(
|
|
Image(
|
|
source='../examples/widgets/sequenced_images/data/images/button_white_animated.zip',
|
|
anim_delay=.1))
|
|
|
|
class RootWidget(FloatLayout):
|
|
pass
|
|
|
|
class MainApp(App):
|
|
|
|
def build(self):
|
|
return RootWidget()
|
|
|
|
if __name__ == '__main__':
|
|
MainApp().run()
|
|
|
|
To try to understand what is happening here, start from line 13::
|
|
|
|
texture: self.background_image.texture
|
|
|
|
This specifies that the `texture` property of `BorderImage` will be updated
|
|
whenever the `texture` property of `background_inage` updates. We define the
|
|
background_image property at line 40::
|
|
|
|
background_image = ObjectProperty(...
|
|
|
|
This sets up `background_image` as an |ObjectProperty| in which we add an |Image|
|
|
widget. An image widget has a `texture` property; where you see
|
|
`self.background_image.texture`, this sets a reference, `texture`, to this property.
|
|
The |Image| widget supports animation: the texture of the image is updated whenever
|
|
the animation changes, and the texture of BorderImage instruction is updated in
|
|
the process.
|
|
|
|
You can also just blit custom data to the texture. For details, look at the
|
|
documention of :class:`~kivy.graphics.texture.Texture`.
|
|
|
|
Nesting Layouts
|
|
---------------
|
|
|
|
Yes! It is quite fun to see how extensible the process can be.
|
|
|
|
|
|
Size and position metrics
|
|
-------------------------
|
|
|
|
.. |Transitions| replace:: :class:`~kivy.uix.screenmanager.TransitionBase`
|
|
.. |ScreenManager| replace:: :class:`~kivy.uix.screenmanager.ScreenManager`
|
|
.. |Screen| replace:: :class:`~kivy.uix.screenmanager.Screen`
|
|
.. |screen| replace:: :mod:`~kivy.modules.screen`
|
|
.. |metrics| replace:: :mod:`~kivy.metrics`
|
|
.. |pt| replace:: :attr:`~kivy.metrics.pt`
|
|
.. |mm| replace:: :attr:`~kivy.metrics.mm`
|
|
.. |cm| replace:: :attr:`~kivy.metrics.cm`
|
|
.. |in| replace:: :attr:`~kivy.metrics.inch`
|
|
.. |dp| replace:: :attr:`~kivy.metrics.dp`
|
|
.. |sp| replace:: :attr:`~kivy.metrics.sp`
|
|
|
|
Kivy's default unit for length is the pixel, all sizes and positions are
|
|
expressed in it by default. You can express them in other units, which is
|
|
useful to achieve better consistency across devices (they get converted to the
|
|
size in pixels automatically).
|
|
|
|
Available units are |pt|, |mm|, |cm|, |in|, |dp| and |sp|. You can learn about
|
|
their usage in the |metrics| documentation.
|
|
|
|
You can also experiment with the |screen| usage to simulate various devices
|
|
screens for your application.
|
|
|
|
Screen Separation with Screen Manager
|
|
-------------------------------------
|
|
|
|
If your application is composed of various screens, you likely want an easy
|
|
way to navigate from one |Screen| to another. Fortunately, there is the
|
|
|ScreenManager| class, that allows you to define screens separately, and to set
|
|
the |Transitions| from one to another.
|