kivy : 如何使用 scroll 处理 _on_keyboard_down 事件

kivy :How to work _on_keyboard_down event with scroll

我在 Tree View.label 中使用 _on_keyboard_down 事件来选择 updown keys.I 在 [=14= 中添加滚动] List.Can 有人告诉我如何在需要滚动时使用 updown 滚动吗?

.py

class TreeviewGroup(Popup):
    treeview = ObjectProperty(None)
    tv = ObjectProperty(None)
    h = NumericProperty(0)
    popup = ObjectProperty()

    def __init__(self, **kwargs):
        super(TreeviewGroup, self).__init__(**kwargs)
        self.tv = TreeView(root_options=dict(text=""),
                       hide_root=False,
                       indent_level=4)

        rows = [('test1'),('test2'),('test3'),('test4'),('test5'),('test6')]

        tree = []

        for r in rows:
            tree.append({'node_id': r, 'children': []})

        for branch in tree:
            populate_tree_view(self.tv, None, branch)
        #self.remove_widgets()
        self.treeview.add_widget(self.tv)
        Clock.schedule_once(self.update, 1)

        self.bind(on_open=self.on_open)

    def on_open(self, *args):
        self._keyboard = Window.request_keyboard(self._keyboard_closed, self)
        self._keyboard.bind(on_key_down=self._on_keyboard_down)
        if self.tv.selected_node is None:
            self.tv.select_node(self.tv.root.nodes[0])

    def _keyboard_closed(self):
        self._keyboard.unbind(on_key_down=self._on_keyboard_down)
        self._keyboard = None

    def _on_keyboard_down(self, keyboard, keycode, text, modifiers):
        node = self.tv.selected_node
        _, key = keycode
        if key in ('down', 'up'):
            parent = node.parent_node
            ix = parent.nodes.index(node)
            nx = ix+1 if 'down' else ix-1
            next_node = parent.nodes[nx % len(parent.nodes)]
            self.tv.select_node(next_node)
            return True
        elif key == 'enter':
            App.get_running_app().root.name.text = node.text
            keyboard.release()
            self.dismiss()

    def remove_widgets(self):
        for child in [child for child in self.treeview.children]:
            self.treeview.remove_widget(child)

    def update(self, *args):
        self.h = len([child for child in self.tv.children]) * 24

.kv

<TreeviewGroup>:
    treeview: treeview
    title: "Select"
    title_size: 17
    title_font: "Verdana"
    size: 800, 800
    auto_dismiss: False

    BoxLayout
        orientation: "vertical"
        ScrollView:
            size_hint: 1, .9
            BoxLayout:
                size_hint_y: None
                id: treeview
                height: root.h

        GridLayout:
            cols : 2
            row_default_height: '20dp'
            size_hint: .5, 0.2
            pos_hint: {'x': .25, 'y': 1}

            Button:
                text: 'Ok'
                on_release: root.dismiss()

            Button:
                text: 'Cancel'
                on_release: root.dismiss()

<TreeViewLabel>:
    text_size: self.size
    height: 30

您必须使用 scroll_to() method and pass the node, you must also set the height of the BoxLayout(self.treeview) to the size of the content, in this case to the TreeView(self.tv).

因此您必须删除 .kv 中的 height: root.h,并且在创建 TreeView in the .py we will make the connection there, in addition to removing that update method that is not necessary and that interrupts the operation of the ScrollView 时。 我不明白为什么它的值是 24 in:

self.h = len([child for child in self.tv.children]) * 24

再合适不过了30也就是TreeViewLabel的高度,另外对于这类任务使用Clock是不合适的,使用bind()

self.tv.bind(minimum_height=self.treeview.setter('height'))

是解决方案。

您还必须更改:

nx = ix+1 if 'down' else ix-1

nx = ix+1 if key == 'down' else ix-1

否则你永远爬不上

进行所有这些更改的解决方案是:

*.py

class TreeviewGroup(Popup):
    treeview = ObjectProperty(None)
    tv = ObjectProperty(None)
    h = NumericProperty(0)
    popup = ObjectProperty()

    def __init__(self, **kwargs):
        super(TreeviewGroup, self).__init__(**kwargs)
        self.tv = TreeView(root_options=dict(text=""),
                       hide_root=False,
                       indent_level=4)

        rows = [('test{}').format(i) for i in range(1, 20)]#[('test1'),('test2'),('test3'),('test4'),('test5'),('test6')]

        tree = [{'node_id': r, 'children': []} for r in rows]

        self.tv.bind(minimum_height=self.treeview.setter('height'))
        for branch in tree:
            populate_tree_view(self.tv, None, branch)
        #self.remove_widgets()
        self.treeview.add_widget(self.tv)

        self.bind(on_open=self.on_open)

    def on_open(self, *args):
        self._keyboard = Window.request_keyboard(self._keyboard_closed, self)
        self._keyboard.bind(on_key_down=self._on_keyboard_down)
        if self.tv.selected_node is None:
            self.tv.select_node(self.tv.root.nodes[0])

    def _keyboard_closed(self):
        self._keyboard.unbind(on_key_down=self._on_keyboard_down)
        self._keyboard = None

    def _on_keyboard_down(self, keyboard, keycode, text, modifiers):
        node = self.tv.selected_node
        _, key = keycode
        if key in ('down', 'up'):
            parent = node.parent_node
            ix = parent.nodes.index(node)
            nx = ix+1 if key == 'down' else ix-1
            next_node = parent.nodes[nx % len(parent.nodes)]
            self.tv.select_node(next_node)
            self.scroll.scroll_to(next_node)
            return True
        elif key == 'enter':
            App.get_running_app().root.name.text = node.text
            keyboard.release()
            self.dismiss()

    def remove_widgets(self):
        for child in [child for child in self.treeview.children]:
            self.treeview.remove_widget(child)

*.kv

<TreeviewGroup>:
    treeview: treeview
    title: "Select"
    title_size: 17
    size: 800, 800
    auto_dismiss: False
    scroll: scroll

    BoxLayout
        orientation: "vertical"
        ScrollView:
            id: scroll
            size_hint: 1, .9

            BoxLayout:
                size_hint_y: None
                id: treeview

        GridLayout:
            cols : 2
            row_default_height: '20dp'
            size_hint: .5, 0.2
            pos_hint: {'x': .25, 'y': 1}

            Button:
                text: 'Ok'
                on_release: root.dismiss()

            Button:
                text: 'Cancel'
                on_release: root.dismiss()

建议,使用适当的名称,例如BoxLayout的名称似乎表示TreeView的名称,这会造成混乱,导致其代码可读性差。