首页 > 解决方案 > 在 Kivy 中独立移动多个小部件

问题描述

我正在尝试使用 Kivy 库创建一个带有 python 的 Ur 皇家游戏。

我正在尝试做的是为每个玩家创建一个棋盘(已经完成,但还有更复杂的工作)和 7 个棋子(数字)。我设法创建了所有 7 个,但不知道如何独立操作或移动它们。

我找到了一个允许我使用鼠标移动对象的代码,但我只需要移动鼠标所在的对象。有点像只抓住你需要的棋子,而不是一直抓住皇后。

代码:

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.graphics import Ellipse
from kivy.clock import Clock
from random import random

class CircleWidget(Widget):
    def __init__(self, **kwargs):
        Widget.__init__(self, **kwargs)
        self.size = (50,50)
        for i in range(0, 7):
            self.circle = Ellipse(pos = self.pos, size = self.size)
            self.canvas.add(self.circle)

    # handle position change
    def on_pos(self, obj, new_pos):
        self.circle.pos = new_pos # when widget moves, so does the graphic instruction

class RootWidget(Widget):

    def __init__(self, **kwargs):
        Widget.__init__(self, **kwargs)
        self.cw = CircleWidget()
        self.add_widget(self.cw)

    def on_touch_down(self, touch):
        if self.collide_point(*touch.pos):
            touch.grab(self)
            # do whatever else here

    def on_touch_move(self, touch):
        if touch.grab_current is self:
            print("This prints all the time...")
            self.cw.pos = (touch.x,touch.y)

    def on_touch_up(self, touch):
        if touch.grab_current is self:
            touch.ungrab(self)
            # and finish up here

    def update(self, dt):
        print("No idea why I need this")

class MyApp(App):
    def build(self):
        rw = RootWidget()
        # call update() every second
        Clock.schedule_interval(rw.update, 1.0)
        return rw

MyApp().run()

另外,我忘记将所有人物的位置编辑为彼此相邻,但这并不是一项艰巨的任务。

有没有帮助一一移动它们?

标签: pythonkivy

解决方案


类 CircleWidget

  1. 在画布上画一个椭圆。
  2. 将possize绑定到回调、重绘方法。
  3. 为每个Circlewidget实现on_touch_downon_touch_upon_touch_move方法。

例子

主文件

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.graphics import Ellipse, Color
from kivy.core.window import Window
from random import randint


class CircleWidget(Widget):
    def __init__(self, **kwargs):
        super(CircleWidget, self).__init__(**kwargs)
        self.size = (50, 50)
        with self.canvas:
            Color(0, 0, 1, 0.5)
            self.circle = Ellipse(pos=self.pos, size=self.size)
        self.bind(pos=self.redraw, size=self.redraw)

    def redraw(self, *args):
        self.circle.size = self.size
        self.circle.pos = self.pos

    def on_touch_down(self, touch):
        if self.collide_point(*touch.pos):
            # if the touch collides with our widget, let's grab it
            touch.grab(self)

            # and accept the touch.
            return True

        return super(CircleWidget, self).on_touch_down(touch)

    def on_touch_up(self, touch):
        # check if it's a grabbed touch event
        if touch.grab_current is self:
            # don't forget to ungrab ourself, or you might have side effects
            touch.ungrab(self)

            # and accept the last up
            return True

        return super(CircleWidget, self).on_touch_up(touch)

    def on_touch_move(self, touch):
        # check if it's a grabbed touch event
        if touch.grab_current is self:
            self.pos = touch.pos

            # and accept the last move
            return True

        return super(CircleWidget, self).on_touch_move(touch)


class RootWidget(Widget):

    def __init__(self, **kwargs):
        super(RootWidget, self).__init__(**kwargs)
        for i in range(8):
            self.add_widget(CircleWidget(pos=(randint(0, Window.width - 50), randint(0, Window.height - 50))))


class MyApp(App):
    def build(self):
        return RootWidget()


if __name__ == "__main__":
    MyApp().run()

输出

Img01 - 应用启动 Img02 - 独立移动多个小部件


推荐阅读