xiaoguozi's Blog
Pay it forword - 我并不觉的自豪,我所尝试的事情都失败了······习惯原本生活的人不容易改变,就算现状很糟,他们也很难改变,在过程中,他们还是放弃了······他们一放弃,大家就都是输家······让爱传出去,很困难,也无法预料,人们需要更细心的观察别人,要随时注意才能保护别人,因为他们未必知道自己要什么·····
Touchevent 中,返回值是 true ,则说明消耗掉了这个事件,返回值是 false ,则没有消耗掉,会继续传递下去,这个是最基本的。 

在 View 中跟 Touch 相关的事件有 dispatchTouchEvent , interceptTouchEvnet , onTouchEvent 三种。 dispatchTouchEvent 是负责分发事件的,事件从 activity 传递出来之后,最先到达的就是最顶层 view 的 dispatchTouchEvent ,然后它进行分发,如果返回 false ,则交给这个 view 的 interceptTouchEvent 方法来决定是否要拦截这个事件,如果 interceptTouchEvent 返回 true ,也就是拦截掉了,则交给它的 onTouchEvent 来处理,如果 interceptTouchEvent 返回 false ,那么就传递给子 view ,由子 view 的 dispatchTouchEvent 再来开始这个事件的分发。 

如果事件传递到 某一层的子 view 的 onTouchEvent 上了,这个方法返回了 false ,那么这个事件会从这个 view 往上传递,都是 onTouchEvent 来接收。而如果传递到最上面的 onTouchEvent 也返回 false 的话,这个事件就会“消失”,而且接收不到下一次事件。(我说的一次事件指的是 down 到 up 之间的一系列事件) 

 

注:上半部分为父View,下半部分为子View; 

完整的传递流程为:父View->子View->子View的子View->……->子View的子View->子View->父View。 
如果整个流程中都没有处理掉这个事件,即所有处理的返回值均为false,则不会再传递下一次事件,因为他会认为你这次的事件阻塞了,没必要给下一次。 
onTouchEvent如果不消耗的话,会从子view传递到父view。
posted @ 2011-09-10 11:33 小果子 阅读(289) | 评论 (0)编辑 收藏
基于Android开发应用时,可能会挺时常出现Out Of Memory 异常.

  在Android中,一个Process 只能使用16M内存,要是超过了这个限定就会跳出这个异常。这样就要求我们要时刻想着开释资源。Java的回收工作是交给GC的,如何让GC能实时的回收已经不是用的对象,这个里面有许多技巧,各人可以google一下。 

  因为总内存的施用超过16M而引起OOM的情况,非常简单,我就不继续展开说。值当注意的是Bitmap在不用时,肯定是要recycle,不然OOM是非常容易出现的。 

  本文想跟各人一起讨论的是另外一种情况:明明还有许多内存,但是发生OOM了。 

  这类情况时常出现在生成Bitmap的时候。有兴趣的可以试一下,在一个函数里生成一个13m 的int数组。

  再该函数结束后,按理说这个int数组应该已经被开释了,或者说可以开释,这个13M的空间应该可以空出来, 

  这个时候要是你继续生白手起家的百万富翁成一个10M的int数组是没有问题的,反而生成一个4M的Bitmap就会跳出OOM。这个就奇怪了,为啥子10M的int够空间,反而4M的Bitmap不敷呢? 

  这个问题困扰好久,在网上,国外各大论坛搜刮了好久,一般关于OOM的解释和解决方法都是,如何让GC尽快回收的代码风格之类,并没有现实的支出上面所说的情况的根源。 

  直到昨天在一个老外的blog上终于看到了这方面的解释,我理解后归纳如下: 

  在Android中: 

  1.一个进程的内存可以由2个部门组成:java 施用内存 ,C 施用内存 ,这两个内存的和必需小于16M,不然就会出现各人熟悉的OOM,这个就是熬头种OOM的情况。 

  2.越发奇怪的是这个:一朝内存分配给Java后,以后这块内存纵然开释后,也只能给Java的施用,这个估计跟java虚拟机里把内存分成好几块进行缓存的原因有关,反正C就别想用到这块的内存了,所以要是Java突然占用了一个大块内存,纵然很快开释了: 

  C能施用的内存 = 16M - Java某一瞬间占在校大学生创业点子用的最大内存。 

  而Bitmap的生成是路程经过过程malloc进行内存分配的,占用的是C的内存,这个也就说明了,上面所说的的4MBitmap无法生成的原因,因为在13M被Java用过后,剩下C能用的只有3M了。

http://blog.csdn.net/ghg8699/article/details/6586853


posted @ 2011-07-03 13:30 小果子 阅读(560) | 评论 (0)编辑 收藏

引言

大部分移动设备平台上的应用程序都运行在他们自己的沙盒中。他们彼此之间互相隔离,并且严格限制应用程序与硬件和原始组件之间的交互。 我们知道交流是多么的重要,作为一个孤岛没有交流的东西,一定毫无意义!Android应用程序也是一个沙盒,但是他们能够使用Intent、Broadcast Receivers、Adapters、Content Providers、Internet去突破他们的边界互相交流。有交流还会和谐,由此可见这些交流手段有多重要。

上篇文章中我们在SMS接收程序和使用Intent发送SMS程序中用到了Intent,并做了简单的回顾和总结:android应用程序的三大组件——Activities、Services、Broadcast Receiver,通过消息触发,这个消息就称作意图(Intent)。然后以活动为例简单介绍了Intent了并说明Intent机制的好处。既然在SMS程序中用到了Intent,这里我就借机顺着这条线,彻底详细地介绍一下Intent。分两篇文章介绍:

  1. Android开发之旅: Intents和Intent Filters(理论部分)
  2. Android开发之旅: Intents和Intent Filters(实例部分)

本文的主要内容如下:

  • 1、概述
  • 2、Intent对象
    • 2.1、组件名字
    • 2.2、动作
    • 2.3、数据
    • 2.4、种类
    • 2.5、附加信息
    • 2.6、标志
  • 3、Intent解析
    • 3.1、Intent过滤器
      • 3.1.1、动作检测
      • 3.1.2、种类检测
      • 3.1.3、数据检测
    • 3.2、通用情况
    • 3.3、使用intent匹配

1、概述

一个应用程序的三个核心组件——activitiesservicesbroadcast receivers,都是通过叫做intents的消息激活。Intent消息是一种同一或不同应用程序中的组件之间延迟运行时绑定的机制。intent本身(是一个Intent对象),是一个被动的数据结构保存一个将要执行的操作的抽象描述,或在广播的情况下,通常是某事已经发生且正在宣告。对于这三种组件,有独立的传送intent的机制:

  • Activity:一个intent对象传递给Context.startActivity()Activity.startActivityForRestult()去启动一个活动或使一个已存在的活动去做新的事情。
  • Service:一个intent对象传递给Context.startService()去初始化一个service或传递一个新的指令给正在运行的service。类似的,一个intent可以传递给Context.bindService()去建立调用组件和目标服务之间的连接。
  • Broadcast Receiver:一个intent对象传递给任何广播方法(如Context.sendBroadcast()Context.sendOrderedBroadcast()Context.sendStickyBroadcast()),都将传递到所有感兴趣的广播接收者。

