Python Kivy Canvas不会更新

时间:2014-12-30 21:27:31

标签: python canvas kivy

我正在使用64x64磁贴创建一个“地图编辑器”。当我点击并更改位置上的图块时,我需要更新画布。我最初用

设置了画布
with self.canvas:
    Rectangle(source = 'image.png')

在一个课程中,然后在我的touch_down课程中我打电话

with self.canvas:
    Rectangle(source = 'newImage.png')

我更改图像后更新它。

我已经能够让它更新但我必须每次创建一个新图像,它似乎不会更新,因为我已经添加了该特定源图像的矩形,并没有看到图像已经改变?

回应Ryan P

仍然没有。我试过这个

Class mypaintwidget(Widget): #This is added as a widget to my layout
    def on_touch_down(self, touch):
        with self.canvas:
            self.rect = Rectangle(source = 'image.png')
        tilepng = pil.open('64x64tile.png') #pil is Python Image Library
        tilemap = pil.open('image.png')       
        tilemap.paste(tilepng,location)
        tilemap.save('newimage.png')
        self.rect.source = 'newimage.png'

它只会更新ONCE。什么都没有(但仍会保存那张图片,但不会向我展示。

1 个答案:

答案 0 :(得分:4)

您需要修改Rectangle指令(或删除和替换,但修改更容易):

with self.canvas:
    self.rect = Rectangle(source='image.png')

然后:

self.rect.source = 'newImage.png'

关于问题的第二部分,问题是图像在加载到Kivy时被缓存。因此,当您保存newimage.png并重新加载时,Kivy知道您已加载newimage.png。对于Kivy应用程序来说,这不是一个好的设计。

此外,在Rectangle中创建on_touch_down表示每次按下窗口小部件时最终都会创建一个新的Rectangle,因此您只需添加越来越多不必要的绘图说明。

您可能还会注意到,当您将多个这些小部件添加到布局时,它们都会在窗口的完整大小的同一位置呈现。窗口小部件不限于在其区域中绘制,并且可以在应用程序内的任何位置绘制。您需要通过传递Rectanglesize参数来确保pos指令知道在哪里绘制。

最后,您可以只在另一个上方显示一个图像,而不是保存图像。这将更加高效,并且不需要使用唯一的文件名或搞乱缓存系统。

您一定要查看Kivy language (kv),因为它更容易用于设计小部件和布置您的应用。

以下是使用kv执行此操作的示例:

<TileWidget>:
    tilesource: ''

    canvas:
        Color:
            rgba: 1, 1, 1, 1
        Rectangle:
            size: self.size
            pos: self.pos
            source: 'image.png'
        Color:
            a: 1 if self.tilesource else 0
        Rectangle:
            size: self.size
            pos: self.pos
            source: self.tilesource

现在我将解释所有这一切。

<TileWidget>:

这是一个类规则,因为名称被<>包围。它将适用于TileWidget

的所有实例
    tilesource: ''

我们setting the value of the property tilesource。但是tilesource不是Widget类的属性!别担心。在kv中,当您为这样的不存在的属性赋值时,将自动创建该属性。由于我们分配给属性的值是一个字符串,Kivy会意识到我们希望它是StringProperty

通过创建此属性,我们可以从外部影响此窗口小部件。我们将使用此属性的值稍后显示图像。

    canvas:

就像在Python中使用类中的with self.canvas:一样。

        Color:
            rgba: 1, 1, 1, 1

canvas块内,我们可以添加绘图说明。我们从Color instruction开始,因为您不知道当前设置的颜色是什么。这种颜色会使我们显示的图像着色,我们不需要任何色调,因此我们使用全白色。

        Rectangle:
            size: self.size
            pos: self.pos
            source: 'image.png'

现在我们要渲染第一张图片。我们确保Rectangle的大小和pos匹配小部件。在kv中,这样做会自动创建绑定。如果移动窗口小部件,其大小将会更改,Rectangle将自行更新以匹配。

        Color:
            a: 1 if self.tilesource else 0

这一次,我们知道颜色的设置。但是,在设置图像之前,我们不想绘制任何其他内容。在kv中,属性将接受任何Python值。这意味着您可以像这样使用ternary expressions,或函数调用或算术等。因此,如果self.tilesource求值为False(如空字符串,我们在上面设置的默认值),那么{{ 1}}颜色的属性(alpha分量)将设置为0,否则将为1。

a

最后,我们渲染所选图像。

现在,要创建小部件本身,我们只需要一点Python:

        Rectangle:
            size: self.size
            pos: self.pos
            source: self.tilesource

处理触摸时使用collide_point非常重要。就像小部件可以在应用程序中的任何位置绘制一样,他们也可以在应用程序的任何位置处理触摸。这可以确保在操作之前触摸实际上在我们的小部件的范围内。 内部 class TileWidget(Widget): def on_touch_down(self, touch): if self.collide_point(*touch.pos): self.tilesource = '64x64tile.png' return True return super(TileWidget, self).on_touch_down(touch) 块,我们将返回True,让Kivy知道我们已经处理了这个触摸,并且没有其他任何东西可以处理它。否则,我们调用super()让默认处理程序接管。