您需要修改Rectangle指令(或删除并替换,但修改起来更容易):
with self.canvas:
self.rect = Rectangle(source='image.png')
然后再:
self.rect.source = 'newImage.png'
至于问题的第二部分,问题在于在Kivy中加载图像时会对其进行缓存。 因此,当您保存newimage.png并再次重新加载时,Kivy知道您已经加载了newimage.png 。 对于Kivy应用程序来说,这并不是一个很好的设计。
同样,在on_touch_down创建Rectangle意味着每次按下该小部件时最终都会创建一个新的Rectangle ,因此您只需添加越来越多的不必要的绘图指令即可。
您可能还会注意到,当您将多个这些小部件添加到布局中时,它们全部以窗口的完整大小呈现在同一位置。 小部件不限于在其区域内绘制,并且可以在应用程序内的任何位置绘制。 您需要通过传递Rectangle指令的size和pos参数来确保其知道在哪里绘制。
最后,除了保存图像,您还可以在另一个图像上显示一个图像。 这将更加高效,并且不需要使用唯一的文件名或将缓存系统弄乱。
您绝对应该看一下Kivy语言(kv),因为它在设计小部件和布局应用程序时非常容易使用。
这是使用kv执行此操作的示例:
:
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所有实例。
tilesource: ''
在这里,我们设置属性 tilesource 的值 。 但是tilesource不是Widget类的属性! 别担心。 在kv中,当您为这样的不存在属性分配值时,该属性将自动创建。 由于我们要分配给该属性的值是一个字符串,因此Kivy将意识到我们希望它是一个StringProperty 。
通过创建此属性,我们可以从外部影响此小部件。 我们稍后将使用此属性的值来显示图像。
canvas:
就像with self.canvas:来自Python类。
Color:
rgba: 1, 1, 1, 1
在canvas块内,我们可以添加绘图指令。 我们从Color指令开始,因为您不知道当前设置的颜色。 该颜色将着色我们显示的图像,并且我们不需要任何着色,因此我们使用全白色。
Rectangle:
size: self.size
pos: self.pos
source: 'image.png'
现在,我们将渲染第一张图像。 我们确保Rectangle的大小和pos与小部件匹配。 在kv中,这样做会自动创建绑定。 如果小部件到处移动,其大小将改变,并且Rectangle将更新以匹配。
Color:
a: 1 if self.tilesource else 0
这次,我们知道颜色设置为什么。 但是,在设置图像之前,我们不想绘制其他任何东西。 在kv中,属性将接受任何Python值。 这意味着您可以使用像这样的三元表达式 ,函数调用或算术等。因此,如果self.tilesource计算结果为False(如空字符串,即我们在上面设置的默认值),那么颜色的a属性( alpha分量)将设置为0,否则将为1。
Rectangle:
size: self.size
pos: self.pos
source: self.tilesource
最后,我们渲染选定的图像。
现在,要创建小部件本身,我们只需要一点Python:
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)
就像小部件可以在应用程序中的任何位置绘制一样,它们也可以处理应用程序中任何位置的触摸。 这样可以确保在执行操作之前,触摸实际上在小部件的范围内。 在 collide_point块中,我们将返回True,以让Kivy知道我们已经处理了此触摸,并且没有其他任何处理。 否则,我们调用super()来让默认处理程序接管。