列表中的 Kivy 可绘制行

问题描述 投票:0回答:1

用户应该能够拖动行来重新排序。在当前的实现中,它只是简单的按钮,但拖动对用户来说更加友好

此代码仅在移动一点后才起作用,一开始有些元素卡在该位置并且无法移动。我不确定是 on_touch_down 还是 init 导致了这种行为。

我使用的是kivy 2.3.0 和 3.11

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.uix.behaviors import DragBehavior
from kivy.graphics import Color, Rectangle

class DraggableLabel(DragBehavior, Label):
    def __init__(self, label_text, description_text, **kwargs):
        super(DraggableLabel, self).__init__(**kwargs)
        self.text = f"{label_text}: {description_text}"
        self.size_hint_y = None
        self.height = 40
        self.drag_touch = None
        self.original_index = 0

        with self.canvas.before:
            Color(0.4, 0.7, 0.9, 1)  # Set the background color (R, G, B, A)
            self.rect = Rectangle(pos=self.pos, size=self.size)

        self.bind(pos=self.update_rect, size=self.update_rect)
        

    def update_rect(self, *args):
        self.rect.pos = self.pos
        self.rect.size = self.size

    def on_touch_down(self, touch):
        if self.collide_point(*touch.pos) and not self.drag_touch:
            self.drag_touch = touch
            self.original_index = self.parent.children.index(self)
            return super(DraggableLabel, self).on_touch_down(touch)
        return super(DraggableLabel, self).on_touch_down(touch)

    def on_touch_move(self, touch):
        if touch == self.drag_touch:
            self.y = touch.y - self.height / 2

            # Update the position in the list while still dragging
            target_index = round(self.y / self.height)
            target_index = max(0, min(target_index, len(self.parent.elements) - 1))

            if self.original_index < target_index:
                target_index -= 1

            if target_index != self.original_index:
                self.parent.reorder_elements(self.original_index, self)
                self.original_index = target_index

    def on_touch_up(self, touch):
        if touch == self.drag_touch:
            self.parent.reorder_elements(self.original_index, self)
            self.drag_touch = None
            return True
        return super(DraggableLabel, self).on_touch_up(touch)

class ReorderableList(BoxLayout):
    def __init__(self, elements, **kwargs):
        super(ReorderableList, self).__init__(**kwargs)
        self.orientation = 'vertical'
        self.spacing = 5
        self.elements = []

        for element in elements:
            label = DraggableLabel(label_text=element['label'],
                                    description_text=element['description'])
            self.add_widget(label)
            self.elements.append(label)

    def reorder_elements(self, original_index, dragged_label):
            dragged_index = self.elements.index(dragged_label)

            target_index = round(dragged_label.y / dragged_label.height)
            target_index = max(0, min(target_index, len(self.elements) - 1))

            if original_index < target_index:
                target_index -= 1

            dragged_widget = self.elements.pop(original_index)
            self.remove_widget(dragged_widget)

            self.elements.insert(target_index, dragged_widget)
            self.add_widget(dragged_widget, index=target_index)

class DragAndDropApp(App):
    def build(self):
        elements = [
            {'label': 'Item 1', 'description': 'Description 1'},
            {'label': 'Item 2', 'description': 'Description 2'},
            {'label': 'Item 3', 'description': 'Description 3'},
            {'label': 'Item 4', 'description': 'Description 4'},
            {'label': 'Item 5', 'description': 'Description 5'},
            {'label': 'Item 6', 'description': 'Description 6'},
            {'label': 'Item 7', 'description': 'Description 7'},
            {'label': 'Item 8', 'description': 'Description 8'},
            {'label': 'Item 9', 'description': 'Description 9'},
            {'label': 'Item 10', 'description': 'Description 10'},
        ]

        return ReorderableList(elements)

if __name__ == '__main__':
    DragAndDropApp().run()


python user-interface kivy
1个回答
0
投票

我认为代码中唯一的问题是

reorder_elements()
中的两行。尝试改变:

dragged_widget = self.elements.pop(original_index)

至:

dragged_widget = dragged_label
self.elements.remove(dragged_widget)

并更改:

self.elements.insert(target_index, dragged_widget)

至:

self.elements.insert(-target_index, dragged_widget)

请记住,

children
ReorderableList
中小部件的顺序与它们在 GUI 中出现的顺序相反,并且与
elements
列表中的顺序相反。

© www.soinside.com 2019 - 2024. All rights reserved.