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 小果子 閱讀(298) |
評論 (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 小果子 閱讀(566) |
評論 (0) |
編輯 收藏
引言
大部分移動設備平臺上的應用程序都運行在他們自己的沙盒中。他們彼此之間互相隔離,并且嚴格限制應用程序與硬件和原始組件之間的交互。 我們知道交流是多么的重要,作為一個孤島沒有交流的東西,一定毫無意義!Android應用程序也是一個沙盒,但是他們能夠使用Intent、Broadcast Receivers、Adapters、Content Providers、Internet去突破他們的邊界互相交流。有交流還會和諧,由此可見這些交流手段有多重要。
上篇文章中我們在SMS接收程序和使用Intent發送SMS程序中用到了Intent,并做了簡單的回顧和總結:android應用程序的三大組件——Activities、Services、Broadcast Receiver,通過消息觸發,這個消息就稱作意圖(Intent)。然后以活動為例簡單介紹了Intent了并說明Intent機制的好處。既然在SMS程序中用到了Intent,這里我就借機順著這條線,徹底詳細地介紹一下Intent。分兩篇文章介紹:
- Android開發之旅: Intents和Intent Filters(理論部分)
- 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、概述
一個應用程序的三個核心組件——activities、services、broadcast 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類型)。它有四個屬性scheme、host、port、path對應于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 小果子 閱讀(383) |
評論 (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 小果子 閱讀(859) |
評論 (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()。
1.getPixel()方法
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()方法處理單個像素
2.getPixel32()方法
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()方法處理單個像素
3.setPixel()方法
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()方法處理單個像素
4.setPixel32()方法
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()。
1.getPixels()方法
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()方法處理多個像素
2.setPixels()方法
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 小果子 閱讀(8813) |
評論 (0) |
編輯 收藏