Merge pull request #1136 from Zen-CODE/Doc_English_Improvements_29

doc: revisions to /tutorials/firstwidget.rst
This commit is contained in:
qua-non 2013-04-23 09:45:19 -07:00
commit ebd6968881

View File

@ -3,11 +3,11 @@
.. highlight:: python .. highlight:: python
:linenothreshold: 3 :linenothreshold: 3
A simple Paint App A Simple Paint App
================== ==================
In the following you will be guided through the creation of your first In the following tutorial, you will be guided through the creation of your
widget. This provides very powerful and important knowledge when first widget. This provides powerful and important knowledge when
programming Kivy applications, as it lets you create completely new user programming Kivy applications, as it lets you create completely new user
interfaces with custom elements for your specific purpose. interfaces with custom elements for your specific purpose.
@ -15,19 +15,19 @@ interfaces with custom elements for your specific purpose.
Basic Considerations Basic Considerations
-------------------- --------------------
When creating an application, you have to ask yourself three main questions: When creating an application, you have to ask yourself three important questions:
* What data does my application process? * What data does my application process?
* How do I visually represent that data? * How do I visually represent that data?
* How does the user interact with that data? * How does the user interact with that data?
If you want to write a very simple line drawing application for example, you If you want to write a very simple line drawing application for example, you
most likely want the user to just draw on the screen with his fingers. most likely want the user to just draw on the screen with his/her fingers.
That's how the user *interacts* with your application. While doing so, That's how the user *interacts* with your application. While doing so,
your application would memorize the positions where the user's finger was, your application would memorize the positions where the user's finger were,
so that you can later draw lines between those positions. So the points so that you can later draw lines between those positions. So the points
where the fingers were would be your *data* and the lines that you draw where the fingers were would be your *data* and the lines that you draw
between these would be your *visual representation*. between them would be your *visual representation*.
In Kivy, an applications user interface is composed of Widgets. Everything In Kivy, an applications user interface is composed of Widgets. Everything
that you see on the screen is somehow drawn by a widget. Often you would that you see on the screen is somehow drawn by a widget. Often you would
@ -36,16 +36,18 @@ context, which is why widgets typically represent one specific instance
that answers the three questions above. A widget encapsulates data, that answers the three questions above. A widget encapsulates data,
defines the user's interaction with that data and draws its visual defines the user's interaction with that data and draws its visual
representation. representation.
You can then build anything from simple to complex user interfaces by You can build anything from simple to complex user interfaces by
nesting widgets. There are many widgets built in, such as buttons, sliders nesting widgets. There are many widgets built in, such as buttons, sliders
and other common stuff. In many cases, however, you need a custom widget and other common stuff. In many cases, however, you need a custom widget
that is beyond the scope of what is shipped with Kivy (e.g. a that is beyond the scope of what is shipped with Kivy (e.g. a
medical visualization widget). medical visualization widget).
So keep these three questions in mind when you design your widgets. Try to So keep these three questions in mind when you design your widgets. Try to
write them in a minimal and reusable manner (I.e. a widget does exactly write them in a minimal and reusable manner (i.e. a widget does exactly
what its supposed to do and nothing more. If you need more, write more what its supposed to do and nothing more. If you need more, write more
widgets or compose other widgets of smaller widgets). widgets or compose other widgets of smaller widgets. We try to adhere to the
`Single Responsibility Principle
<http://en.wikipedia.org/wiki/Single_responsibility_principle>`_).
Paint Widget Paint Widget
@ -74,13 +76,13 @@ Here is the basic code skeleton that we will need:
This is actually really simple. Save it as paint.py. This is actually really simple. Save it as paint.py.
If you run it, you should only see a black screen. If you run it, you should only see a black screen.
As you can see, instead of using a built-in widget such as Button (see As you can see, instead of using a built-in widget such as a Button (see
:ref:`quickstart`), we are going to write our own widget to do the drawing. :ref:`quickstart`), we are going to write our own widget to do the drawing.
We do that by creating a class that inherits from We do that by creating a class that inherits from
:class:`~kivy.uix.widget.Widget` (line 5-6) and although that class does nothing :class:`~kivy.uix.widget.Widget` (line 5-6) and although that class does nothing
yet, we can still treat it like a normal Kivy widget (line 11). yet, we can still treat it like a normal Kivy widget (line 11).
The ``if __name__ ...`` construct (line 14) is a Python mechanism that prevents The ``if __name__ ...`` construct (line 14) is a Python mechanism that prevents
you from executing the code in the if-statement when importing from that file, you from executing the code in the if-statement when importing from the file,
i.e. if you write ``import paint``, it won't do something unexpected but i.e. if you write ``import paint``, it won't do something unexpected but
just nicely provide the classes defined in the file. just nicely provide the classes defined in the file.
@ -88,11 +90,14 @@ just nicely provide the classes defined in the file.
.. note:: .. note::
You may be wondering why you have to import App and Widget separately, You may be wondering why you have to import App and Widget separately,
instead of doing something like ``from kivy import *``. While shorter, instead of doing something like ``from kivy import *``. While shorter,
this would have the disadvantage of cluttering your namespace and this would have the disadvantage of `polluting your namespace
making the start of the application potentially much slower. <http://en.wikipedia.org/wiki/Namespace_%28computer_science%29#Python>`_
It's also not as clear what your application uses. The way we do it is and make the start of the application potentially much slower.
It can also introduce ambiguity into class and variable naming,
so is generally frowned upon in the Python community. The way we do it is
faster and cleaner. faster and cleaner.
Adding Behaviour Adding Behaviour
~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~
@ -104,12 +109,12 @@ input. Change the code like so:
:literal: :literal:
This is just to show you how easy it is to react to user input. When a This is just to show how easy it is to react to user input. When a
:class:`~kivy.input.motionevent.MotionEvent` (i.e. a touch, click, etc.) occurs, :class:`~kivy.input.motionevent.MotionEvent` (i.e. a touch, click, etc.) occurs,
we simply print the information about the touch object to the console. we simply print the information about the touch object to the console.
You won't see anything on the screen, but if you observe the command-line from You won't see anything on the screen, but if you observe the command-line from
which you are running the program, you will see a message for every touch which you are running the program, you will see a message for every touch.
(initially). This also demonstrates that a widget does not always have to This also demonstrates that a widget does not have to
have a visual representation. have a visual representation.
Now that's not really an overwhelming user experience. Let's add some code Now that's not really an overwhelming user experience. Let's add some code
@ -135,9 +140,10 @@ How does it work?
* Line 9: You might have guessed it already: This sets the * Line 9: You might have guessed it already: This sets the
:class:`~kivy.graphics.context_instructions.Color` for successive :class:`~kivy.graphics.context_instructions.Color` for successive
drawing operations to yellow (default color format is RGB, so (1, 1, 0) is drawing operations to yellow (default color format is RGB, so (1, 1, 0) is
yellow). This is true until another color is set. Think of this as dipping yellow). This is true until another
your brushes in that color which you can then use to draw on a canvas :class:`~kivy.graphics.context_instructions.Color` is set.
until you dip the brushes into another color. Think of this as dipping your brushes in that color, which you can
then use to draw on a canvas until you dip the brushes into another color.
* Line 10: We specify the diameter for the circle that we are about to * Line 10: We specify the diameter for the circle that we are about to
draw. Using a variable for that is preferable since we need to refer draw. Using a variable for that is preferable since we need to refer
to that value multiple times and we don't want to have to change it to that value multiple times and we don't want to have to change it
@ -203,7 +209,7 @@ This is what has changed:
So far so good. This isn't exactly beautiful yet, though. It looks a bit So far so good. This isn't exactly beautiful yet, though. It looks a bit
like spaghetti bolognese. What about we give each touch its own color? like spaghetti bolognese. How about giving each touch its own color?
Great, let's do it: Great, let's do it:
.. include:: ../../../examples/guide/firstwidget/5_random_colors.py .. include:: ../../../examples/guide/firstwidget/5_random_colors.py
@ -219,9 +225,10 @@ Here are the changes:
* Line 10: In this case we simply create a new tuple of 3 random * Line 10: In this case we simply create a new tuple of 3 random
float values that will represent a random RGB color. Since we do float values that will represent a random RGB color. Since we do
this in ``on_touch_down``, every new touch will get its own color. this in ``on_touch_down``, every new touch will get its own color.
Don't get confused by the use of two ``=`` operators. We're just Don't get confused by the use of
binding the tuple to ``color`` as well as a shortcut for use within this `tuples <http://docs.python.org/2/tutorial/datastructures.html#tuples-and-sequences>`_.
method because we're lazy. We're just binding the tuple to ``color`` for use as a shortcut
within this method because we're lazy.
* Line 12: As before, we set the color for the canvas. Only this time * Line 12: As before, we set the color for the canvas. Only this time
we use the random values we generated and feed them to the color we use the random values we generated and feed them to the color
class using Python's tuple unpacking syntax (since the Color class class using Python's tuple unpacking syntax (since the Color class
@ -246,19 +253,18 @@ might even be able to create a nice little drawing!
Then, when passing it to the color instruction, set the mode to HSV Then, when passing it to the color instruction, set the mode to HSV
color space: ``Color(*color, mode='hsv')``. This way you will have a color space: ``Color(*color, mode='hsv')``. This way you will have a
smaller number of possible colors, but the colors that you get will smaller number of possible colors, but the colors that you get will
always be equally bright. Only the hue changes. always be equally bright: only the hue changes.
Bonus Points Bonus Points
~~~~~~~~~~~~ ~~~~~~~~~~~~
At this point, we could say we are done. The widget does what it's At this point, we could say we are done. The widget does what it's
supposed to do: It traces the touches and draws lines. It even still draws supposed to do: it traces the touches and draws lines. It even draws
circles at the positions where a line begins. circles at the positions where a line begins.
But what if the user wants to start a new drawing? With the current code, But what if the user wants to start a new drawing? With the current code,
the only option to clear the window would be to restart the entire the only way to clear the window would be to restart the entire application.
application.
Luckily, we can do better. Let us add a *Clear* button that erases all the Luckily, we can do better. Let us add a *Clear* button that erases all the
lines and circles that have been drawn so far. lines and circles that have been drawn so far.
There are two options now: There are two options now:
@ -270,8 +276,8 @@ There are two options now:
* Or we set up the button only once, initially, in our app class and * Or we set up the button only once, initially, in our app class and
when it's pressed we clear the widget. when it's pressed we clear the widget.
For our simple example, that doesn't really matter at all. For larger For our simple example, it doesn't really matter that much. For larger
applications you should give some thought to who does what in your code. applications you should give some thought to who does what in your app.
We'll go with the second option here so that you see how you can build up We'll go with the second option here so that you see how you can build up
your application's widget tree in your app class's :meth:`~kivy.app.App.build` your application's widget tree in your app class's :meth:`~kivy.app.App.build`
method. We'll also change to the HSV color space (see preceding note): method. We'll also change to the HSV color space (see preceding note):
@ -290,22 +296,23 @@ Here's what happens:
our painting widget and the button we're about to add. This is just our painting widget and the button we're about to add. This is just
a poor-man's approach to setting up a widget tree hierarchy. We a poor-man's approach to setting up a widget tree hierarchy. We
could just as well use a layout or do some other fancy stuff. could just as well use a layout or do some other fancy stuff.
Again: This widget does absolutely nothing except holding the two Again: this widget does absolutely nothing except holding the two
widgets we will now add to it as children. widgets we will now add to it as children.
* Line 26: We create our ``MyPaintWidget()`` as usual, only this time * Line 26: We create our ``MyPaintWidget()`` as usual, only this time
we don't return it directly but bind it to a variable name. we don't return it directly but bind it to a variable name.
* Line 27: We create a button widget. It will have a label on it that * Line 27: We create a button widget. It will have a label on it that
displays the text 'Clear'. displays the text 'Clear'.
* Line 28 & 29: We set up the widget hierarchy by making both the * Line 28 & 29: We set up the widget hierarchy by making both the
painter and the clear button children of the dummy parent widget. painter and the clearbtn children of the dummy parent widget.
That means painter and button are now siblings in the usual computer That means `painter` and `clearbtn` are now siblings in the usual computer
science tree terminology. science tree terminology.
* Lines 31 & 32: Up to now, the button did nothing. It was there, * Lines 31 & 32: Up to now, the button did nothing. It was there,
visible, and you could press it, but nothing would happen. visible, and you could press it, but nothing would happen.
We change that here: We create a small throw-away function that is We change that here: we create a small, throw-away function that is
going to be our callback function which is called when the button is going to be our
pressed. The function just clears the painter's canvas' contents, `callback function <http://en.wikipedia.org/wiki/Callback_function#Python>`_
making it black again. when the button is pressed. The function just clears the painter's
canvas' contents, making it black again.
* Line 33: We bind the button's on_release event (which is fired when * Line 33: We bind the button's on_release event (which is fired when
the button is pressed and then released) to the callback we just the button is pressed and then released) to the callback we just
defined. defined.