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

为什么我需要创建一个新的行实例,而不是在Kivy中简单地更新或添加和删除它,kivy,Kivy,我试图用鼠标从窗口的一个点拖到另一个点来画一条线。我还希望在拖动时表示线。就像用旧画笔画一条线 我的问题是,我只能通过不断删除旧行并向画布添加新的顶点指令来实现这一点。但是,我无法更新现有说明。甚至不添加和删除相同的指令。它必须是Line的一个新实例。通过运行以下代码,您可以看到我想要的结果。如果您尝试使用注释行运行它,它将不再工作 from kivy.app import App from kivy.uix.relativelayout import RelativeLayout from k

我试图用鼠标从窗口的一个点拖到另一个点来画一条线。我还希望在拖动时表示线。就像用旧画笔画一条线

我的问题是,我只能通过不断删除旧行并向画布添加新的顶点指令来实现这一点。但是,我无法更新现有说明。甚至不添加和删除相同的指令。它必须是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()

我还尝试使用Kivy属性作为颜色说明的建议。它不起作用,但确实存在。

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

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

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

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

基于6_button.py
我用
ipdb
深入研究了代码,我意识到有一个叫做needs\u redraw的Line属性。在当前行中它总是False,并且变量是写保护的。我用
ipdb
深入研究代码,我意识到有一个名为needs\u redraw的Line属性。在当前行中它总是False,并且变量是写保护的。这并不是那么尴尬。但是,它没有解释为什么直接分配不起作用
self.line.points[2]=touch.x
。我开始认为这是创建新实例的唯一方法,但您找到了另一种方法。我可以告诉您,如果您正在为
椭圆
更新
pos
,这将失败,因为它是一个
元组
,并且没有
pop
方法。看看一个Kivy开发者的回答。创建一条新的生产线可能并没有那么错,也并没有那么尴尬。但是,它没有解释为什么直接分配不起作用
self.line.points[2]=touch.x
。我开始认为这是创建新实例的唯一方法,但您找到了另一种方法。我可以告诉您,如果您正在为
椭圆
更新
pos
,这将失败,因为它是一个
元组
,并且没有
pop
方法。看看一个Kivy开发者的回答。毕竟,创建一条新线可能没有那么错。
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()