复合选择行为

: CompoundSelectionBehavior 混合类(mixin)实现了由派生控件管理的可选控件的键盘和触摸选择逻辑。例如,它可以与 GridLayout 结合使用,为布局添加选择功能。

复合选择概念

其核心功能是维护一个可选择的动态控件列表。当触摸和键盘输入传入时,它会根据这些输入选择一个或多个控件。例如,它利用鼠标滚轮和键盘上下键来滚动浏览控件列表。同时,通过键盘的Shift和Ctrl键也可以实现多选功能。

最后,除了上/下类型的键盘输入外,复合选择还可以接受来自键盘的字母,用于选择具有以这些字母开头的关联字符串的节点,类似于文件浏览器选择文件的方式。

选择机制

当控制器需要选择节点时,它会调用 select_node()deselect_node()。因此,为了改变节点选择行为,必须重写这些方法。默认情况下,该类不监听键盘或触摸事件,因此派生的小部件必须在其希望传递用于选择目的的事件上调用 select_with_touch()select_with_key_down()select_with_key_up()

示例

要向包含 Button 部件的网格布局添加选择功能,对于添加到布局中的每个按钮,你需要将按钮的 on_touch_down 绑定到 select_with_touch(),以传递触摸事件:

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()

警告

此代码仍处于实验阶段,其API在未来的版本中可能会有所变动。

class kivy.uix.behaviors.compoundselection.CompoundSelectionBehavior(**kwargs)[源代码]

基类:object

选择行为 mixin 实现了由派生控件管理的可选中控件的键盘和触摸选择逻辑。有关更多信息,请参阅 复合选择行为模块 的文档。

在 1.9.0 版本加入.

clear_selection()[源代码]

取消选择当前所有已选中的节点。

deselect_node(node)[源代码]

取消选中可能已选中的节点。

当控制器取消选择一个节点时,会调用此方法;也可以从外部直接调用以取消选择节点。派生的小部件应重写此方法,并在调用时将节点更改为其未选中状态。

参数:
节点

要取消选择的节点。

警告

如果该方法被覆盖,派生控件必须使用super调用它。

get_index_of_node(node, selectable_nodes)[源代码]

(内部)返回 nodeget_selectable_nodes() 返回的 selectable_nodes 中的索引。

get_selectable_nodes()[源代码]

(内部)返回可被选择的节点列表。派生控件可覆盖此方法以返回正确的列表。

该列表用于确定在组选择时要选中哪些节点。例如,当按下Home键时,将选中列表中的最后一个元素;按下PageDown键时,将从当前选中节点在此列表中的位置开始,按负的 page_count 节点数移动(若按住Shift键,则添加)选择范围,依此类推。尽管如此,即使节点不在此列表中,它们仍可被选中。

备注

动态修改此列表是安全的,包括移除、添加或重新排列其元素。即使节点不在列表中,也可以被选中。从列表中移除的已选中节点将保持选中状态,直到调用 deselect_node() 方法。

警告

布局会以相反的顺序显示其子组件。也就是说,children 的内容是从右到左、从下到上显示的。因此,在内部,此函数返回的元素索引会被反转,以便默认情况下适用于大多数布局,从而使最终结果保持一致,例如,home 虽然在视觉上会选择此列表中的最后一个元素,但在从上到下、从左到右计数时会选择第一个元素。如果不需要此行为,则应返回一个反转后的列表。

默认返回 children

goto_node(key, last_node, last_node_idx)[源代码]

(内部)控制器使用此方法获取由键指示的位置处的节点。键可以是键盘输入,例如 pageup,或鼠标滚轮的滚动输入,例如 scrollup。'last_node' 是最后选中的节点,用于查找结果节点。例如,如果键是向上,则返回的节点是最后一个节点上方的一个节点。

它可以被派生的小部件覆盖。

参数:
key

str,用于查找目标节点的字符串。它可以是任何键盘按键,也可以是鼠标的scrollup、scrolldown、scrollright和scrollleft字符串。如果字母快速连续输入,这些字母会在作为key传入之前被合并,可用于查找具有以这些字母开头的关联字符串的节点。

last_node

最后选中的节点。

last_node_idx

get_selectable_nodes 列表中最后选中节点的缓存索引。如果该列表未发生变化,则无需在该列表中查找 last_node 的索引,从而节省了查找时间。

返回:

元组,包含由键定位的节点及其在 get_selectable_nodes() 列表中的索引。返回 (last_node, last_node_idx) 表示未找到节点。

keyboard_select

