使用Moblin进行应用程序开发——Clutter之动画

作者: 方亮 (Intel) (27 篇文章) 日期: 六月 16, 2009 在 2:19 下午

     正文开始之前先说几句别的。上月20号发布的Moblin V2 Beta版中,Clutter的版本已经到了0.9APIclutter 0.8相比有了些变化,两者在API上已不兼容。鉴于pyclutter目前版本依然还是0.8,并且本系列博文更侧重于概念,因此所用的API一律基于clutter 0.8。等clutter 1.0正式版本发布后,我们再来看API的变化。

 

之前讲了一点有关ActorStage的内容,有了演员和舞台,接下来自然而然就要上台表演,也就是这里所谓的动画了。在Clutter的动画中,有三个概念不得不提一下,他们是——TimelineAlphaBehaviour

       Timeline,即时间轴,也就是表演的时间段,这个概念我想大家应该都能明白,不多废话了。Behaviour,即行为,也就是表演的内容,比如放大、缩小、旋转、透明化等等均属于行为的范畴。最后讲讲Alpha,这个词挺难翻译的,如果放到表演上来理解,Alpha所指的应该是表演方式。比如同样是将某个Actor放大2倍,通过Alpha可以控制是采用线性放大,加速放大还是减速放大等效果。Alpha其实是一个与总帧数和当前帧相关的函数,它的返回值是一个介于0ALPHA_MAX之间的数,每当一个新的帧产生时都会调用Alpha函数,通过Alpha函数的返回值来确定当前帧的变化。用户可以自定义Alpha函数,也可以使用clutter提供的一些常用Alpha函数。

       一般来说,基于clutter进行动画编程,代码结构通常是这样的:

1.      创建时间轴ClutterTimeline

2.      创建ClutterAlpha

3.      创建ClutterBehaviour

4.      Behaviour应用到Actor

5.      启动时间轴

目前Clutter提供的Behaviour包括有BsplineEllipseDepthOpacityPathRotateScale。如果用户觉得这些Behaviour无法满足应用的需求,可以通过实现自定义Behaviour或者使用Timelinenew-frame事件来制作自定义的动画效果。

    回到以前使用的demo 程序——照片浏览器上来,这次要添加的功能是相片的正中显示。之前照片是以随机方位和角度铺在桌面上,现在通过双击照片,图片将以动画的形式移至窗口正中并转至0度。单击正中显示照片将使图片以动画形式回到原先的位置。

       代码如下:

#!/usr/bin/python

 

import sys

import os

import random

 

import clutter

 

STAGE_WIDTH=1024

STAGE_HEIGHT=768

Dragging = False

DraggingPhoto = None

Center = False

pic_list = []

timeline = None

alpha = None

p_behavior = None

r_behavior = None

 

class Photo:

       '''Photo class'''

       border_width = 10

 

       def __init__(self, path, stage):

              self.stage = stage

              self.path = path

              self.x = 0

              self.y = 0

              self.degree = 0

              self.drag_start_x = 0

              self.drag_start_y = 0

 

              self.pic = clutter.Texture()

              self.pic.set_from_file(path)

              self.width = self.pic.get_width()+2*Photo.border_width

              self.height = self.pic.get_height()+2*Photo.border_width     

                    

              self.frame = clutter.Rectangle()

              self.frame.set_color(clutter.Color(0xff, 0xff, 0xff, 0xff))

              self.frame.set_position(self.x, self.y)

              self.frame.set_size(self.width, self.height)

 

              self.group = clutter.Group()

              self.group.add(self.frame)

              self.group.add(self.pic)

              self.pic.set_position(Photo.border_width, Photo.border_width)

             

              self.stage.add(self.group)    

 

              self.group.set_reactive(True)

              self.group.connect("button-press-event", self.on_button_press)

              self.group.connect("button-release-event", self.on_button_release)

              self.group.connect("motion-event", self.on_motion)

             

 

       def set_random_position(self):

              stage_width = self.stage.get_width()

              stage_height = self.stage.get_height()

             

              left = random.randint(0, stage_width)

              top = random.randint(0, stage_height)

              degree = random.randint(0, 360)

 

              self.set_position(left, top, degree)

                    

 

       def set_position(self, x, y, degree):

              self.x = x

              self.y = y

              self.degree = degree

              self.group.set_position(x, y)

              self.group.set_rotation(clutter.Z_AXIS, degree, self.width/2, self.height/2, 0)

 

             

       def on_button_press(self, actor, event):

              global Dragging, DraggingPhoto, Center, timeline, alpha, p_behavior, r_behavior

 

              if event.button == 1 and event.click_count == 2 and Center == False:

                     self.group.raise_top()

                     for pic in pic_list:

                            pic.group.set_reactive(False)

                     self.group.set_reactive(True)

 

                     timeline = clutter.Timeline(30, 30)

                     alpha = clutter.Alpha(timeline, clutter.ramp_inc_func)

                    

                     tx = int((STAGE_WIDTH-self.width)/2)

                     ty = int((STAGE_HEIGHT-self.height)/2)

                                  

                     knots=((self.x, self.y), (tx, ty),)

                     p_behavior = clutter.BehaviourPath(alpha, knots)

                     p_behavior.apply(self.group)

 

                     r_behavior = clutter.BehaviourRotate(clutter.Z_AXIS, self.degree, 0, alpha, True)

                     r_behavior.set_center(self.width/2, self.height/2, 0)

                     r_behavior.apply(self.group)

 

                     timeline.start()

                     Center = True

 

                     return True

 

              if event.button == 1 and event.click_count == 1 and Center == True:

                     for pic in pic_list:

                            pic.group.set_reactive(True)

 

                     timeline = clutter.Timeline(30, 30)

                     alpha = clutter.Alpha(timeline, clutter.ramp_dec_func)

                    

                     tx = int((STAGE_WIDTH-self.width)/2)

                     ty = int((STAGE_HEIGHT-self.height)/2)

                                         

                     knots=((self.x, self.y), (tx, ty),)

                     p_behavior = clutter.BehaviourPath(alpha, knots)

                     p_behavior.apply(self.group)

 

                     r_behavior = clutter.BehaviourRotate(clutter.Z_AXIS, self.degree, 0, alpha, True)

                     r_behavior.set_center(self.width/2, self.height/2, 0)

                     r_behavior.apply(self.group)

 

                     timeline.start()

 

                     Center = False

 

                     return True

             

              if event.button == 1 and Dragging == False and Center == False:

                     Dragging = True

                     DraggingPhoto = self

                     self.drag_start_x = event.x

                     self.drag_start_y = event.y

                     self.group.raise_top()

                    

                     return True   

 

              return False  

 

       def on_motion(self, actor, event):

              global Dragging, DraggingPhoto

              if event.modifier_state & clutter.BUTTON1_MASK and Dragging == True and DraggingPhoto == self:

                     dist_x = event.x - self.drag_start_x

                     dist_y = event.y - self.drag_start_y

                     self.group.move_by(dist_x, dist_y)

                     self.drag_start_x = event.x

                     self.drag_start_y = event.y

                     return True

 

              return False

 

 

       def on_button_release(self, actor, event):

              global Dragging, DraggingPhoto

              if event.button == 1:

                     Dragging = False

                     DraggingPhoto = None

                     return True

 

              return False

 

      

 