在每种情况下,Android系统查找合适的activity、service、broadcast receivers来响应意图,如果有必要的话,初始化他们。这些消息系统之间没有重叠,即广播意图仅会传递给广播接收者,而不会传递活动或服务,反之亦然。

下面首先描述intent对象,然后介绍Android将intent映射到相应组件的规则——如何解决哪个组件应该接收intent消息。对于没有指定目标组件名字的intent,这个处理过程包括按照intent filters匹配每个潜在的目标对象。

2、Intent对象

一个Intent对象是一个捆信息,包含对intent有兴趣的组件的信息(如要执行的动作和要作用的数据)、Android系统有兴趣的信息(如处理intent组件的分类信息和如何启动目标活动的指令)。下面列出它的主要信息:

2.1、组件名字

处理intent的组件的名字。这个字段是一个ComponentName对象——是目标组件的完全限定类名(如"com.example.project.app.FreneticActivity")和应用程序所在的包在清单文件中的名字(如"com.example.project")的组合。其中组件名字中的包部分不必一定和清单文件中的包名一样。

组件名字是可选的,如果设置了,intent对象传递到指定类的实例;如果没有设置,Android使用intent中的其它信息来定位合适的目标组件(见下面的Intent解析)。组件的名字通过setComponent()setClass()setClassName()设置,通过getComponent()读取。

2.2、动作

一个字符串命名的动作将被执行,或在广播intent中,已发生动作且正被报告。Intent类定义了一些动作常量,如下:

Constant

Target component

Action

ACTION_CALL

activity

Initiate a phone call.

ACTION_EDIT

activity

Display data for the user to edit.

ACTION_MAIN

activity

Start up as the initial activity of a task, with no data input and no returned output.

ACTION_SYNC

activity

Synchronize data on a server with data on the mobile device.

ACTION_BATTERY_LOW

broadcast receiver

A warning that the battery is low.

ACTION_HEADSET_PLUG

broadcast receiver

A headset has been plugged into the device, or unplugged from it.

ACTION_SCREEN_ON

broadcast receiver

The screen has been turned on.

ACTION_TIMEZONE_CHANGED

broadcast receiver

The setting for the time zone has changed.

查看更多的动作请参考Intent类。其它的动作定义在Android API中,我们还可以定义自己的动作字符串一再我们的应用程序中激活组件。自定义动作字符串应该包含应用程序报名前缀,如"com.example.project.SHOW_COLOR"。

动作很大程度上决定了剩下的intent如何构建,特别是数据(data)和附加(extras)字段,就像一个方法名决定了参数和返回值。正是这个原因,应该尽可能明确指定动作,并紧密关联到其它intent字段。换句话说,应该定义你的组件能够处理的Intent对象的整个协议,而不仅仅是单独地定义一个动作。

一个intent对象的动作通过setAction()方法设置,通过getAction()方法读取。

2.3、数据

数据(data)是将作用于其上的数据的URI和数据的MIME类型。不同的动作有不同的数据规格。例如,如果动作字段是ACTION_EDIT,数据字段将包含将显示用于编辑的文档的URI;如果动作是ACTION_CALL,数据字段将是一个tel:URI和将拨打的号码;如果动作是ACTION_VIEW,数据字段是一个http:URI,接收活动将被调用去下载和显示URI指向的数据。

当匹配一个intent到一个能够处理数据的组件,通常知道数据的类型(它的MIME类型)和它的URI很重要。例如,一个组件能够显示图像数据,不应该被调用去播放一个音频文件。

在许多情况下,数据类型能够从URI中推测,特别是content:URIs,它表示位于设备上的数据且被内容提供者(content provider)控制。但是类型也能够显示地设置,setData()方法指定数据的URI,setType()指定MIME类型,setDataAndType()指定数据的URI和MIME类型。通过getData()读取URI,getType()读取类型。

2.4、种类

此外,还包含关于应该处理intent的组件类型信息。可以在一个Intent对象中指定任意数量的种类描述。Intent类定义的一些种类常量,如下这些:

Constant

Meaning

CATEGORY_BROWSABLE

The target activity can be safely invoked by the browser to display data referenced by a link — for example, an image or an e-mail message.

CATEGORY_GADGET

The activity can be embedded inside of another activity that hosts gadgets.

CATEGORY_HOME

The activity displays the home screen, the first screen the user sees when the device is turned on or when the HOME key is pressed.

CATEGORY_LAUNCHER

The activity can be the initial activity of a task and is listed in the top-level application launcher.

CATEGORY_PREFERENCE

The target activity is a preference panel.

更多的种类常量请参考Intent类。

addCategory()方法添加一个种类到Intent对象中,removeCategory()方法删除一个之前添加的种类,getCategories()方法获取Intent对象中的所有种类。

2.5、附加信息

额外的键值对信息应该传递到组件处理intent。就像动作关联的特定种类的数据URIs,也关联到某些特定的附加信息。例如,一个ACTION_TIMEZONE_CHANGE intent有一个"time-zone"的附加信息,标识新的时区,ACTION_HEADSET_PLUG有一个"state"附加信息,标识头部现在是否塞满或未塞满;有一个"name"附加信息,标识头部的类型。如果你自定义了一个SHOW_COLOR动作,颜色值将可以设置在附加的键值对中。

Intent对象有一系列的put…()方法用于插入各种附加数据和一系列的get…()用于读取数据。这些方法与Bundle对象的方法类似,实际上,附加信息可以作为一个Bundle使用putExtras()getExtras()安装和读取。

2.6、标志

有各种各样的标志,许多指示Android系统如何去启动一个活动(例如,活动应该属于那个任务)和启动之后如何对待它(例如,它是否属于最近的活动列表)。所有这些标志都定义在Intent类中。

3、Intent解析

Intent可以分为两组:

  • 显式intent:通过名字指定目标组件。因为开发者通常不知道其它应用程序的组件名字,显式intent通常用于应用程序内部消息,如一个活动启动从属的服务或启动一个姐妹活动。
  • 隐式intent:并不指定目标的名字(组件名字字段是空的)。隐式intent经常用于激活其它应用程序中的组件。

Android传递一个显式intent到一个指定目标类的实例。Intent对象中只用组件名字内容去决定哪个组件应该获得这个intent,而不用其他内容。

