我正在使用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。什么都没有(但仍会保存那张图片,但不会向我展示。
答案 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
,因此您只需添加越来越多不必要的绘图说明。
您可能还会注意到,当您将多个这些小部件添加到布局时,它们都会在窗口的完整大小的同一位置呈现。窗口小部件不限于在其区域中绘制,并且可以在应用程序内的任何位置绘制。您需要通过传递Rectangle
和size
参数来确保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()
让默认处理程序接管。