为啥我需要创建 Line 的新实例,而不是在 Kivy 中简单地更新或添加和删除它

Posted

技术标签:

【中文标题】为啥我需要创建 Line 的新实例,而不是在 Kivy 中简单地更新或添加和删除它【英文标题】:Why do I need to create a new instance of a Line instead of simply update or add and remove it in Kivy为什么我需要创建 Line 的新实例,而不是在 Kivy 中简单地更新或添加和删除它 【发布时间】:2013-06-12 09:29:47 【问题描述】:

我试图用鼠标从窗口的一个点拖动到另一个点来画一条线。我还想在拖动时代表这条线。就像在旧的 MS PaintBrush 中画线一样。

我的问题是我只能通过不断删除旧线并在画布上添加 new 顶点指令来实现这一点。但是,我无法更新现有说明。甚至没有添加和删除相同的指令。它必须是 Line 的新实例。通过运行以下代码,您可以看到我想要的结果。如果您尝试使用注释行运行它,它将不再起作用。

from kivy.app import App
from kivy.uix.relativelayout import RelativeLayout
from kivy.graphics import Line

class MyCanvas(RelativeLayout):
    def on_touch_down(self, touch):
        with self.canvas:
            self.line = Line(points=[touch.x,touch.y,touch.x+1,touch.y+1])
        self.bind(on_touch_move=self.update_line, on_touch_up=self.end_line)
        return True

    def update_line(self, instance, touch):
        self.line.points[2] = touch.x
        self.line.points[3] = touch.y
        self.canvas.remove(self.line)
#        self.canvas.add(self.line) # - this doesn't work
#        self.canvas.ask_update()   # - not even using this
        with self.canvas:
            self.line = Line(points=self.line.points) # this works

    def end_line(self, instance, touch):
        self.unbind(on_touch_move=self.update_line)
        self.unbind(on_touch_up=self.end_line)
        self.line.points[2] = touch.x
        self.line.points[3] = touch.y
        self.canvas.remove(self.line)
#        self.canvas.add(self.line) # - this doesn't work
#        self.canvas.ask_update()   #- not even using this
        self.canvas.add(Line(points=self.line.points))  # this way works

class ExampleApp(App):
    def build(self):
        return MyCanvas()

ExampleApp().run()

我还尝试使用带有颜色指令的 in this other question 建议的 Kivy 属性。没用,还有another question related to it。

【问题讨论】:

我用ipdb 深入研究了代码,我意识到有一个名为needs_redraw 的Line'attribute。在当前行中始终为 False,并且变量被写保护。 【参考方案1】:

我正在努力解决同样的问题。我从 kivy/guide/firstwidget 目录中的 6_button.py 示例开始

我发现了一些可行的方法(使用 pop 两次从点中删除最后一个 x,y 对)但我认为这很尴尬,请参阅下面的代码。我希望有人可以告诉我们如何正确“更新”。

基于 6_button.py

from random import random
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.button import Button
from kivy.graphics import Color, Ellipse, Line


class MyPaintWidget(Widget):

    def on_touch_down(self, touch):
        color = (random(), 1, 1)
        with self.canvas:
            Color(*color, mode='hsv')
            d = 10.
            Ellipse(pos=(touch.x - d / 2, touch.y - d / 2), size=(d, d))
            touch.ud['line'] = Line(points=(touch.x, touch.y, touch.x+30, touch.y))
            #print(dir(touch.ud['line']))

    def on_touch_move(self, touch):
        #touch.ud['line'].points += [touch.x, touch.y]
        touch.ud['line'].points.pop()                     #
        touch.ud['line'].points.pop()                     # works but is awkward
        touch.ud['line'].points += [touch.x, touch.y]     #

        #touch.ud['line'].points[2:4] = [touch.x, touch.y] 
        #self.canvas.ask_update()              # no error but didnt work
        #touch.ud['line'].ask_update()         # didnt work
        #print(touch.ud['line'].points)
        #touch.ud['line'].needs_redraw()       # error 'bool not callable'
        #touch.ud['line'].needs_redraw = True  # error 'not writable'
        #touch.ud['line'].needs_redraw         #no error but doesnt work


class MyPaintApp(App):

    def build(self):
        parent = Widget()
        painter = MyPaintWidget()
        clearbtn = Button(text='Clear')
        parent.add_widget(painter)
        parent.add_widget(clearbtn)

        def clear_canvas(obj):
            painter.canvas.clear()
        clearbtn.bind(on_release=clear_canvas)

        return parent


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

【讨论】:

没那么尴尬。它没有解释为什么直接分配不起作用self.line.points[2] = touch.x。我开始认为这是创建新实例的唯一方法,但您找到了另一种方法。我可以告诉你,如果你将pos 更新为Ellipse,这将失败,因为它是tuple 并且没有pop 方法。看看这个由 Kivy 开发人员回答的question。毕竟,创建一个新 Line 可能并没有那么错。

以上是关于为啥我需要创建 Line 的新实例,而不是在 Kivy 中简单地更新或添加和删除它的主要内容,如果未能解决你的问题,请参考以下文章

如何更新form2中的数据而不创建form2的新实例

如果我的应用在后台,为啥 Android 操作系统不会创建 singleTop 活动的新实例?

为啥我们需要在单独的服务层中编写业务逻辑而不是在控制器本身中编写?

为啥 PyAudio 在一个模块中工作而不是在另一个模块中工作?

为啥 sql 数据库不允许为所有查询创建函数而不是在调用程序中构造 sql 字符串?

在不同的新标签中打开两个链接,而不是在同一个