决定键盘是否可用于选择。若为False,键盘输入将被忽略。

keyboard_select 是一个 BooleanProperty,默认值为 True。

multiselect

决定是否可以选择多个节点。若启用,键盘的Shift和Ctrl键选择,可选地与触摸结合,例如,将能够以通常预期的方式选择多个控件。当此属性为False时,它优先于 touch_multiselect

multiselect 是一个 BooleanProperty,默认值为 False。

nodes_order_reversed

(内部)指示节点自上而下显示的顺序是否与它们在 get_selectable_nodes() 中的顺序相反(例如,children 属性的顺序与其显示顺序相反)。

page_count

确定按下pageup(或pagedown)时,所选节点相对于上次所选节点位置向上或向下移动的量。

page_count 是一个 NumericProperty,默认值为 10。

right_count

决定当键盘上的右(或左)箭头被按下时,所选节点相对于上一个选中节点位置向上或向下移动的量。

right_count 是一个 NumericProperty,默认值为 1。

scroll_count

确定鼠标滚轮滚动时,所选节点相对于上一个所选节点位置上下移动的量。

right_count 是一个 NumericProperty,默认值为 0。

select_node(node)[源代码]

选择节点。

当控制器选中一个节点时,会调用此方法,也可以从外部直接调用以选中节点。派生的小部件应重写此方法,并在被调用时将节点状态更改为选中状态。

参数:
节点

要选择的节点。

返回:

bool,若节点被选中则为True,否则为False。

警告

如果该方法被覆盖,派生控件必须使用super调用它。

select_with_key_down(keyboard, scancode, codepoint, modifiers, **kwargs)[源代码]

处理按键按下事件。当按键按下用于选择时,会调用此方法。根据按下的键盘按键和配置,它可以从可选节点列表(get_selectable_nodes())中选择或取消选择节点或节点范围。

参数设计使其可以直接绑定到键盘的on_key_down事件。因此,当按键被按住时,像键盘那样重复调用它是安全的。

返回:

布尔值,如果按键被使用则为True,否则为False。

select_with_key_up(keyboard, scancode, **kwargs)[源代码]

(内部)处理按键释放。当 select_with_key_down() 返回 True 的按键被释放时,派生控件必须调用此方法。

这些参数的设计使其可以直接绑定到键盘的on_key_up事件上。

返回:

bool,若按键释放已被使用则为True,否则为False。

select_with_touch(node, touch=None)[源代码]

(内部)处理节点上的触摸事件。当节点被触摸并用于选择时,派生控件应调用此方法。根据按下的键盘按键和配置,它可能会选择或取消选择此节点以及可选中节点列表中的其他节点,参见 get_selectable_nodes()

参数:
节点

接收触摸的节点。对于滚动类型的触摸,该值可能为 None。

touch

可选参数,触摸事件。默认为 None。

返回:

bool,若触摸已被使用则为True,否则为False。

selected_nodes

所选节点的列表。

备注

可以连续选择多个节点,例如使用键盘操作。在监听 selected_nodes 时,需要注意这一点。

selected_nodes 是一个 ListProperty,默认值为空列表 []。它是只读的,不应被修改。

text_entry_timeout

当快速连续输入字符时(即与上一个字符的时间差小于 text_entry_timeout),这些按键会被拼接起来,并将合并后的文本作为 goto_node() 的 key 参数传递。

在 1.10.0 版本加入.

touch_deselect_last

multiselecttouch_multiselect 为 False 时,决定是否允许取消选择最后选中的节点。

在 1.10.0 版本加入.

touch_deselect_last 是一个 BooleanProperty,在移动平台上默认为 True,在桌面平台上默认为 False。

touch_multiselect

一种特殊的触摸模式,它决定了由 select_with_touch() 处理的触摸事件是将当前触摸的节点添加到选中集合中,还是在添加节点之前清除选中集合。这种模式允许通过简单触摸多个节点来实现多选。

这与 multiselect 不同,因为当其为 True 时,只需触摸一个未选中的节点即可将其选中,即使未按下 ctrl 键也是如此。然而,如果其为 False,则在 multiselect 为 True 时,必须按下 ctrl 键才能添加到选中项中。

备注

:属性 multiselect,当设为 False 时,将禁用 touch_multiselect

touch_multiselect 是一个 BooleanProperty,默认值为 False。

up_count

决定当键盘上的上(或下)箭头被按下时,所选节点相对于上一个选中节点位置向上或向下移动的距离。

up_count 是一个 NumericProperty,默认值为 1。