def main(args):    

       if len(args) < 2:

              print "The number of arguments is less than 2!"

              return -1

 

       path=args[1]

       if not os.path.exists(path):

              print path, "doesn't exist!"

              return -1

 

       stage = clutter.Stage()

       stage.set_size(STAGE_WIDTH, STAGE_HEIGHT)

       stage.set_color(clutter.Color(0x00, 0x00, 0x00, 0x00))

       stage.connect("destroy", clutter.main_quit)

      

 

       if not path.endswith(os.sep):

              path+=os.sep

 

       filelist = os.listdir(path)

      

       for item in filelist:

              pic=Photo(path+item, stage)

              pic.set_random_position()

              pic_list.append(pic)

             

       stage.show_all()

       clutter.main()      

 

 

if __name__ == '__main__':

       main(sys.argv)

 

分类: 移动技术
标签:, ,

如需了解英特尔软件产品相关的性能和优化选项,请参阅优化注意事项.

 评论 (16)

2009年06月18日 21:11


grsh
强大!
2009年06月19日 00:47


1
2009年06月20日 01:49


孙常虹
很不错
2009年06月20日 01:49


孙常虹
很不错
2009年06月20日 01:49


iii
很不错
2009年06月20日 20:47


chxu
不错
2009年06月21日 04:29


shisulong
ding hao
2009年06月21日 21:05


的法国
阿大使馆的试过
2009年06月23日 07:40


lgh
顶,谢谢了
2009年06月23日 21:57


太子
很好 可以用用
2009年06月24日 00:31


wang
feichang hao a ,xiexie a a
2009年06月25日 20:53


wm
学习它接近一个月了,我发现clutter没有直接能用的button,input-box。请问怎么用clutter封装一个按钮类和文 本框输入类呢?

急???
2009年06月25日 21:07

方亮 (Intel)
方亮 (Intel)总分:
2,935
注册用户
clutter与传统的UI库如GTK相比似乎更加底层一些,因此其中的控件类型很少。没有button,inputbox倒是有的,呵呵 。在Moblin.org上有个项目叫NBTK,引用下官方描述,呵呵。
“The Netbook Toolkit is a GUI toolkit, using Clutter and is optimised for the Moblin netbook experience. It consists of various classes useful for building UIs such as Buttons, Tooltips, Scrollbars and others. It also supports styling through CSS stylesheets.”
地址是http://moblin.org/projects/netbook-toolkit-nbtk。目前暂时还没有在线文档,文档都打在源码包里。有兴趣的话可以去看一看。
2009年07月01日 23:57

wm111
wm111总分:
10
注册用户
非常感谢!
因为现在项目需要用clutter来做,所以会有很多问题摆在眼前,头都大了,input-box我还是用一个矩形,一个text加入到一 个group里面来实现的,只是封装起来了,还得处理些东东,不知道这样做可行不?还得请多多指教?
2009年07月02日 00:14

方亮 (Intel)
方亮 (Intel)总分:
2,935
注册用户
to wm111: 即使可行也太麻烦了……ClutterEntry是一个单行的编辑框,应该能符合你的要求。
2009年07月02日 07:20

wm111
wm111总分:
10
注册用户
我用的是clutter-0.9.2版本,ClutterEntry好像都被ClutterText所能代替,并且单用这个是没有输入框的 边框的,功能倒可以实现,能否有什么例子呢?关于input-box,button.

 引用 (0)


 写评论  

欲获得技术支持,请访问软件支持页面.
姓名 (必填)*

电子邮件 (必填,不在本页面显示)*

您的 URL (可选)


评论*