隐式intent需要另外一种不同的策略。由于缺省指定目标,Android系统必须查找一个最适合的组件(一些组件)去处理intent——一个活动或服务去执行请求动作,或一组广播接收者去响应广播声明。这是通过比较Intent对象的内容和intent过滤器(intent filters)来完成的。intent过滤器关联到潜在的接收intent的组件。过滤器声明组件的能力和界定它能处理的intents,它们打开组件接收声明的intent类型的隐式intents。如果一个组件没有任何intent过滤器,它仅能接收显示的intents,而声明了intent过滤器的组件可以接收显示和隐式的intents。

只有当一个Intent对象的下面三个方面都符合一个intent过滤器:action、data(包括URI和数据类型)、category,才被考虑。附加信息和标志在解析哪个组件接收intent中不起作用。

3.1、Intent过滤器

活动、服务、广播接收者为了告知系统能够处理哪些隐式intent,它们可以有一个或多个intent过滤器。每个过滤器描述组件的一种能力,即乐意接收的一组intent。实际上,它筛掉不想要的intents,也仅仅是不想要的隐式intents。一个显式intent总是能够传递到它的目标组件,不管它包含什么;不考虑过滤器。但是一个隐式intent,仅当它能够通过组件的过滤器之一才能够传递给它。

一个组件的能够做的每一工作有独立的过滤器。例如,记事本中的NoteEditer活动有两个过滤器,一个是启动一个指定的记录,用户可以查看和编辑;另一个是启动一个新的、空的记录,用户能够填充并保存。

一个intent过滤器是一个IntentFilter类的实例。因为Android系统在启动一个组件之前必须知道它的能力,但是intent过滤器通常不在java代码中设置,而是在应用程序的清单文件(AndroidManifest.xml)中以<intent-filter>元素设置。但有一个例外,广播接收者的过滤器通过调用Context.registerReceiver()动态地注册,它直接创建一个IntentFilter对象。

一个过滤器有对应于Intent对象的动作、数据、种类的字段。过滤器要检测隐式intent的所有这三个字段,其中任何一个失败,Android系统都不会传递intent给组件。然而,因为一个组件可以有多个intent过滤器,一个intent通不过组件的过滤器检测,其它的过滤器可能通过检测。

3.1.1、动作检测

清单文件中的<intent-filter>元素以<action>子元素列出动作,例如:

<intent-filter . . . >
    <action android:name="com.example.project.SHOW_CURRENT" />
    <action android:name="com.example.project.SHOW_RECENT" />
    <action android:name="com.example.project.SHOW_PENDING" />
    . . .
</intent-filter>

像例子所展示,虽然一个Intent对象仅是单个动作,但是一个过滤器可以列出不止一个。这个列表不能够为空,一个过滤器必须至少包含一个<action>子元素,否则它将阻塞所有的intents。

要通过检测,Intent对象中指定的动作必须匹配过滤器的动作列表中的一个。如果对象或过滤器没有指定一个动作,结果将如下:

  • 如果过滤器没有指定动作,没有一个Intent将匹配,所有的intent将检测失败,即没有intent能够通过过滤器。
  • 如果Intent对象没有指定动作,将自动通过检查(只要过滤器至少有一个过滤器,否则就是上面的情况了)

3.1.2、种类检测

类似的,清单文件中的<intent-filter>元素以<category>子元素列出种类,例如:

<intent-filter . . . >
    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />
    . . .
</intent-filter>

注意本文前面两个表格列举的动作和种类常量不在清单文件中使用,而是使用全字符串值。例如,例子中所示的"android.intent.category.BROWSABLE"字符串对应于本文前面提到的BROWSABLE常量。类似的,"android.intent.action.EDIT"字符串对应于ACTION_EDIT常量。

对于一个intent要通过种类检测,intent对象中的每个种类必须匹配过滤器中的一个。即过滤器能够列出额外的种类,但是intent对象中的种类都必须能够在过滤器中找到,只有一个种类在过滤器列表中没有,就算种类检测失败!

因此,原则上如果一个intent对象中没有种类(即种类字段为空)应该总是通过种类测试,而不管过滤器中有什么种类。但是有个例外,Android对待所有传递给Context.startActivity()的隐式intent好像它们至少包含"android.intent.category.DEFAULT"(对应CATEGORY_DEFAULT常量)。因此,活动想要接收隐式intent必须要在intent过滤器中包含"android.intent.category.DEFAULT"。

注意:"android.intent.action.MAIN" 和 "android.intent.category.LAUNCHER"设置,它们分别标记活动开始新的任务和带到启动列表界面。它们可以包含"android.intent.category.DEFAULT"到种类列表,也可以不包含。

3.1.3、数据检测

类似的,清单文件中的<intent-filter>元素以<data>子元素列出数据,例如:

<intent-filter . . . >
    <data android:mimeType="video/mpeg" android:scheme="http" . . . /> 
    <data android:mimeType="audio/mpeg" android:scheme="http" . . . />
    . . .
</intent-filter>

每个<data>元素指定一个URI和数据类型(MIME类型)。它有四个属性schemehostportpath对应于URI的每个部分:
scheme://host:port/path
例如,下面的URI:
content://com.example.project:200/folder/subfolder/etc
scheme是content,host是"com.example.project",port是200,path是"folder/subfolder/etc"。host和port一起构成URI的凭据(authority),如果host没有指定,port也被忽略。
这四个属性都是可选的,但它们之间并不都是完全独立的。要让authority有意义,scheme必须也要指定。要让path有意义,scheme和authority也都必须要指定。

当比较intent对象和过滤器的URI时,仅仅比较过滤器中出现的URI属性。例如,如果一个过滤器仅指定了scheme,所有有此scheme的URIs都匹配过滤器;如果一个过滤器指定了scheme和authority,但没有指定path,所有匹配scheme和authority的URIs都通过检测,而不管它们的path;如果四个属性都指定了,要都匹配才能算是匹配。然而,过滤器中的path可以包含通配符来要求匹配path中的一部分。

<data>元素的type属性指定数据的MIME类型。Intent对象和过滤器都可以用"*"通配符匹配子类型字段,例如"text/*","audio/*"表示任何子类型。

数据检测既要检测URI,也要检测数据类型。规则如下:

  • 一个Intent对象既不包含URI,也不包含数据类型:仅当过滤器也不指定任何URIs和数据类型时,才不能通过检测;否则都能通过。
  • 一个Intent对象包含URI,但不包含数据类型:仅当过滤器也不指定数据类型,同时它们的URI匹配,才能通过检测。例如,mailto:tel:都不指定实际数据。
  • 一个Intent对象包含数据类型,但不包含URI:仅当过滤也只包含数据类型且与Intent相同,才通过检测。
  • 一个Intent对象既包含URI,也包含数据类型(或数据类型能够从URI推断出):数据类型部分,只有与过滤器中之一匹配才算通过;URI部分,它的URI要出现在过滤器中,或者它有content:file: URI,又或者过滤器没有指定URI。换句话说,如果它的过滤器仅列出了数据类型,组件假定支持content:file:

