4
The :class:`Label` widget is for rendering text. It supports ascii and unicode
8
l = Label(text='Hello world')
10
# unicode text; can only display glyphs that are available in the font
11
l = Label(text=u'Hello world ' + unichr(2764))
14
l = Label(text='Multi\\nLine')
17
l = Label(text='Hello world', font_size='20sp')
19
.. _kivy-uix-label-sizing-and-text-content:
21
Sizing and text content
22
---------------------------
24
By default, the size of :class:`Label` is not affected by :attr:`~Label.text`
25
content and the text is not affected by the size. In order to control
26
sizing, you must specify :attr:`~Label.text_size` to constrain the text
27
and/or bind :attr:`~Label.size` to :attr:`~Label.texture_size` to grow with
30
For example, this label's size will be set to the text content
31
(plus :attr:`~Label.padding`):
33
.. code-block:: python
36
size: self.texture_size
38
This label's text will wrap at the specified width and be clipped to the height:
40
.. code-block:: python
43
text_size: cm(6), cm(4)
45
.. note:: The :attr:`~Label.shorten` and :attr:`~Label.max_lines` attributes
46
control how overflowing text behaves.
48
Combine these concepts to create a Label that can grow vertically but wraps the
49
text at a certain width:
51
.. code-block:: python
54
text_size: root.width, None
55
size: self.texture_size
57
Text alignment and wrapping
58
---------------------------
60
The :class:`Label` has :attr:`~Label.halign` and :attr:`~Label.valign`
61
properties to control the alignment of its text. However, by default the text
62
image (:attr:`~Label.texture`) is only just large enough to contain the
63
characters and is positioned in the center of the Label. The valign property
64
will have no effect and halign will only have an effect if your text has
65
newlines; a single line of text will appear to be centered even though halign is
66
set to left (by default).
68
In order for the alignment properties to take effect, set the
69
:attr:`~Label.text_size`, which specifies the size of the bounding box within
70
which text is aligned. For instance, the following code binds this size to the
71
size of the Label, so text will be aligned within the widget bounds. This
72
will also automatically wrap the text of the Label to remain within this area.
74
.. code-block:: python
84
.. versionadded:: 1.1.0
86
You can change the style of the text using :doc:`api-kivy.core.text.markup`.
87
The syntax is similar to the bbcode syntax but only the inline styling is
90
# hello world with world in bold
91
l = Label(text='Hello [b]World[/b]', markup=True)
93
# hello in red, world in blue
94
l = Label(text='[color=ff3333]Hello[/color][color=3333ff]World[/color]',
97
If you need to escape the markup from the current text, use
98
:func:`kivy.utils.escape_markup`::
100
text = 'This is an important message [1]'
101
l = Label(text='[b]' + escape_markup(text) + '[/b]', markup=True)
103
The following tags are available:
113
``[font=<str>][/font]``
115
``[size=<integer>][/size]``
117
``[color=#<color>][/color]``
118
Change the text color
119
``[ref=<str>][/ref]``
120
Add an interactive zone. The reference + bounding box inside the
121
reference will be available in :attr:`Label.refs`
123
Put an anchor in the text. You can get the position of your anchor within
124
the text with :attr:`Label.anchors`
126
Display the text at a subscript position relative to the text before it.
128
Display the text at a superscript position relative to the text before it.
130
If you want to render the markup text with a [ or ] or & character, you need to
131
escape them. We created a simple syntax::
139
"[size=24]Hello &bl;World&bt;[/size]"
141
Interactive zone in text
142
------------------------
144
.. versionadded:: 1.1.0
146
You can now have definable "links" using text markup. The idea is to be able
147
to detect when the user clicks on part of the text and to react.
148
The tag ``[ref=xxx]`` is used for that.
150
In this example, we are creating a reference on the word "World". When
151
this word is clicked, the function ``print_it`` will be called with the
152
name of the reference::
154
def print_it(instance, value):
155
print('User clicked on', value)
156
widget = Label(text='Hello [ref=world]World[/ref]', markup=True)
157
widget.bind(on_ref_press=print_it)
159
For prettier rendering, you could add a color for the reference. Replace the
160
``text=`` in the previous example with::
162
'Hello [ref=world][color=0000ff]World[/color][/ref]'
164
Catering for Unicode languages
165
------------------------------
167
The font kivy uses does not contain all the characters required for displaying
168
all languages. When you use the built-in widgets, this results in a block being
169
drawn where you expect a character.
171
If you want to display such characters, you can chose a font that supports them
172
and deploy it universally via kv:
177
-font_name: '/<path>/<to>/<font>'
179
Note that this needs to be done before your widgets are loaded as kv rules are
180
only applied at load time.
185
The following example marks the anchors and references contained in a label::
187
from kivy.app import App
188
from kivy.uix.label import Label
189
from kivy.clock import Clock
190
from kivy.graphics import Color, Rectangle
196
def get_x(label, ref_x):
197
""" Return the x value of the ref/anchor relative to the canvas """
198
return label.center_x - label.texture_size[0] * 0.5 + ref_x
201
def get_y(label, ref_y):
202
""" Return the y value of the ref/anchor relative to the canvas """
203
# Note the inversion of direction, as y values start at the top of
204
# the texture and increase downwards
205
return label.center_y + label.texture_size[1] * 0.5 - ref_y
207
def show_marks(self, label):
209
# Indicate the position of the anchors with a red top marker
210
for name, anc in label.anchors.items():
213
Rectangle(pos=(self.get_x(label, anc[0]),
214
self.get_y(label, anc[1])),
217
# Draw a green surround around the refs. Note the sizes y inversion
218
for name, boxes in label.refs.items():
222
Rectangle(pos=(self.get_x(label, box[0]),
223
self.get_y(label, box[1])),
224
size=(box[2] - box[0],
229
text='[anchor=a]a\\nChars [anchor=b]b\\n[ref=myref]ref[/ref]',
231
Clock.schedule_once(lambda dt: self.show_marks(label), 1)
238
__all__ = ('Label', )
240
from functools import partial
241
from kivy.clock import Clock
242
from kivy.uix.widget import Widget
243
from kivy.core.text import Label as CoreLabel
244
from kivy.core.text.markup import MarkupLabel as CoreMarkupLabel
245
from kivy.properties import StringProperty, OptionProperty, \
246
NumericProperty, BooleanProperty, ReferenceListProperty, \
247
ListProperty, ObjectProperty, DictProperty
248
from kivy.utils import get_hex_from_color
252
'''Label class, see module documentation for more information.
256
Fired when the user clicks on a word referenced with a
257
``[ref]`` tag in a text markup.
260
__events__ = ['on_ref_press']
262
_font_properties = ('text', 'font_size', 'font_name', 'bold', 'italic',
263
'underline', 'strikethrough',
264
'halign', 'valign', 'padding_x', 'padding_y',
265
'text_size', 'shorten', 'mipmap', 'markup',
266
'line_height', 'max_lines', 'strip', 'shorten_from',
267
'split_str', 'unicode_errors')
269
def __init__(self, **kwargs):
270
self._trigger_texture = Clock.create_trigger(self.texture_update, -1)
271
super(Label, self).__init__(**kwargs)
273
# bind all the property for recreating the texture
274
d = Label._font_properties
276
update = self._trigger_texture_update
283
fbind('markup', self._bind_for_markup)
285
self._bind_for_markup(self, self.markup)
287
# force the texture creation
288
self._trigger_texture()
290
def _bind_for_markup(self, inst, markup):
292
self.fbind('color', self._trigger_texture_update, 'color')
294
self.funbind('color', self._trigger_texture_update, 'color')
296
def _create_label(self):
297
# create the core label class according to markup value
298
if self._label is not None:
299
cls = self._label.__class__
303
if (markup and cls is not CoreMarkupLabel) or \
304
(not markup and cls is not CoreLabel):
305
# markup have change, we need to change our rendering method.
306
d = Label._font_properties
307
dkw = dict(list(zip(d, [getattr(self, x) for x in d])))
309
self._label = CoreMarkupLabel(**dkw)
311
self._label = CoreLabel(**dkw)
313
def _trigger_texture_update(self, name=None, source=None, value=None):
314
# check if the label core class need to be switch to a new one
319
self._label.text = value
320
elif name == 'text_size':
321
self._label.usersize = value
322
elif name == 'font_size':
323
self._label.options[name] = value
325
self._label.options[name] = value
326
self._trigger_texture()
328
def texture_update(self, *largs):
329
'''Force texture recreation with the current Label properties.
331
After this function call, the :attr:`texture` and :attr:`texture_size`
332
will be updated in this order.
334
mrkup = self._label.__class__ is CoreMarkupLabel
337
if (not self._label.text or (self.halign[-1] == 'y' or self.strip) and
338
not self._label.text.strip()):
339
self.texture_size = (0, 0)
341
self.refs, self._label._refs = {}, {}
342
self.anchors, self._label._anchors = {}, {}
346
# we must strip here, otherwise, if the last line is empty,
347
# markup will retain the last empty line since it only strips
348
# line by line within markup
349
if self.halign[-1] == 'y' or self.strip:
351
self._label.text = ''.join(('[color=',
352
get_hex_from_color(self.color),
353
']', text, '[/color]'))
354
self._label.refresh()
355
# force the rendering to get the references
356
if self._label.texture:
357
self._label.texture.bind()
358
self.refs = self._label.refs
359
self.anchors = self._label.anchors
361
self._label.refresh()
362
texture = self._label.texture
363
if texture is not None:
364
self.texture = self._label.texture
365
self.texture_size = list(self.texture.size)
367
def on_touch_down(self, touch):
368
if super(Label, self).on_touch_down(touch):
370
if not len(self.refs):
373
tx -= self.center_x - self.texture_size[0] / 2.
374
ty -= self.center_y - self.texture_size[1] / 2.
375
ty = self.texture_size[1] - ty
376
for uid, zones in self.refs.items():
379
if x <= tx <= w and y <= ty <= h:
380
self.dispatch('on_ref_press', uid)
384
def on_ref_press(self, ref):
391
disabled_color = ListProperty([1, 1, 1, .3])
392
'''Text color, in the format (r, g, b, a)
394
.. versionadded:: 1.8.0
396
:attr:`disabled_color` is a :class:`~kivy.properties.ListProperty` and
397
defaults to [1, 1, 1, .5].
400
text = StringProperty('')
401
'''Text of the label.
403
Creation of a simple hello world::
405
widget = Label(text='Hello world')
407
If you want to create the widget with an unicode string, use::
409
widget = Label(text=u'My unicode string')
411
:attr:`text` is a :class:`~kivy.properties.StringProperty` and defaults to
415
text_size = ListProperty([None, None])
416
'''By default, the label is not constrained to any bounding box.
417
You can set the size constraint of the label with this property.
418
The text will autoflow into the constrains. So although the font size
419
will not be reduced, the text will be arranged to fit into the box as best
420
as possible, with any text still outside the box clipped.
422
This sets and clips :attr:`texture_size` to text_size if not None.
424
.. versionadded:: 1.0.4
426
For example, whatever your current widget size is, if you want the label to
427
be created in a box with width=200 and unlimited height::
429
Label(text='Very big big line', text_size=(200, None))
433
This text_size property is the same as the
434
:attr:`~kivy.core.text.Label.usersize` property in the
435
:class:`~kivy.core.text.Label` class. (It is named size= in the
438
:attr:`text_size` is a :class:`~kivy.properties.ListProperty` and
439
defaults to (None, None), meaning no size restriction by default.
442
font_name = StringProperty('Roboto')
443
'''Filename of the font to use. The path can be absolute or relative.
444
Relative paths are resolved by the :func:`~kivy.resources.resource_find`
449
Depending of your text provider, the font file can be ignored. However,
450
you can mostly use this without problems.
452
If the font used lacks the glyphs for the particular language/symbols
453
you are using, you will see '[]' blank box characters instead of the
454
actual glyphs. The solution is to use a font that has the glyphs you
455
need to display. For example, to display |unicodechar|, use a font such
456
as freesans.ttf that has the glyph.
458
.. |unicodechar| image:: images/unicode-char.png
460
:attr:`font_name` is a :class:`~kivy.properties.StringProperty` and
461
defaults to 'Roboto'.
464
font_size = NumericProperty('15sp')
465
'''Font size of the text, in pixels.
467
:attr:`font_size` is a :class:`~kivy.properties.NumericProperty` and
471
line_height = NumericProperty(1.0)
472
'''Line Height for the text. e.g. line_height = 2 will cause the spacing
473
between lines to be twice the size.
475
:attr:`line_height` is a :class:`~kivy.properties.NumericProperty` and
478
.. versionadded:: 1.5.0
481
bold = BooleanProperty(False)
482
'''Indicates use of the bold version of your font.
486
Depending of your font, the bold attribute may have no impact on your
489
:attr:`bold` is a :class:`~kivy.properties.BooleanProperty` and defaults to
493
italic = BooleanProperty(False)
494
'''Indicates use of the italic version of your font.
498
Depending of your font, the italic attribute may have no impact on your
501
:attr:`italic` is a :class:`~kivy.properties.BooleanProperty` and defaults
505
underline = BooleanProperty(False)
506
'''Adds an underline to the text.
509
This feature requires a SDL2 window provider.
511
.. versionadded:: 1.9.2
513
:attr:`underline` is a :class:`~kivy.properties.BooleanProperty` and defaults
517
strikethrough = BooleanProperty(False)
518
'''Adds a strikethrough line to the text.
521
This feature requires a SDL2 window provider.
523
.. versionadded:: 1.9.2
525
:attr:`strikethrough` is a :class:`~kivy.properties.BooleanProperty` and defaults
529
padding_x = NumericProperty(0)
530
'''Horizontal padding of the text inside the widget box.
532
:attr:`padding_x` is a :class:`~kivy.properties.NumericProperty` and
535
.. versionchanged:: 1.9.0
536
`padding_x` has been fixed to work as expected.
537
In the past, the text was padded by the negative of its values.
540
padding_y = NumericProperty(0)
541
'''Vertical padding of the text inside the widget box.
543
:attr:`padding_y` is a :class:`~kivy.properties.NumericProperty` and
546
.. versionchanged:: 1.9.0
547
`padding_y` has been fixed to work as expected.
548
In the past, the text was padded by the negative of its values.
551
padding = ReferenceListProperty(padding_x, padding_y)
552
'''Padding of the text in the format (padding_x, padding_y)
554
:attr:`padding` is a :class:`~kivy.properties.ReferenceListProperty` of
555
(:attr:`padding_x`, :attr:`padding_y`) properties.
558
halign = OptionProperty('left', options=['left', 'center', 'right',
560
'''Horizontal alignment of the text.
562
:attr:`halign` is an :class:`~kivy.properties.OptionProperty` and
563
defaults to 'left'. Available options are : left, center, right and
568
This doesn't change the position of the text texture of the Label
569
(centered), only the position of the text in this texture. You probably
570
want to bind the size of the Label to the :attr:`texture_size` or set a
573
.. versionchanged:: 1.6.0
574
A new option was added to :attr:`halign`, namely `justify`.
577
valign = OptionProperty('bottom', options=['bottom', 'middle', 'top'])
578
'''Vertical alignment of the text.
580
:attr:`valign` is an :class:`~kivy.properties.OptionProperty` and defaults
581
to 'bottom'. Available options are : bottom, middle and top.
585
This doesn't change the position of the text texture of the Label
586
(centered), only the position of the text within this texture. You
587
probably want to bind the size of the Label to the :attr:`texture_size`
588
or set a :attr:`text_size` to change this behavior.
591
color = ListProperty([1, 1, 1, 1])
592
'''Text color, in the format (r, g, b, a)
594
:attr:`color` is a :class:`~kivy.properties.ListProperty` and defaults to
598
texture = ObjectProperty(None, allownone=True)
599
'''Texture object of the text.
600
The text is rendered automatically when a property changes. The OpenGL
601
texture created in this operation is stored in this property. You can use
602
this :attr:`texture` for any graphics elements.
604
Depending on the texture creation, the value will be a
605
:class:`~kivy.graphics.texture.Texture` or
606
:class:`~kivy.graphics.texture.TextureRegion` object.
610
The :attr:`texture` update is scheduled for the next frame. If you need
611
the texture immediately after changing a property, you have to call
612
the :meth:`texture_update` method before accessing :attr:`texture`::
614
l = Label(text='Hello world')
617
# l.texture is not updated yet
619
# l.texture is good now.
621
:attr:`texture` is an :class:`~kivy.properties.ObjectProperty` and defaults
625
texture_size = ListProperty([0, 0])
626
'''Texture size of the text. The size is determined by the font size and
627
text. If :attr:`text_size` is [None, None], the texture will be the size
628
required to fit the text, otherwise it's clipped to fit :attr:`text_size`.
630
When :attr:`text_size` is [None, None], one can bind to texture_size
631
and rescale it proportionally to fit the size of the label in order to
632
make the text fit maximally in the label.
636
The :attr:`texture_size` is set after the :attr:`texture`
637
property. If you listen for changes to :attr:`texture`,
638
:attr:`texture_size` will not be up-to-date in your callback.
639
Bind to :attr:`texture_size` instead.
642
mipmap = BooleanProperty(False)
643
'''Indicates whether OpenGL mipmapping is applied to the texture or not.
644
Read :ref:`mipmap` for more information.
646
.. versionadded:: 1.0.7
648
:attr:`mipmap` is a :class:`~kivy.properties.BooleanProperty` and defaults
652
shorten = BooleanProperty(False)
654
Indicates whether the label should attempt to shorten its textual contents
655
as much as possible if a :attr:`text_size` is given. Setting this to True
656
without an appropriately set :attr:`text_size` will lead to unexpected
659
:attr:`shorten_from` and :attr:`split_str` control the direction from
660
which the :attr:`text` is split, as well as where in the :attr:`text` we
661
are allowed to split.
663
:attr:`shorten` is a :class:`~kivy.properties.BooleanProperty` and defaults
667
shorten_from = OptionProperty('center', options=['left', 'center',
669
'''The side from which we should shorten the text from, can be left,
672
For example, if left, the ellipsis will appear towards the left side and we
673
will display as much text starting from the right as possible. Similar to
674
:attr:`shorten`, this option only applies when :attr:`text_size` [0] is
675
not None, In this case, the string is shortened to fit within the specified
678
.. versionadded:: 1.9.0
680
:attr:`shorten_from` is a :class:`~kivy.properties.OptionProperty` and
681
defaults to `center`.
684
split_str = StringProperty('')
685
'''The string used to split the :attr:`text` while shortening the string
686
when :attr:`shorten` is True.
688
For example, if it's a space, the string will be broken into words and as
689
many whole words that can fit into a single line will be displayed. If
690
:attr:`shorten_from` is the empty string, `''`, we split on every character
691
fitting as much text as possible into the line.
693
.. versionadded:: 1.9.0
695
:attr:`split_str` is a :class:`~kivy.properties.StringProperty` and
696
defaults to `''` (the empty string).
699
unicode_errors = OptionProperty(
700
'replace', options=('strict', 'replace', 'ignore'))
701
'''How to handle unicode decode errors. Can be `'strict'`, `'replace'` or
704
.. versionadded:: 1.9.0
706
:attr:`unicode_errors` is an :class:`~kivy.properties.OptionProperty` and
707
defaults to `'replace'`.
710
markup = BooleanProperty(False)
712
.. versionadded:: 1.1.0
714
If True, the text will be rendered using the
715
:class:`~kivy.core.text.markup.MarkupLabel`: you can change the
716
style of the text using tags. Check the
717
:doc:`api-kivy.core.text.markup` documentation for more information.
719
:attr:`markup` is a :class:`~kivy.properties.BooleanProperty` and defaults
723
refs = DictProperty({})
725
.. versionadded:: 1.1.0
727
List of ``[ref=xxx]`` markup items in the text with the bounding box of
728
all the words contained in a ref, available only after rendering.
730
For example, if you wrote::
732
Check out my [ref=hello]link[/ref]
734
The refs will be set with::
736
{'hello': ((64, 0, 78, 16), )}
738
The references marked "hello" have a bounding box at (x1, y1, x2, y2).
739
These co-ordinates are relative to the top left corner of the text, with
740
the y value increasing downwards. You can define multiple refs with the same
741
name: each occurence will be added as another (x1, y1, x2, y2) tuple to
744
The current Label implementation uses these references if they exist in
745
your markup text, automatically doing the collision with the touch and
746
dispatching an `on_ref_press` event.
748
You can bind a ref event like this::
750
def print_it(instance, value):
751
print('User click on', value)
752
widget = Label(text='Hello [ref=world]World[/ref]', markup=True)
753
widget.on_ref_press(print_it)
757
This works only with markup text. You need :attr:`markup` set to
761
anchors = DictProperty({})
763
.. versionadded:: 1.1.0
765
Position of all the ``[anchor=xxx]`` markup in the text.
766
These co-ordinates are relative to the top left corner of the text, with
767
the y value increasing downwards. Anchors names should be unique and only
768
the first occurence of any duplicate anchors will be recorded.
771
You can place anchors in your markup text as follows::
774
[anchor=title1][size=24]This is my Big title.[/size]
775
[anchor=content]Hello world
778
Then, all the ``[anchor=]`` references will be removed and you'll get all
779
the anchor positions in this property (only after rendering)::
781
>>> widget = Label(text=text, markup=True)
782
>>> widget.texture_update()
784
{"content": (20, 32), "title1": (20, 16)}
788
This works only with markup text. You need :attr:`markup` set to
793
max_lines = NumericProperty(0)
794
'''Maximum number of lines to use, defaults to 0, which means unlimited.
795
Please note that :attr:`shorten` take over this property. (with
796
shorten, the text is always one line.)
798
.. versionadded:: 1.8.0
800
:attr:`max_lines` is a :class:`~kivy.properties.NumericProperty` and
804
strip = BooleanProperty(False)
805
'''Whether leading and trailing spaces and newlines should be stripped from
806
each displayed line. If True, every line will start at the right or left
807
edge, depending on :attr:`halign`. If :attr:`halign` is `justify` it is
810
.. versionadded:: 1.9.0
812
:attr:`strip` is a :class:`~kivy.properties.BooleanProperty` and