2014-12-30 66 views
1

我正在使用64x64瓷磚創建「地圖編輯器」。當我點擊並更改位置處的瓷磚時,我需要更新畫布。我最初設置的畫布Python Kivy Canvas不會更新

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

在一個類中,然後在我的touch_down類我叫

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

後,我改變我的形象進行更新。

我已經能夠得到它的更新,但我必須每次創建一個新的圖像,它似乎不會更新,因爲我已經添加該矩形與該特定的源圖像,並沒有看到圖像有被改變了?

針對瑞安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' 

它只會更新一次。然後什麼(但仍保存圖像,但不會拿出來給我

回答

4

您需要修改Rectangle指令(或撤換,但修改比較容易)。

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

再後來:

self.rect.source = 'newImage.png' 

至於你的問題的第二部分,問題是,圖像在Kivy在加載緩存。所以,當你保存newimage.png並重新加載它再次,基維知道你已經加載newimage.png。這對於Kivy應用程序來說並不是一個很好的設計。

此外,Rectangleon_touch_down創造意味着你最終創造按下部件新Rectangle每一次,所以你只需要添加更多不必要的繪圖指令。

您可能還會注意到,當您將多個這些小部件添加到佈局時,它們都會在窗口的整個大小的同一位置呈現。小部件不限制在他們的區域繪製,並且可以在應用程序的任何地方繪製。您需要確保Rectangle指令知道在哪裏繪製,通過傳遞sizepos參數。

最後,不是保存圖像,而是隻顯示其中一個。這將會更有效率,並且不需要使用獨特的文件名或者與緩存系統混淆。

您絕對應該看看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 propertytilesource。但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的大小和位置與小部件匹配。在kv中,這樣做會自動創建一個綁定。如果小部件被移動,它的大小將會改變,並且Rectangle將自我更新以匹配。

 Color: 
      a: 1 if self.tilesource else 0 

這一次,我們知道顏色設置爲什麼。但是,我們不想在設置圖像之前繪製其他任何東西。在kv中,屬性將接受任何Python值。這意味着你可以像這樣使用ternary expressions,或者函數調用或者算術等。因此,如果self.tilesource的計算結果爲False(就像我們在上面設置的默認值的空字符串),那麼顏色(alpha分量)的a屬性將被設置爲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是很重要的。就像小部件可以在應用程序的任何位置繪製一樣,它們也可以在應用程序的任何位置處理觸摸。這可以確保在動作之前觸摸實際上在我們的小部件的範圍內。 Insidecollide_point block,我們將返回True以讓Kivy知道我們已經處理了這個接觸,並且沒有別的東西會處理它。否則,我們呼叫super()讓默認處理程序接管。

+0

我似乎無法使用 * self.rect.source ='newImage.png'* 與另一個類比* with self.canvas:self.rect = Rectangle(source ='image。png')* 我得到一個錯誤* AttributeError:'class'對象沒有屬性'rect'* –

+0

在這種情況下,你的問題的一部分是你試圖添加第二個Rectangle到不同的畫布。您需要引用原始小部件以更改其上的矩形。 –

+0

我無法獲得代碼在這些評論中很好地顯示即時將它添加到我的問題 –