如果一个Intent能够通过不止一个活动或服务的过滤器,用户可能会被问那个组件被激活。如果没有目标找到,会产生一个异常。

3.2、通用情况

上面最后一条规则表明组件能够从文件或内容提供者获取本地数据。因此,它们的过滤器仅列出数据类型且不必明确指出content:file: scheme的名字。这是一种典型的情况,一个<data>元素像下面这样:

<data android:mimeType="image/*" />

告诉Android这个组件能够从内容提供者获取image数据并显示它。因为大部分可用数据由内容提供者(content provider)分发,过滤器指定一个数据类型但没有指定URI或许最通用。

另一种通用配置是过滤器指定一个scheme和一个数据类型。例如,一个<data>元素像下面这样:

<data android:scheme="http" android:type="video/*" />

告诉Android这个组件能够从网络获取视频数据并显示它。考虑,当用户点击一个web页面上的link,浏览器应用程序会做什么?它首先会试图去显示数据(如果link是一个HTML页面,就能显示)。如果它不能显示数据,它将把一个隐式Intent加到scheme和数据类型,去启动一个能够做此工作的活动。如果没有接收者,它将请求下载管理者去下载数据。这将在内容提供者的控制下完成,因此一个潜在的大活动池(他们的过滤器仅有数据类型)能够响应。

大部分应用程序能启动新的活动,而不引用任何特别的数据。活动有指定"android.intent.action.MAIN"的动作的过滤器,能够启动应用程序。如果它们出现在应用程序启动列表中,它们也指定"android.intent.category.LAUNCHER"种类:

<intent-filter . . . >
    <action android:name="code android.intent.action.MAIN" />
    <category android:name="code android.intent.category.LAUNCHER" />
</intent-filter>

3.3、使用intent匹配

Intents对照着Intent过滤器匹配,不仅去发现一个目标组件去激活,而且去发现设备上的组件的其他信息。例如,Android系统填充应用程序启动列表,最高层屏幕显示用户能够启动的应用程序:是通过查找所有的包含指定了"android.intent.action.MAIN"的动作和"android.intent.category.LAUNCHER"种类的过滤器的活动,然后在启动列表中显示这些活动的图标和标签。类似的,它通过查找有"android.intent.category.HOME"过滤器的活动发掘主菜单。

我们的应用程序也可以类似的使用这种Intent匹配方式。PackageManager有一组query…()方法返回能够接收特定intent的所有组件,一组resolve…()方法决定最适合的组件响应intent。例如,queryIntentActivities()返回一组能够给执行指定的intent参数的所有活动,类似的queryIntentServices()返回一组服务。这两个方法都不激活组件,它们仅列出所有能够响应的组件。对应广播接收者也有类似的方法——queryBroadcastReceivers()

注:本文的主要内容意译自SDK文档。抱歉此系列的发文速度越来越来,主要是因为现在空闲时间很少,每天下班之后除了要写此系列的文章,还有其它知识需要总结并且还有为每天的工作做知识准备(大家应该也发现了我的blog最近发布了一些关于C++的文章)。其实我一直告诫自己,信息时代效率是关键(当然专注作为一种品质,任何时候都非常重要),如果效率一直这么低而且不够专注,将来Android 2.2、2.3甚至更高版本都发布了,我这系列的基础部分都还没有写完。我会尽量加快此系列的发文速度,当然我会保持一贯的作风——文章的内容要经过验证才会发布,尽可能保证内容的正确性,不过由于一个人的见识和天生的会陷入自我思维,错误在所难免!还希望大家及时指出,以免文章误导他人和让我一直错下去。


http://www.cnblogs.com/skynet/archive/2010/07/20/1781644.html
posted @ 2011-06-22 16:41 小果子 阅读(376) | 评论 (0)编辑 收藏
01.#include <iostream>  
02.#include <list>  
03.#include <boost/any.hpp>  
04. 
05.typedef std::list<boost::any> list_any;  
06. 
07.//关键部分:可以存放任意类型的对象  
08.void fill_list(list_any& la)  
09.{      
10.    la.push_back(10);//存放常数   
11.    la.push_back( std::string("dyunze") );//存放字符串对象;注意la.push_back(“dyunze”)错误,因为会被当错字符串数组  
12.}  
13. 
14.//根据类型进行显示  
15.void show_list(list_any& la)  
16.{  
17.    list_any::iterator it;  
18.    boost::any anyone;  
19. 
20.    for( it = la.begin(); it != la.end(); it++ )  
21.    {     
22.        anyone = *it;  
23. 
24.        if( anyone.type() == typeid(int) )  
25.            std::cout<<boost::any_cast<int>(*it)<<std::endl;  
26.        else if( anyone.type() == typeid(std::string) )  
27.            std::cout<<boost::any_cast<std::string>(*it).c_str()<<std::endl;  
28.    }  
29.}  
30. 
31.int main()  
32.{  
33.    list_any la;  
34.    fill_list(la);  
35.    show_list(la);  
36. 
37.    return 0;  
38.} 
#include <iostream>
#include <list>
#include <boost/any.hpp>

typedef std::list<boost::any> list_any;

//关键部分:可以存放任意类型的对象
void fill_list(list_any& la)
{   
    la.push_back(10);//存放常数
    la.push_back( std::string("dyunze") );//存放字符串对象;注意la.push_back(“dyunze”)错误,因为会被当错字符串数组
}

//根据类型进行显示
void show_list(list_any& la)
{
    list_any::iterator it;
    boost::any anyone;

    for( it = la.begin(); it != la.end(); it++ )
    {   
        anyone = *it;

        if( anyone.type() == typeid(int) )
            std::cout<<boost::any_cast<int>(*it)<<std::endl;
        else if( anyone.type() == typeid(std::string) )
            std::cout<<boost::any_cast<std::string>(*it).c_str()<<std::endl;
    }
}

int main()
{
    list_any la;
    fill_list(la);
    show_list(la);

    return 0;
}

boost::any的优点:

     对设计模式理解的朋友都会知道合成模式。因为多态只有在使用指针或引用的情况下才能显现,所以std容器中只能存放指针或引用(但实际上只能存放指针,无法存放引用,这个好像是c++的不足吧)。如:

     std::list<BaseClass*> mylist;

这样,我们就要对指针所指向内容的生存周期操心(可能需要程序员适时删除申请的内存;但是由于存放指针,插入/删除的效率高),而使用boost::any就可能避免这种情况,因为我们可以存放类型本身(当然存放指针也可以)。这是boost::any的优点之一。

    boost::any另一个优点是可以存放任何类型。而前面提到的mylist只能存放BaseClass类指针以及其继承类的指针。

