Kivy - 如何将项目从 ScrollView 拖放到另一个布局?

Kivy - How to drag and drop items from ScrollView to another layout?

我试图将一些排列在 GridLayout(实际上是在 ScrollView 内)内的图像拖到外部布局。

要拖动的图像定义了 on_touch_down 事件,当单击图像时,父级从 WidgetMenu 更改为 MainLayout,因此可以在这些小部件之间拖动。目前的问题是当我触摸图像时,DragBehavior 丢失了。

完整代码:

import kivy
kivy.require("1.9.1")
from kivy.app import App
from kivy.core.window import Window
from kivy.uix.scrollview    import ScrollView
from kivy.uix.widget import Widget
from kivy.uix.behaviors import DragBehavior
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.gridlayout import GridLayout

from kivy.base import runTouchApp
from kivy.lang import Builder

Builder.load_string('''
<WidgetMenu>:
    canvas.before:
        Color:
            rgb: 0.9,0.5,0.3
        RoundedRectangle:
            pos:self.pos
            size: self.size
            radius: [20,]
    orientation: "vertical"
    padding:30

    ScrollView:

        GridLayout:
            cols:1
            size_hint_y:None
            row_default_height:root.height*.15
            height:self.minimum_height
            DragImage:
            DragImage:
            DragImage:


<DragImage>:
    drag_rectangle: self.x, self.y, self.width, self.height
    drag_timeout: 100000000
    drag_distance: 0
    size_hint:None,None
    size:234,34
    canvas:
        Color:
            rgb:1,0,1
        Rectangle:
            pos: self.pos
            size: self.size

<MainLayout>:
    canvas:
        Color:
            rgb:1,1,1
        Rectangle:
            size: self.size
            pos: self.pos
    WidgetMenu:
        size_hint: 0.35,0.9

''')

class MainLayout(FloatLayout):
    pass
class WidgetMenu(BoxLayout):
    pass
class DragImage(DragBehavior,FloatLayout):
    def on_touch_down(self,touch):
        workspace = self.parent.parent.parent.parent
        grid = self.parent
        menu = self.parent.parent.parent
        if "MainLayout" in str(workspace):
            grid.remove_widget(self)
            workspace.remove_widget(menu)
            self.pos = Window.mouse_pos
            workspace.add_widget(self)
        return True

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

ScrollApp().run()

请帮忙。

您的代码存在两个问题,即您没有在 on_touch_down 中调用 super 方法,并且将 DragImage 置于顶层 MainLayout 会更改 posDragImage,从而改变其 DragRectangleDragRectangle 中的更改将 touch.pos 留在了它之外,因此 DragBehavior 认为触摸不在 DragImage.

我通过调用 super 方法并在将其传递给 super 方法之前更改 touch.pos 来解决这两个问题。我还添加了一些代码,以在单击鼠标时将 DragImage 保持在相对于鼠标的相同位置。还添加了对 self.collide_point() 的调用,以忽略不在 DragImage.

上的点击
class DragImage(DragBehavior,FloatLayout):
    def on_touch_down(self,touch):
        if not self.collide_point(*touch.pos):
            return False
        workspace = self.parent.parent.parent.parent
        grid = self.parent
        menu = self.parent.parent.parent
        if "MainLayout" in str(workspace):
            grid.remove_widget(self)
            workspace.remove_widget(menu)

            # the following code assumes that workspace is the entire Window
            self.x = Window.mouse_pos[0] - (touch.pos[0] - self.x)
            self.y = Window.mouse_pos[1] - (touch.pos[1] - self.y)
            workspace.add_widget(self)
            touch.pos = Window.mouse_pos
        return super(DragImage, self).on_touch_down(touch)