[英]Rotate image in Kivy without using Builder / .kv file and NumericProperty
So based on a bunch of different examples, I cobbled together an example Kivy app which uses Kivy Animation
to rotate an image. 因此,基于许多不同的示例,我将示例Kivy应用程序拼凑在一起,该应用程序使用Kivy Animation
旋转图像。
I want to know how to achieve the same result without using the .kv
file (or Builder.load_string
). 我想知道如何在不使用.kv
文件(或Builder.load_string
)的情况下实现相同的结果。
#! /usr/bin/env python3
import kivy
kivy.require('1.9.1')
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.label import Label
from kivy.uix.image import Image
from kivy.uix.floatlayout import FloatLayout
from kivy.graphics import Rectangle, Color, Rotate, PushMatrix, PopMatrix
from kivy.core.window import Window
from kivy.clock import Clock
from kivy.graphics.svg import Svg
from kivy.animation import Animation
from kivy.lang import Builder
from kivy.properties import NumericProperty
import random
WINDOW_WIDTH, WINDOW_HEIGHT = Window.size
Builder.load_string('''
<Sprite>:
canvas.before:
PushMatrix
Rotate:
angle: self.angle
axis: (0, 0, 1)
origin: self.center
canvas.after:
PopMatrix
''')
class Sprite( Image ):
angle = NumericProperty(0)
def __init__( self, x=0, y=0, **kwargs ):
super( Sprite, self ).__init__( **kwargs )
self.size_hint = (None, None) # tell the layout not to size me
self.angle = 0
self.source = 'alien.png'
self.size = self.texture.size
if ( x == 0 and y == 0 ):
self.pos = ( random.randrange(0,WINDOW_WIDTH) , random.randrange(0,WINDOW_HEIGHT) )
else:
self.pos = ( x,y )
self.animate() # start moving animation
def animateComplete( self, *kargs ):
Animation.cancel_all( self ) # is this needed?
self.angle = 0
self.animate()
def animate( self ):
self.anim = Animation( angle=360, duration=1 )
self.anim.bind( on_complete=self.animateComplete )
self.anim.repeat = True
self.anim.start( self )
class FPSText( Label ):
def __init__( self, **kwargs ):
super( FPSText, self ).__init__( **kwargs )
self.size_hint = (None, None) # tell the layout not to size me
self.pos_hint = { 'right':1, 'top':1 }
def update( self, count ):
self.text = "%d aliens / %3.1f FPS" % ( count, Clock.get_fps() )
self.size = self.texture_size
class AlienGame( FloatLayout ):
def __init__(self, **kwargs):
super( AlienGame, self).__init__(**kwargs)
self.aliens = []
self.fps_text = FPSText()
self.add_widget( self.fps_text )
self.addAlien( WINDOW_WIDTH//2, WINDOW_HEIGHT//2 )
def addAlien( self, x=0, y=0 ):
new_alien = Sprite( x, y )
self.aliens.append( new_alien )
self.add_widget( new_alien )
def update( self, dt ):
self.fps_text.text = '--'
self.fps_text.update( len( self.aliens ) )
def on_touch_down( self, touch ):
if ( touch.is_double_tap ):
for i in range( 7 ):
self.addAlien()
else: #if ( touch.is_single_tap ): (no single tap property)
self.addAlien( touch.pos[0], touch.pos[1] )
class RotApp( App ):
def build( self ):
game = AlienGame()
Clock.schedule_interval(game.update, 1.0 / 60.0)
return game
if ( __name__ == '__main__' ):
RotApp().run()
I tried something like: 我尝试了类似的东西:
class Sprite( Image ):
def __init__( self, x=0, y=0, **kwargs ):
super( Sprite, self ).__init__( **kwargs )
self.size_hint = (None, None) # tell the layout not to size me
self.source = 'alien.png'
self.size = self.texture.size
# define the rotation
with self.canvas.before:
PushMatrix()
self.rot = Rotate()
self.rot.angle = 0
self.rot.origin = self.center
self.rot.axis = (0, 0, 1)
with self.canvas.after:
PopMatrix()
But was unable to get the self.rot.angle
to update with the animation. 但是无法获取self.rot.angle
来更新动画。 It worked fine if I handled the animation manually, but I want to use the Kivy Animation
object. 如果我手动处理动画,效果很好,但是我想使用Kivy Animation
对象。
Is there a plain-python method of doing this? 是否有执行此操作的纯Python方法?
Yes, it's possible, here is your Sprite class that rotates using only python code. 是的,有可能,这是您的Sprite类,仅使用python代码进行旋转。 The only thing here is - there is a reason the kv lang was made! 这里唯一的是-制作kv lang是有原因的! It makes this stuff much easier. 它使这些工作变得容易得多。 I highly suggest keeping the kv code in. Anyway, to answer your question: the key was to 1) Start the animation on the self.rot widget rather than the self widget 2) Reset the self.rot.origin variable since self.center is (0,0) the moment a widget is initialized (and before it's actually placed on the screen, giving it a proper self.center). 我强烈建议保留kv代码。无论如何,要回答您的问题:关键是1)在self.rot小部件而不是self小部件上启动动画2)从self.center开始重置self.rot.origin变量是(0,0)初始化小部件的时间(在将其实际放置在屏幕上之前,为其赋予适当的self.center)。
Alternatively, you could use the bind
method. 另外,您可以使用bind
方法。 for example, set self.rot.angle = self.angle
and then later on, self.bind(angle=on_angle)
which would call your on_angle
function anytime your self.angle
changes. 例如,设置self.rot.angle = self.angle
,然后设置self.rot.angle = self.angle
self.bind(angle=on_angle)
, on_angle
self.angle
更改,它将调用on_angle
函数。 You would have to define a self.on_angle
function which should reset self.rot.angle = self.angle
. 您将必须定义一个self.on_angle
函数,该函数应重置self.rot.angle = self.angle
。 KV lang automatically does this for you, saving you tons of code. KV lang自动为您执行此操作,从而节省了大量代码。 In kv, angle: self.angle
automatically updates the angle
variable anytime the self.angle
variable changes, meaning no playing with the bind
function. 在kv中, angle: self.angle
每当self.angle
变量更改时angle: self.angle
自动更新angle
变量,这意味着不使用bind
函数。
Here is your sprite class. 这是您的Sprite类别。 Note the two lines self.rot.origin = self.center
and self.anim.start(self.rot)
: 注意两行self.rot.origin = self.center
和self.anim.start(self.rot)
:
class Sprite( Image ):
angle = NumericProperty(0)
def __init__( self, x=0, y=0, **kwargs ):
super( Sprite, self ).__init__( **kwargs )
# define the rotation
with self.canvas.before:
PushMatrix()
self.rot = Rotate()
self.rot.angle = 0
self.rot.origin = self.center
self.rot.axis = (0, 0, 1)
with self.canvas.after:
PopMatrix()
self.size_hint = (None, None) # tell the layout not to size me
self.angle = 0
self.source = 'alien.png'
self.size = self.texture.size
if ( x == 0 and y == 0 ):
self.pos = ( random.randrange(0,WINDOW_WIDTH) , random.randrange(0,WINDOW_HEIGHT) )
else:
self.pos = ( x,y )
self.rot.origin = self.center # Reset the center of the Rotate canvas instruction
self.animate() # start moving animation
def animateComplete( self, *kargs ):
Animation.cancel_all( self ) # is this needed?
self.rot.angle = 0
self.animate()
def animate( self ):
self.anim = Animation( angle=360, duration=1 )
self.anim.bind( on_complete=self.animateComplete )
self.anim.repeat = True
self.anim.start( self.rot ) # Start rotating the self.rot widget instead of the self widget
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.