boost::any的缺点:

    由于boost::any可以存放任何类型,自然它用不了多态特性,没有统一的接口,所以在获取容器中的元素时需要实现判别元素的真正类型,这增加了程序员的负担。与面向对象编程思想有些矛盾,但整个标准c++模板库何尝不是如此,用那些牛人的话来说,是“有益补充”。

   总之,有利必有弊,没有十全十美的。

  

分析并模仿boost::any:

     读了一下boost::any的源代码,并模仿一下其实现(相当一部分时拷贝原代码),下面是代码(只包含必要功能)。

实现any的功能主要由三部分组成:
1)any类
2)真正保存数据的holder类及其基类placeholder
3)获取真正数据的模板函数any_cast,类型转换的功能。

view plaincopy to clipboardprint?
01.#include <iostream>  
02.#include <list>  
03.#include <cassert>  
04. 
05.//自定义的any类  
06.class any  
07.{  
08.public:  
09.      
10.    //保存真正数据的接口类  
11.    class placeholder  
12.    {  
13.    public:       
14.        virtual ~placeholder()  
15.        {  
16.        }  
17.    public:   
18. 
19.        virtual const std::type_info & type() const = 0;  
20.        virtual placeholder * clone() const = 0;      
21.    };  
22. 
23.    //真正保存和获取数据的类。  
24.    template<typename ValueType>  
25.    class holder : public placeholder  
26.    {  
27.    public:           
28.        holder(const ValueType & value): held(value)  
29.        {  
30.        }  
31. 
32.    public:   
33. 
34.        virtual const std::type_info & type() const 
35.        {  
36.            return typeid(ValueType);  
37.        }  
38. 
39.        virtual placeholder * clone() const 
40.        {  
41.            return new holder(held);//使用了原型模式  
42.        }  
43. 
44.    public:   
45. 
46.        //真正的数据,就保存在这里  
47.        ValueType held;  
48.    };  
49. 
50.public:  
51. 
52.    any(): content(NULL)     
53.    {         
54.    }  
55. 
56.    //模板构造函数,参数可以是任意类型,真正的数据保存在content中  
57.    template<typename ValueType>  
58.    any(const ValueType & value): content(new holder<ValueType>(value))  
59.    {  
60.    }    
61. 
62.    //拷贝构造函数  
63.    any(const any & other)  
64.        : content(other.content ? other.content->clone() : 0)  
65.    {  
66.    }  
67. 
68.    //析构函数,删除保存数据的content对象  
69.    ~any()  
70.    {  
71.        if(NULL != content)  
72.            delete content;  
73.    }  
74. 
75.private:  
76.    //一个placeholde对象指针,指向其子类folder的一个实现  
77.    // 即content( new holder<ValueType>(value) )语句  
78.    placeholder* content;  
79. 
80.    template<typename ValueType> friend ValueType any_cast(const any& operand);  
81.public:   
82. 
83.    //查询真实数据的类型。  
84.    const std::type_info & type() const 
85.    {  
86.        return content ? content->type() : typeid(void);  
87.    }  
88.};  
89. 
90. 
91.//获取content->helder数据的方法。用来获取真正的数据  
92.template<typename ValueType>  
93.ValueType any_cast(const any& operand)  
94.{  
95.    assert( operand.type() == typeid(ValueType) );  
96.    return static_cast<any::holder<ValueType> *>(operand.content)->held;  
97.}  
98. 
99.//下代码是使用示例  
100. 
101.typedef std::list<any> list_any;  
102. 
103.void fill_list(list_any& la)  
104.{      
105.    la.push_back(10);//存放常数;调用了any的模板构造函数,下同  
106.    la.push_back( std::string("我是string") );//存放字符串对象;注意la.push_back(“dyunze”)错误,因为会被当错字符串数组  
107. 
108.    char* p = "我是常量区字符串abc";  
109.    la.push_back(p);//可以存放指针,但要注意指针的失效问题  
110.}  
111. 
112.//根据类型进行显示  
113.void show_list(list_any& la)  
114.{  
115.    list_any::iterator it;  
116. 
117.    for( it = la.begin(); it != la.end(); it++ )  
118.    {     
119. 
120.        if( (*it).type() == typeid(int) )  
121.            std::cout<<any_cast<int>(*it)<<std::endl;  
122.        else if( (*it).type() == typeid(std::string) )  
123.            std::cout<<any_cast<std::string>(*it).c_str()<<std::endl;  
124.        else if( (*it).type() == typeid(char*) )  
125.            std::cout<<any_cast<char*>(*it)<<std::endl;  
126.    }  
127.}  
128. 
129.int main()  
130.{  
131.    list_any la;  
132.    fill_list(la);  
133.    show_list(la);  
134. 
135.    return 0;  
136.} 

 boost::any是一个很有趣的类,刚刚开始我还以为其就是一个variant类型,
