Kivy - How can I drag and drop widgets between ScrollViews by Draggable?

36 Views Asked by At

I've got into a Kivy project that requires Draggable.

environment:

OS: Windows 10 Home

Python==3.11.5

Kivy==2.2.1

kivy-garden-draggable==0.2.0

Here are my py and kv files:

lists.py:

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.scrollview import ScrollView
from kivy_garden.draggable import KXDraggableBehavior, KXReorderableBehavior

class ListApp(App):
    def build(self):
        return MainLayout()

class MainLayout(BoxLayout):
    pass

class ReorderableBoxLayout(KXReorderableBehavior, BoxLayout):
    pass

class Card(KXDraggableBehavior, Label):
    pass

ListApp().run()

list.kv

<ReorderableBoxLayout@KXReorderableBehavior+BoxLayout>

<MainLayout>    
    canvas.before:
        Color:
            rgba: .6, .7, .8, 1
        Rectangle:
            pos: self.pos
            size: self.size
    
    BoxLayout:
        padding: '10dp'
        spacing: '10dp'

        ScrollView:
            id: left_box
            height: self.parent.height

            ReorderableBoxLayout:
                drag_classes: ['test',]
                orientation: 'vertical'
                padding: '5dp'
                spacing: '10dp'
                size_hint_y: None
                on_minimum_height: self.height = self.minimum_height

                Card:

                Card:

        ScrollView:
            id: center_box
            height: self.parent.height

            ReorderableBoxLayout:
                drag_classes: ['test',]
                orientation: 'vertical'
                padding: '5dp'
                spacing: '10dp'
                size_hint_y: None
                on_minimum_height: self.height = self.minimum_height

                Card:

                Card:

        ScrollView:
            id: right_box
            height: self.parent.height

            ReorderableBoxLayout:
                drag_classes: ['test',]
                orientation: 'vertical'
                padding: '5dp'
                spacing: '10dp'
                size_hint_y: None
                on_minimum_height: self.height = self.minimum_height

                Card:

                Card:

<Card>
    drag_cls: 'test'
    drag_timeout: 0
    text: 'Card'
    font_size: '30sp'
    size_hint_y: None
    
    canvas.before:
        Color:
            rgba: .5, .8, .5, 1
        Rectangle:
            pos: self.pos
            size: self.size

I'm trying to move widgets between ScrollViews. I've put three SVs in and they have some draggable widgets. When I carry a widget from SV(index number: 2), I can put it in SV(1) or SV(0), but when I try it from SV(1) or SV(0), the problem occurs. The draggable widgets would never get into SVs when the SV that the widget put in is to the left of one the widget was originally in.

In other words,

Work:

SV(2) -> SV(1), SV(0)

SV(1) -> SV(0)

Never Work:

SV(0) -> SV(1), SV(2)

SV(1) -> SV(2)

Does anybody know the solution?

Thank you!

1

There are 1 best solutions below

0
Nattōsai Mitō On

You need to dispatch touch events to all the ScrollViews no matter any of them consumes touches. For instance:

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy_garden.draggable import KXDraggableBehavior, KXReorderableBehavior

class ListApp(App):
    def build(self):
        return MainLayout()

class MainLayout(BoxLayout):
    pass

class ReorderableBoxLayout(KXReorderableBehavior, BoxLayout):
    pass

class Card(KXDraggableBehavior, Label):
    pass

class EquitableBoxLayout(BoxLayout):
    '''Always dispatches touch events to all its children'''
    def on_touch_down(self, touch):
        return any([c.dispatch('on_touch_down', touch) for c in self.children])
    def on_touch_move(self, touch):
        return any([c.dispatch('on_touch_move', touch) for c in self.children])
    def on_touch_up(self, touch):
        return any([c.dispatch('on_touch_up', touch) for c in self.children])

ListApp().run()
<MainLayout>    
    canvas.before:
        Color:
            rgba: .6, .7, .8, 1
        Rectangle:
            pos: self.pos
            size: self.size
    
    EquitableBoxLayout:
        padding: '10dp'
        spacing: '10dp'

        ScrollView:
            id: left_box
            height: self.parent.height

            ReorderableBoxLayout:
                drag_classes: ['test',]
                orientation: 'vertical'
                padding: '5dp'
                spacing: '10dp'
                size_hint_y: None
                on_minimum_height: self.height = self.minimum_height

                Card:

                Card:

        ScrollView:
            id: center_box
            height: self.parent.height

            ReorderableBoxLayout:
                drag_classes: ['test',]
                orientation: 'vertical'
                padding: '5dp'
                spacing: '10dp'
                size_hint_y: None
                on_minimum_height: self.height = self.minimum_height

                Card:

                Card:

        ScrollView:
            id: right_box
            height: self.parent.height

            ReorderableBoxLayout:
                drag_classes: ['test',]
                orientation: 'vertical'
                padding: '5dp'
                spacing: '10dp'
                size_hint_y: None
                on_minimum_height: self.height = self.minimum_height

                Card:

                Card:

<Card>
    drag_cls: 'test'
    drag_timeout: 0
    text: 'Card'
    font_size: '30sp'
    size_hint_y: None
    
    canvas.before:
        Color:
            rgba: .5, .8, .5, 1
        Rectangle:
            pos: self.pos
            size: self.size