Table Of Contents
- Compound Selection Behavior
- Compound selection concepts
- Selection mechanics
- Example
CompoundSelectionBehavior
CompoundSelectionBehavior.clear_selection()
CompoundSelectionBehavior.deselect_node()
CompoundSelectionBehavior.get_index_of_node()
CompoundSelectionBehavior.get_selectable_nodes()
CompoundSelectionBehavior.goto_node()
CompoundSelectionBehavior.keyboard_select
CompoundSelectionBehavior.multiselect
CompoundSelectionBehavior.nodes_order_reversed
CompoundSelectionBehavior.page_count
CompoundSelectionBehavior.right_count
CompoundSelectionBehavior.scroll_count
CompoundSelectionBehavior.select_node()
CompoundSelectionBehavior.select_with_key_down()
CompoundSelectionBehavior.select_with_key_up()
CompoundSelectionBehavior.select_with_touch()
CompoundSelectionBehavior.selected_nodes
CompoundSelectionBehavior.text_entry_timeout
CompoundSelectionBehavior.touch_deselect_last
CompoundSelectionBehavior.touch_multiselect
CompoundSelectionBehavior.up_count
Compound Selection Behavior¶
The CompoundSelectionBehavior
mixin class implements the logic
behind keyboard and touch selection of selectable widgets managed by the
derived widget. For example, it can be combined with a
GridLayout
to add selection to the layout.
Compound selection concepts¶
At its core, it keeps a dynamic list of widgets that can be selected. Then, as the touches and keyboard input are passed in, it selects one or more of the widgets based on these inputs. For example, it uses the mouse scroll and keyboard up/down buttons to scroll through the list of widgets. Multiselection can also be achieved using the keyboard shift and ctrl keys.
Finally, in addition to the up/down type keyboard inputs, compound selection can also accept letters from the keyboard to be used to select nodes with associated strings that start with those letters, similar to how files are selected by a file browser.
Selection mechanics¶
When the controller needs to select a node, it calls select_node()
and
deselect_node()
. Therefore, they must be overwritten in order alter
node selection. By default, the class doesn’t listen for keyboard or
touch events, so the derived widget must call
select_with_touch()
, select_with_key_down()
, and
select_with_key_up()
on events that it wants to pass on for selection
purposes.
Example¶
To add selection to a grid layout which will contain
Button
widgets. For each button added to the layout, you
need to bind the on_touch_down
of the button
to select_with_touch()
to pass on the touch events:
from kivy.uix.behaviors.compoundselection import CompoundSelectionBehavior
from kivy.uix.button import Button
from kivy.uix.gridlayout import GridLayout
from kivy.uix.behaviors import FocusBehavior
from kivy.core.window import Window
from kivy.app import App
class SelectableGrid(FocusBehavior, CompoundSelectionBehavior, GridLayout):
def keyboard_on_key_down(self, window, keycode, text, modifiers):
"""Based on FocusBehavior that provides automatic keyboard
access, key presses will be used to select children.
"""
if super(SelectableGrid, self).keyboard_on_key_down(
window, keycode, text, modifiers):
return True
if self.select_with_key_down(window, keycode, text, modifiers):
return True
return False
def keyboard_on_key_up(self, window, keycode):
"""Based on FocusBehavior that provides automatic keyboard
access, key release will be used to select children.
"""
if super(SelectableGrid, self).keyboard_on_key_up(window, keycode):
return True
if self.select_with_key_up(window, keycode):
return True
return False
def add_widget(self, widget, *args, **kwargs):
""" Override the adding of widgets so we can bind and catch their
*on_touch_down* events. """
widget.bind(on_touch_down=self.button_touch_down,
on_touch_up=self.button_touch_up)
return super(SelectableGrid, self) .add_widget(widget, *args, **kwargs)
def button_touch_down(self, button, touch):
""" Use collision detection to select buttons when the touch occurs
within their area. """
if button.collide_point(*touch.pos):
self.select_with_touch(button, touch)
def button_touch_up(self, button, touch):
""" Use collision detection to de-select buttons when the touch
occurs outside their area and *touch_multiselect* is not True. """
if not (button.collide_point(*touch.pos) or
self.touch_multiselect):
self.deselect_node(button)
def select_node(self, node):
node.background_color = (1, 0, 0, 1)
return super(SelectableGrid, self).select_node(node)
def deselect_node(self, node):
node.background_color = (1, 1, 1, 1)
super(SelectableGrid, self).deselect_node(node)
def on_selected_nodes(self, grid, nodes):
print("Selected nodes = {0}".format(nodes))
class TestApp(App):
def build(self):
grid = SelectableGrid(cols=3, rows=2, touch_multiselect=True,
multiselect=True)
for i in range(0, 6):
grid.add_widget(Button(text="Button {0}".format(i)))
return grid
TestApp().run()
Warning
This code is still experimental, and its API is subject to change in a future version.
- class kivy.uix.behaviors.compoundselection.CompoundSelectionBehavior(**kwargs)[source]¶
Bases:
builtins.object
The Selection behavior mixin implements the logic behind keyboard and touch selection of selectable widgets managed by the derived widget. Please see the
compound selection behaviors module
documentation for more information.New in version 1.9.0.
- deselect_node(node)[source]¶
Deselects a possibly selected node.
It is called by the controller when it deselects a node and can also be called from the outside to deselect a node directly. The derived widget should overwrite this method and change the node to its unselected state when this is called
- Parameters:
- node
The node to be deselected.
Warning
This method must be called by the derived widget using super if it is overwritten.
- get_index_of_node(node, selectable_nodes)[source]¶
(internal) Returns the index of the node within the selectable_nodes returned by
get_selectable_nodes()
.
- get_selectable_nodes()[source]¶
(internal) Returns a list of the nodes that can be selected. It can be overwritten by the derived widget to return the correct list.
This list is used to determine which nodes to select with group selection. E.g. the last element in the list will be selected when home is pressed, pagedown will move (or add to, if shift is held) the selection from the current position by negative
page_count
nodes starting from the position of the currently selected node in this list and so on. Still, nodes can be selected even if they are not in this list.Note
It is safe to dynamically change this list including removing, adding, or re-arranging its elements. Nodes can be selected even if they are not on this list. And selected nodes removed from the list will remain selected until
deselect_node()
is called.Warning
Layouts display their children in the reverse order. That is, the contents of
children
is displayed form right to left, bottom to top. Therefore, internally, the indices of the elements returned by this function are reversed to make it work by default for most layouts so that the final result is consistent e.g. home, although it will select the last element in this list visually, will select the first element when counting from top to bottom and left to right. If this behavior is not desired, a reversed list should be returned instead.Defaults to returning
children
.
- goto_node(key, last_node, last_node_idx)[source]¶
(internal) Used by the controller to get the node at the position indicated by key. The key can be keyboard inputs, e.g. pageup, or scroll inputs from the mouse scroll wheel, e.g. scrollup. ‘last_node’ is the last node selected and is used to find the resulting node. For example, if the key is up, the returned node is one node up from the last node.
It can be overwritten by the derived widget.
- Parameters:
- key
str, the string used to find the desired node. It can be any of the keyboard keys, as well as the mouse scrollup, scrolldown, scrollright, and scrollleft strings. If letters are typed in quick succession, the letters will be combined before it’s passed in as key and can be used to find nodes that have an associated string that starts with those letters.
- last_node
The last node that was selected.
- last_node_idx
The cached index of the last node selected in the
get_selectable_nodes()
list. If the list hasn’t changed it saves having to look up the index of last_node in that list.
- Returns:
tuple, the node targeted by key and its index in the
get_selectable_nodes()
list. Returning (last_node, last_node_idx) indicates a node wasn’t found.
- keyboard_select¶
Determines whether the keyboard can be used for selection. If False, keyboard inputs will be ignored.
keyboard_select
is aBooleanProperty
and defaults to True.
- multiselect¶
Determines whether multiple nodes can be selected. If enabled, keyboard shift and ctrl selection, optionally combined with touch, for example, will be able to select multiple widgets in the normally expected manner. This dominates
touch_multiselect
when False.multiselect
is aBooleanProperty
and defaults to False.
- nodes_order_reversed¶
(Internal) Indicates whether the order of the nodes as displayed top- down is reversed compared to their order in
get_selectable_nodes()
(e.g. how the children property is reversed compared to how it’s displayed).
- page_count¶
Determines by how much the selected node is moved up or down, relative to the position of the last selected node, when pageup (or pagedown) is pressed.
page_count
is aNumericProperty
and defaults to 10.
- right_count¶
Determines by how much the selected node is moved up or down, relative to the position of the last selected node, when the right (or left) arrow on the keyboard is pressed.
right_count
is aNumericProperty
and defaults to 1.
- scroll_count¶
Determines by how much the selected node is moved up or down, relative to the position of the last selected node, when the mouse scroll wheel is scrolled.
right_count
is aNumericProperty
and defaults to 0.
- select_node(node)[source]¶
Selects a node.
It is called by the controller when it selects a node and can be called from the outside to select a node directly. The derived widget should overwrite this method and change the node state to selected when called.
- Parameters:
- node
The node to be selected.
- Returns:
bool, True if the node was selected, False otherwise.
Warning
This method must be called by the derived widget using super if it is overwritten.
- select_with_key_down(keyboard, scancode, codepoint, modifiers, **kwargs)[source]¶
Processes a key press. This is called when a key press is to be used for selection. Depending on the keyboard keys pressed and the configuration, it could select or deselect nodes or node ranges from the selectable nodes list,
get_selectable_nodes()
.The parameters are such that it could be bound directly to the on_key_down event of a keyboard. Therefore, it is safe to be called repeatedly when the key is held down as is done by the keyboard.
- Returns:
bool, True if the keypress was used, False otherwise.
- select_with_key_up(keyboard, scancode, **kwargs)[source]¶
(internal) Processes a key release. This must be called by the derived widget when a key that
select_with_key_down()
returned True is released.The parameters are such that it could be bound directly to the on_key_up event of a keyboard.
- Returns:
bool, True if the key release was used, False otherwise.
- select_with_touch(node, touch=None)[source]¶
(internal) Processes a touch on the node. This should be called by the derived widget when a node is touched and is to be used for selection. Depending on the keyboard keys pressed and the configuration, it could select or deslect this and other nodes in the selectable nodes list,
get_selectable_nodes()
.- Parameters:
- node
The node that received the touch. Can be None for a scroll type touch.
- touch
Optionally, the touch. Defaults to None.
- Returns:
bool, True if the touch was used, False otherwise.
- selected_nodes¶
The list of selected nodes.
Note
Multiple nodes can be selected right after one another e.g. using the keyboard. When listening to
selected_nodes
, one should be aware of this.selected_nodes
is aListProperty
and defaults to the empty list, []. It is read-only and should not be modified.
- text_entry_timeout¶
When typing characters in rapid succession (i.e. the time difference since the last character is less than
text_entry_timeout
), the keys get concatenated and the combined text is passed as the key argument ofgoto_node()
.New in version 1.10.0.
- touch_deselect_last¶
Determines whether the last selected node can be deselected when
multiselect
ortouch_multiselect
is False.New in version 1.10.0.
touch_deselect_last
is aBooleanProperty
and defaults to True on mobile, False on desktop platforms.
- touch_multiselect¶
A special touch mode which determines whether touch events, as processed by
select_with_touch()
, will add the currently touched node to the selection, or if it will clear the selection before adding the node. This allows the selection of multiple nodes by simply touching them.This is different from
multiselect
because when it is True, simply touching an unselected node will select it, even if ctrl is not pressed. If it is False, however, ctrl must be pressed in order to add to the selection whenmultiselect
is True.Note
multiselect
, when False, will disabletouch_multiselect
.touch_multiselect
is aBooleanProperty
and defaults to False.
- up_count¶
Determines by how much the selected node is moved up or down, relative to the position of the last selected node, when the up (or down) arrow on the keyboard is pressed.
up_count
is aNumericProperty
and defaults to 1.