能够将任意类型值保存进去,能够以任意类型值读出来,不过我错了 :(
  boost::any的作者认为,所谓generic type有三个层面的解释方法:
  1.类似variant类型那样任意进行类型转换,可以保存一个(int)5进去,
    读一个(string)"5"出来。Win下面的VARIANT类型是以一个巨大的
    union实现的类似功能,使用灵活但效率较低
  2.区别对待包含值的类型,保存一个(int)5进去,不会被隐式转换为
    (string)'5'或者(double)5.0,这样效率较高且类型安全,
    不必担心ambiguous conversions
  3.对包含值类型不加区别,例如把所有保存的值强制转换为void *保存
    读取时再有程序员判断其类型。这样效率虽最高但无法保证类型安全
  boost::any就选择了第二层面的设计思路,它允许用户将任意类型值保存
进一个any类型变量,但内部并不改变值的类型,并提供方法让用户在使用时
主动/被动进行类型判断。

  在实现方面,boost::any使用两层内部类placeholder和holder保存
实际类型的值。类placeholder只是一个接口,模板类holder是特定类型
的实现。其中type()方法获取实际值类型,即typeid(ValueType);
clone()方法获取值的拷贝return new holder(held);
  virtual const std::type_info & type() const
  virtual placeholder * clone() const
  其值的类型信息不象Win的VARIANT那样以专门的字段保存,
而是通过模板参数形式静态保存。这样效率更高(仅在编译期),

通用性更强(任何类型都可以,真正any)但灵活性不如VARIANT
  在进行拷贝构造/赋值/swap时,都直接将整个placeholder换掉,
这样可以保证值类型的延续性。

  在使用方面,提供了主动/被动进行类型检测的方法。
  可以使用any::type()方法主动检测值类型
bool is_int(const boost::any & operand)
{
    return operand.type() == typeid(int);
}
  也可以通过any_cast函数被动进行检测。此函数与C++中的*_cast
系列关键字有相同的语法规范,尝试进行类型转换,如类型不匹配则对
指针转换返回NULL,对引用转换抛出boost::bad_any_cast异常
  boost::any str = string("12345");
  try
  {
    cout << boost::any_cast<int>(str) << endl;
  }
  catch(boost::bad_any_cast e)
  {
    cerr << e.what() << endl;
  }


  在应用方面,any类型适合于类型不同但使用相关的值。如C++的...
形式的函数参数本事不是类型安全的,可以通过vector<any>改造之
然后在使用时检测类型是否匹配,如可改造printf为
  void safe_printf(const char *format, const vector<any>& params)
  {
    int index = 0;
    for(const char *pch = format; *pch; pch++)
    {
      switch(*pch)
      {
        case '%':
        {
          switch(*++pch)
          {
            case 'i':
            case 'd':
            {
              if(params[index].type() == typeid(int) ||
                 params[index].type() == typeid(short))
              {
                ...
              }
              else
                throw ...
            }
          }
        }
        case '\':
        {
          ...
        }
        default:
        {
          putchar(*pch);
        }
      }
    }
  }

附:boost::any.hpp
#ifndef BOOST_ANY_INCLUDED
#define BOOST_ANY_INCLUDED

// what:  variant type boost::any
// who:   contributed by Kevlin Henney,
//        with features contributed and bugs found by
//        Ed Brey, Mark Rodgers, Peter Dimov, and James Curran
// when:  July 2001
// where: tested with BCC 5.5, MSVC 6.0, and g++ 2.95

#include <algorithm>
#include <typeinfo>

#include "boost/config.hpp"

namespace boost
{
    class any
    {
    public: // structors

        any()
          : content(0)
        {
        }

        template<typename ValueType>
        any(const ValueType & value)
          : content(new holder<ValueType>(value))
        {
        }

        any(const any & other)
          : content(other.content ? other.content->clone() : 0)
        {
        }

        ~any()
        {
            delete content;
        }

    public: // modifiers

        any & swap(any & rhs)
        {
            std::swap(content, rhs.content);
            return *this;
        }

        template<typename ValueType>
        any & operator=(const ValueType & rhs)
        {
            any(rhs).swap(*this);
            return *this;
        }

        any & operator=(const any & rhs)
        {
            any(rhs).swap(*this);
            return *this;
        }

    public: // queries

        bool empty() const
        {
            return !content;
        }

        const std::type_info & type() const
        {
            return content ? content->type() : typeid(void);
        }

#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
    private: // types
#else
    public: // types (public so any_cast can be non-friend)
#endif


        class placeholder
        {
        public: // structors
    
            virtual ~placeholder()
            {
            }

        public: // queries

            virtual const std::type_info & type() const = 0;

            virtual placeholder * clone() const = 0;
    
        };

        template<typename ValueType>
        class holder : public placeholder
        {
        public: // structors

            holder(const ValueType & value)
              : held(value)
            {
            }

        public: // queries

            virtual const std::type_info & type() const
            {
                return typeid(ValueType);
            }

            virtual placeholder * clone() const
            {

                return new holder(held);
            }

        public: // representation

            ValueType held;

        };

#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS

    private: // representation

        template<typename ValueType>
        friend ValueType * any_cast(any *);

#else

    public: // representation (public so any_cast can be non-friend)

#endif

        placeholder * content;

    };

    class bad_any_cast : public std::bad_cast
    {
    public:
        virtual const char * what() const throw()
        {
            return "boost::bad_any_cast: "
                   "failed conversion using boost::any_cast";
        }
    };

    template<typename ValueType>
    ValueType * any_cast(any * operand)
    {
        return operand && operand->type() == typeid(ValueType)
                    ? &static_cast<any::holder<ValueType> *>(operand->content)->held
                    : 0;
    }

    template<typename ValueType>
    const ValueType * any_cast(const any * operand)
    {
        return any_cast<ValueType>(const_cast<any *>(operand));
    }

    template<typename ValueType>
    ValueType any_cast(const any & operand)
    {
        const ValueType * result = any_cast<ValueType>(&operand);
        if(!result)
            throw bad_any_cast();
        return *result;
    }

}

// Copyright Kevlin Henney, 2000, 2001, 2002. All rights reserved.
//
// Permission to use, copy, modify, and distribute this software for any
// purpose is hereby granted without fee, provided that this copyright and
// permissions notice appear in all copies and derivatives.
//
// This software is provided "as is" without express or implied warranty.

#endif

posted @ 2011-06-16 18:32 小果子 阅读(832) | 评论 (0)编辑 收藏
ActionScript 3.0中,可以创建位图图像,还可以把外部的位图图像加载到Flash Player中。使用位图类,可以处理位图的像素和杂点。通过滤镜类,还可以增加位图的各种滤镜效果。
19.1  位图类
常用的有关位图的类有三个:Bitmap类、BitmapData类和BitmapDataChannel类。Bitmap类用来显示位图图像,BitmapData类用来处理位图,BitmapDataChannel类是个枚举值,表示使用的通道。
 19.1.1  Bitmap
Bitmap类表示位图图像的显示对象。可以使用Bitmap类的构造函数创建图像,也可以使用Loader类加载外部图像。Bitmap类常用的属性如表19.1所示。
表19.1  Bitmap类常用的属性
   
   
bitmapData
被引用的BitmapData对象
pixelSnapping
控制Bitmap对象是否贴紧至最近的像素
smoothing
控制在缩放时是否对位图进行平滑处理
 19.1.2  BitmapData
BitmapData类用来处理Bitmap对象的数据。BitmapData类可以在程序运行时,任意调整位图的大小、透明度、像素等。BitmapData类常用的属性如表19.2所示,常用的方法如表19.3所示。
表19.2  BitmapData类常用的属性
   
   
height
位图图像的高度
rect
定义位图图像大小和位置的矩形
transparent
定义位图图像是否支持每个像素具有不同的透明度
width
位图图像的宽度
表19.3  BitmapData对象常用的方法
   
   
applyFilter
取得一个源图像和一个滤镜对象,并生成过滤的图像
clone
返回一个新的BitmapData对象,它是对原始实例的克隆,包含与原始实例所含位图完全相同的副本
colorTransform
使用ColorTransform对象调整位图图像的指定区域中的颜色值
compare
比较两个BitmapData对象
copyChannel
将数据从另一个BitmapData对象或当前BitmapData对象的一个通道传输到当前BitmapData对象的某个通道中
copyPixels
为没有拉伸、旋转或色彩效果的图像之间的像素处理提供一个快速例程
dispose
释放用来存储BitmapData对象的内存
draw
使用Flash Player矢量渲染器在位图图像上绘制source显示对象
fillRect
使用指定的ARGB颜色填充一个矩形像素区域
floodFill
对图像执行倾倒填充操作,从(x, y)坐标开始,填充一种特定的颜色
generateFilterRect
已知BitmapData对象、源矩形和滤镜对象,确定applyFilter()方法调用所影响的目标矩形
getColorBoundsRect
确定矩形区域是将位图图像中指定颜色的所有像素完全包括起来(如果将findColor参数设置为true),还是将不包括指定颜色的所有像素完全包括起来(如果将findColor参数设置为false
getPixel
返回一个整数,它表示BitmapData对象中在特定点(x, y 处的RGB 像素值
getPixel32
返回一个ARGB颜色值,它包含Alpha通道数据和RGB数据
getPixels
从像素数据的矩形区域生成一个字节数组
hitTest
在一个位图图像与一个点、矩形或其他位图图像之间执行像素级的点击检测 
lock
锁定图像,以使引用BitmapData对象的任何对象(如Bitmap对象)在此BitmapData对象更改时不会更新
merge
对每个通道执行从源图像向目标图像的混合
noise
使用表示随机杂点的像素填充图像
paletteMap
重新映射一个具有最多四组调色板数据(每个通道一组)的图像中的颜色通道值
perlinNoise
生成Perlin杂点图像
pixelDissolve
执行源图像到目标图像的像素溶解,或使用同一图像执行像素溶解
scroll
按某一(x, y)像素量滚动图像
setPixel
设置BitmapData对象的单个像素
setPixel32
设置BitmapData对象单个像素的颜色和Alpha透明度值
setPixels
将字节数组转换为像素数据的矩形区域
threshold
根据指定的阈值测试图像中的像素值,并将通过测试的像素设置为新的颜色值
unlock
解除锁定图像,以使引用BitmapData对象的任何对象(如Bitmap对象)在此BitmapData对象更改时更新
 19.1.3  创建位图类
通常情况下,Bitmap类和BitmapData类是结合在一起使用的。Bitmap类的构造函数的语法格式如下所示:
Bitmap(bitmapData:BitmapData = null, pixelSnapping:String = "auto", smoothing:Boolean = false)
其各个参数的说明如下。
—  bitmapData:被引用的BitmapData对象。
—  pixelSnapping:默认值为auto,表示Bitmap对象是否贴紧至最近的像素。
—  smoothing:默认值为false,表示在缩放时是否对位图进行平滑处理。
BitmapData类的构造函数的语法格式如下所示:
BitmapData(width:int, height:int, transparent:Boolean = true, fillColor:uint = 0xFFFFFFFF)
其各个参数的说明如下。
—  width:位图图像的宽度,以像素为单位。
—  height:位图图像的高度,以像素为单位。
—  transparent:指定位图图像是否支持每个像素具有不同的透明度。
—  fillColor:用于填充位图图像区域的32位ARGB颜色值。
下面的示例使用两个位图类,创建一个矩形,代码如下所示:
package 
{
    import flash.display.Sprite;
    import flash.display.Bitmap;
    import flash.display.BitmapData;
   
    public class BitmapExample extends Sprite
    {
        /********************
         * 构造函数
         * */
        public function BitmapExample(
)
        {
            // 创建BitmapData类
            var bitmap:BitmapData = new BitmapData(400, 300, true, 0x500066FF);
           
            // 创建Bitmap类
            var image:Bitmap = new Bitmap(bitmap);
            // 设置显示位置
            image.x = 90;
            image.y = 50;
           
            // 增加到舞台
            addChild(image);
        }
    }
   
}
编译代码并运行,结果如图19.1所示。
图19.1  创建位图类
 19.1.4  加载外部图像
除了在内部创建位图之外,还可以加载外部的图像到位图中。加载外部的图像,需要用到Loader对象。通过Loader对象的load()方法,可以加载外部的URL。下面的示例使用Loader对象,加载外部图像到位图中,代码如下所示:
package 
{
    import flash.display.Sprite;
    import flash.display.Loader;
    import flash.events.Event;
    import flash.net.URLRequest;
    import flash.display.Bitmap;
    import flash.display.BitmapData;
   
    public class BitmapExample extends Sprite
    {
        private var loader:Loader = new Loader();
        /********************
         * 构造函数
         * */
        public function BitmapExample()
        {
            // 侦听数据加载
            loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onComplete);
            // 外部图像URL
            loader.load(new URLRequest("Bitmap.jpg"));
        }
        /********************
         * 加载外部图像到位图
         * */
        public function onComplete(event:Event):void
        {
            // 创建位图
            var image:Bitmap = Bitmap(loader.content);
            var bitmap:BitmapData = image.bitmapData;
            addChild(image);
           
            // 设置
            image.x = 20;
            image.y = 30;
        }
    }
   
}
编译代码并运行,结果如图19.2所示。
图19.2  加载外部图像
19.2  像素的处理
BitmapData类中,包含了一组用于像素处理的方法。使用这些方法可以处理单个像素,还可以处理像素数组。
 19.2.1  处理单个像素
处理单个像素用到的方法包括:getPixel()、getPixel32()、setPixel()和setPixel32()。
1getPixel()方法
getPixel()方法表示在指定的点获取位图的RGB像素。此方法有两个参数,分别是指定点的横坐标和纵坐标。其语法格式如下所示:
getPixel(x:int, y:int):uint
参数的详细说明如下。
—  x:指定点的横坐标。
—  y:指定点的纵坐标。
下面的示例使用getPixel()方法获取点(1,1)的RGB像素值,代码如下所示:
package 
{
    import flash.display.Sprite;
    import flash.display.Bitmap;
    import flash.display.BitmapData;
   
    public class BitmapExample extends Sprite
    {
        /********************
         * 构造函数
         * */
        public function BitmapExample()
        {
            // 创建BitmapData类
            var bitmap:BitmapData = new BitmapData(400, 300, false, 0xCC66FF);
           
            // 设置像素
            var i:uint = bitmap.getPixel(1, 1);
           
            // 输出获取的像素
            trace(i.toString(16));
        }
    }
   
}
编译代码并运行,输出的效果如图19.3所示。
图19.3  使用getPixel()方法处理单个像素
2getPixel32()方法
getPixel32()方法与getPixel()方法类似,区别是getPixel32()方法返回一个ARGB的像素值。其中返回值包含了透明度的值。其语法格式如下所示:
getPixel32(x:int, y:int):uint
参数的详细说明如下。
—  x:指定点的横坐标。
—  y:指定点的纵坐标。
下面的示例使用getPixel32()方法,返回指定点的像素值,代码如下所示:
package 
{
    import flash.display.Sprite;
    import flash.display.Bitmap;
    import flash.display.BitmapData;
   
    public class BitmapExample extends Sprite
    {
        /********************
         * 构造函数
         * */
        public function BitmapExample()
        {
            // 创建BitmapData类
            var bitmap:BitmapData = new BitmapData(400, 300, true, 0x50CC66FF);
           
            // 设置像素
            var i:uint = bitmap.getPixel32(1, 1);
           
            // 输出获取的像素
            trace(i.toString(16));
        }
    }
   
}
编译代码并运行,输出的结果如图19.4所示。
图19.4  使用getPixel32()方法处理单个像素
3setPixel()方法
setPixel()方法用来设置BitmapData对象的单个像素。此方法有三个参数,前两个参数表示要设置单个像素的点,第三个参数color表示生成的像素RGB颜色。其语法格式如下所示:
setPixel(x:int, y:int, color:uint):void
参数的详细说明如下所示:
—  x:像素值会更改的像素的x位置。
—  y:像素值会更改的像素的y位置。
—  color:生成的像素的RGB颜色。
下面的示例使用setPixel()方法,循环设置某些点的像素的RGB颜色,代码如下所示:
package 
{
    import flash.display.Sprite;
    import flash.display.Bitmap;
    import flash.display.BitmapData;
   
    public class BitmapExample extends Sprite
    {
        /********************
         * 构造函数
         * */
        public function BitmapExample()
        {
            // 创建BitmapData类
            var bitmap:BitmapData = new BitmapData(400, 300, false, 0x000066FF);
           
            // 设置像素
            for(var i:uint = 0; i < 300; i++)
            {
                bitmap.setPixel(20, i, 0xFFFFFF);
                bitmap.setPixel(80, i, 0x000000);
                bitmap.setPixel(160, i, 0x00CC00);
            }
           
            // 创建Bitmap类
            var image:Bitmap = new Bitmap(bitmap);
            // 设置显示位置
            image.x = 90;
            image.y = 50;
           
            // 增加到舞台
            addChild(image);
        }
    }
   
}
编译代码并运行,结果如图19.5所示。
图19.5  setPixel()方法处理单个像素
4setPixel32()方法
setPixel32()方法与setPixel()方法类似,不同的是,setPixel32()方法是设置ARGB(其中A表示透明度)的像素值。此方法的前两个参数与setPixel()方法相同,最后一个参数表示生成的像素的ARGB颜色。其语法格式如下所示:
setPixel32(x:int, y:int, color:uint):void
参数的详细说明如下所示:
—  x:像素值会更改的像素的x位置。
—  y:像素值会更改的像素的y位置。
—  color:生成的像素的ARGB颜色。
下面的示例使用setPixel32()方法,循环设置某些点的像素值,代码如下所示:
package 
{
    import flash.display.Sprite;
    import flash.display.Bitmap;
    import flash.display.BitmapData;
   
    public class BitmapExample extends Sprite
    {
        /********************
         * 构造函数
         * */
        public function BitmapExample()
        {
            // 创建BitmapData类
            var bitmap:BitmapData = new BitmapData(400, 300, true, 0x700066FF);
           
            // 设置像素
            for(var i:uint = 0; i < 300; i++)
            {
                bitmap.setPixel32(20, i, 0x20FF0000);
                bitmap.setPixel32(21, i, 0x40FF0000);
                bitmap.setPixel32(22, i, 0x60FF0000);
                bitmap.setPixel32(23, i, 0x80FF0000);
                bitmap.setPixel32(24, i, 0x00FF0000);
            }
           
            // 创建Bitmap类
            var image:Bitmap = new Bitmap(bitmap);
            // 设置显示位置
            image.x = 90;
            image.y = 50;
           
            // 增加到舞台
            addChild(image);
        }
    }
   
}
编译代码并运行,结果如图19.6所示。
图19.6  使用setPixel32()方法处理单个像素
 19.2.2  处理多个像素
ActionScript 3.0除了能处理单个像素外,还能处理多个像素。处理多个像素,一般是与字节数组有关的,把字节数组与像素的矩形区域相互转换。与处理多个元素有关的方法有两个:getPixels()和setPixels()。
1getPixels()方法
getPixels()方法将像素的矩形区域转换为一个字节数组并返回。getPixels()方法有一个参数,表示当前BitmapData对象中的一个矩形区域。其语法格式如下所示:
getPixels(rect:Rectangle):ByteArray
下面的示例使用getPixels()方法获取矩形区域的像素值,代码如下所示:
package 
{
    import flash.display.Sprite;
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.geom.Rectangle;
    import flash.utils.ByteArray;
   
    public class BitmapExample extends Sprite
    {
        /********************
         * 构造函数
         * */
        public function BitmapExample()
        {
            // 创建BitmapData类
            var bitmap:BitmapData = new BitmapData(400, 300, true, 0x700066FF);
           
            var bounds:Rectangle = new Rectangle(0, 0,bitmap.width, bitmap.height);
            var pixels:ByteArray = bitmap.getPixels(bounds);
            trace("像素数组的长度" + pixels.length);
            trace("以下是取几个元素的值:");
            trace(pixels[0]);
            trace(pixels[4]);
            trace(pixels[6]);
            trace(pixels[10]);
        }
    }
   
}
编译代码并运行,输出的结果如图19.7所示。
图19.7  使用getPixels()方法处理多个像素
2setPixels()方法
setPixels()方法将字节数组转换为像素的矩形区域。其语法格式如下所示:
 setPixels(rect:Rectangle, inputByteArray:ByteArray):void
参数说明如下。
—  rect:指定BitmapData对象的矩形区域。
—  inputByteArray:一个字节数组对象,由要在矩形区域中使用的32位未经过相乘的像素值组成。
package 
{
    import flash.display.Sprite;
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.geom.Rectangle;
    import flash.utils.ByteArray;
   
    public class BitmapExample extends Sprite
    {
        /********************
         * 构造函数
         * */
        public function BitmapExample()
        {
            // 创建BitmapData对象
            var bmd1:BitmapData = new BitmapData(200, 200, true, 0xFFCCCCCC);
            var bmd2:BitmapData = new BitmapData(200, 200, true, 0xFFFF0000);
            // 创建获取像素的矩形区域
            var rect:Rectangle = new Rectangle(20, 20, 150, 150);
            var bytes:ByteArray = bmd1.getPixels(rect);
            // 设置像素
            bytes.position = 0;
            bmd2.setPixels(rect, bytes);
            // 创建Bitmap对象
            var bm1:Bitmap = new Bitmap(bmd1);
            addChild(bm1);
            var bm2:Bitmap = new Bitmap(bmd2);
            addChild(bm2);
           
            // 设置位置
            bm1.x = 50;
            bm1.y = 100;
            bm2.x = 260;
            bm2.y = 100;
        }
    }
   
}
编译代码并运行,结果如图19.8所示。

http://leo398.blog.51cto.com/658992/341950
posted @ 2011-06-10 17:39 小果子 阅读(8719) | 评论 (0)编辑 收藏
仅列出标题
共58页: First 23 24 25 26 27 28 29 30 31 Last