在 Python 代码中单独移动 Scatter 中的小部件

Posted

技术标签:

【中文标题】在 Python 代码中单独移动 Scatter 中的小部件【英文标题】:Move widgets in Scatter individually in Python code 【发布时间】:2022-01-22 06:55:45 【问题描述】:

我正在尝试创建一个自定义小部件,我想将多个实例添加到布局中。这些小部件应该是可拖动的。

获得所需结果的一种方法是使用我已经成功实现的DragBehavior Mixin。现在我想使用Scatter 获得相同的结果。

from kivy.app import App
from kivy.core.window import Window
from kivy.graphics import Color, Rectangle
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.label import Label
from kivy.uix.scatter import Scatter


class MyLabelWidget(Label):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        with self.canvas:
            Color(0, 1, 0, 0.25)
            self.background_rect = Rectangle(pos=self.pos, size=self.size)

        self.bind(pos=self.update)

    def update(self, *args):
        self.background_rect.pos = self.pos


class ScattererApp(App):
    def build(self):
        Window.size = 400, 400

        layout = FloatLayout()
        scatter = Scatter()

        widget_1 = MyLabelWidget(
            size_hint=(None, None),
            size=(100, 100),
            pos=(50, 50),
            text="Drag me",
        )
        widget_2 = MyLabelWidget(
            size_hint=(None, None),
            size=(100, 100),
            pos=(150, 150),
            text="Drag me, too",
        )

        layout.add_widget(scatter)
        scatter.add_widget(widget_1)
        scatter.add_widget(widget_2)

        return layout


ScattererApp().run()

但不幸的是,当我尝试拖动一个小部件时,所有小部件的位置都会发生变化:

我想要的是能够单独拖动小部件,就像我对 DragBehavior 实现所做的那样:

from kivy.app import App
from kivy.core.window import Window
from kivy.graphics import Color, Rectangle
from kivy.uix.behaviors import DragBehavior
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.label import Label


class DragLabel(DragBehavior, Label):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.drag_rectangle = (self.x, self.y, self.width, self.height)
        self.drag_timeout = 10000000
        self.drag_distance = 0

        with self.canvas:
            Color(0, 1, 0, 0.25)
            self.background_rect = Rectangle(pos=self.pos, size=self.size)

        self.bind(pos=self.update)

    def update(self, *args):
        self.drag_rectangle = (self.x, self.y, self.width, self.height)
        self.background_rect.pos = self.pos


class DraggerApp(App):
    def build(self):
        Window.size = 400, 400
        layout = FloatLayout()

        widget_1 = DragLabel(
            size_hint=(None, None),
            size=(100, 100),
            pos=(50, 50),
            text="Drag me",
        )
        widget_2 = DragLabel(
            size_hint=(None, None),
            size=(100, 100),
            pos=(150, 150),
            text="Drag me, too",
        )

        layout.add_widget(widget_1)
        layout.add_widget(widget_2)

        return layout


DraggerApp().run()

我的 update 回调方法似乎永远不会被调用,尽管我 bound 它位于 MyLabelWidget 对象的位置上,正如 Alexander Taylor 的 Updating canvas instructions declared in Python 文章中所述:

self.bind(pos=self.update)

有没有什么方法可以在不使用Kv language的情况下达到预期的效果?

【问题讨论】:

【参考方案1】:

好的,我似乎错误地使用了 Scatter 类。每个小部件本身都应该是一个 scatter,而不仅仅是添加到单个 scatter 实例中:

from kivy.app import App
from kivy.core.window import Window
from kivy.graphics import Color, Rectangle
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.label import Label
from kivy.uix.scatter import Scatter


class MyLabelWidget(Scatter, Label):
    def __init__(self, bgcolor, **kwargs):
        super().__init__(**kwargs)

        with self.canvas.before:
            Color(*bgcolor)
            self.background_rect = Rectangle(
                pos_hint=(None, None),
                pos=self.pos,
                size_hint=(None, None),
                size=self.size,
            )


class Scatterer2App(App):
    def build(self):
        Window.size = 400, 400

        layout = FloatLayout()

        widget_1 = MyLabelWidget(
            size_hint=(None, None),
            size=(100, 100),
            pos=(50, 50),
            bgcolor=(1, 0, 0, 1),
            text="Drag me",
        )
        widget_2 = MyLabelWidget(
            size_hint=(None, None),
            size=(100, 100),
            pos=(150, 150),
            bgcolor=(0, 0, 1, 1),
            text="Drag me, too",
        )

        layout.add_widget(widget_1)
        layout.add_widget(widget_2)
        return layout


Scatterer2App().run()

但这会导致标签和标签背景定位不正确:

为了解决这个问题,MyLabelWidget 不应该继承自 Scatter,而是添加到单个 Scatter 实例中:

from kivy.app import App
from kivy.core.window import Window
from kivy.graphics import Color, Rectangle
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.label import Label
from kivy.uix.scatter import Scatter
from kivy.uix.widget import Widget


class MyLabelWidget(Label):
    def __init__(self, bgcolor, **kwargs):
        super().__init__(**kwargs)

        with self.canvas.before:
            Color(*bgcolor)
            self.background_rect = Rectangle(size=self.size)


class MyScatterLabelWidget(Scatter):
    def __init__(self, bgcolor, text, **kwargs):
        super().__init__(**kwargs)
        self.label = MyLabelWidget(size=self.size, bgcolor=bgcolor, text=text)
        self.add_widget(self.label)


class Scatterer3App(App):
    def build(self):
        Window.size = 400, 400

        layout = FloatLayout()

        widget_1 = MyScatterLabelWidget(
            size_hint=(None, None),
            size=(100, 100),
            pos=(50, 50),
            bgcolor=(1, 0, 0, 1),
            text="Drag me",
        )
        widget_2 = MyScatterLabelWidget(
            size_hint=(None, None),
            size=(100, 100),
            pos=(150, 150),
            bgcolor=(0, 0, 1, 1),
            text="Drag me, too",
        )

        layout.add_widget(widget_1)
        layout.add_widget(widget_2)
        return layout


Scatterer3App().run()

【讨论】:

以上是关于在 Python 代码中单独移动 Scatter 中的小部件的主要内容,如果未能解决你的问题,请参考以下文章

python 中scatter cmap库 cmap=plt.cm.Paired 啥意思

python可视化---scatter()函数

在 Plotly Python 中移动 x 轴和 y 轴刻度

Matplotlib使用scatter函数在Python中绘制气泡图(bubble plot)通过size参数指定数据点的大小

Python随着时间的推移在Scatter3d中绘制动画标记样式或点

Python使用scatter()绘制散点图