大重美幸の「これ見落としてませんか? ActionScript 3.0」

第8回 TextBlockクラスでグラフィックを取り込んだ文字表現

前回は新テキストエンジンを利用するTextBlockクラスにテキストを表示する方法を紹介しました。今回はグラフィックエレメント、グループエレメント、タブ揃えを紹介します。少しばかり面倒に見えるTextBlockクラスですが、テキストフィールドでは難しいアニメーションやレイアウトもTextBlockクラスを使えば簡単です。TextBlockクラスの真価をお見せしましょう。

サンプルファイル : edge_oshige_08_sample_fla.zip (47KB)

テキストブロックにグラフィックエレメントを入れて取り出す

TextBlockクラスはテキストだけでなく絵を扱うこともできます。基本的な考え方は前回説明したテキストを表示する場合と同じで、テキストエレメントの代わりにグラフィックエレメントを作ります。次のサンプルはその方法を示すもっとも簡単な例です。


//猫のムービークリップインスタンスを作る
var cat:MovieClip = new catface();
//エレメントフォーマット
var foramat:ElementFormat = new ElementFormat();
//グラフィックエレメントを作る
var graphicElement:GraphicElement = new GraphicElement(cat, cat.width, cat.height, foramat);

次にテキストブロックをTextBlockクラスで作り、グラフィックエレメントをテキストブロックのcontentプロパティに設定します。


//グラフィックエレメントをコンテンツとして設定する
textBlock.content = graphicElement;

前回も説明したようにテキストブロックは表示オブジェクトではないので、テキストブロックをそのままステージに表示することはできません。テキストブロックに入れたグラフィックエレメントを表示するには、テキストブロックからcreateTextLine()を使って1行分のテキストラインを取り出して表示します。


//テキストラインを作って表示する
var textLine:TextLine = textBlock.createTextLine(null, cat.width);

このテキストラインtextLineは表示オブジェクトなので、MovieClipやSpriteのインスタンスと同じように拡大縮小や回転もできます。ここでは縦横2倍、回転角度30度で表示しています。

30度だけ回転して表示
fig1 テキストブロックに入れておいたグラフィックエレメントを取り出して2倍に拡大し、
30度だけ回転して表示しています

[sample] GraphicElement_sample.fla
テキストブロックに入れたグラフィックエレメントからテキストラインを作って表示します。

//猫のムービークリップインスタンスを作る
var cat:MovieClip = new catface();
//エレメントフォーマット
var foramat:ElementFormat = new ElementFormat();
//グラフィックエレメントを作る
var graphicElement:GraphicElement = new GraphicElement(cat, cat.width, cat.height, foramat);
//テキストブロックを作る
var textBlock:TextBlock = new TextBlock();
//グラフィックエレメントをコンテンツとして設定する
textBlock.content = graphicElement;
//テキストラインを作って表示する
var textLine:TextLine = textBlock.createTextLine(null, cat.width);
textLine.x=100;
textLine.y=200;
textLine.scaleX = textLine.scaleY = 2;
textLine.rotation = 30;
addChild(textLine);

複数のグラフィックエレメントをグループエレメントにまとめる

グラフィックエレメントの表示方法を説明しましたが、一度テキストブロックに入れて、そこからまた取り出して表示するという操作が無意味に見えるかもしれません。何より、これならばそのままムービークリップインスタンスを表示する方がはるかに簡単です。
TextBlockクラスを使うメリットが発揮されるのは、複数のグラフィックエレメントを扱うときです。そうは言ってもテキストブロックのcontentプロパティに設定できるエレメントは1個だけです。ここで登場するのが複数のグラフィックエレメントを1個のエレメントにまとめるグループエレメントです。グループエレメントはGroupElementクラスで作ります。


//グループエレメントを作る
var groupElement:GroupElement = new GroupElement(groupVector);

グループ化したい複数のエレメントを引数にしてインスタンスを作るわけですが、複数のエレメントを指定する引数はベクターで指定します。ベクターはVectorクラスで作り、保管する値のタイプ(ベース型)と個数を指定できる配列です。GroupElementクラスの引数はベース型がContentElementクラスのベクターです。


//グループ化するエレメントのベクターを作る
var groupVector:Vector.<ContentElement> = new Vector.<ContentElement>(mclist.length, true);

このベクターにムービークリップから作ったグラフィックエレメントを設定していきます。


//ベクターに値を設定
groupVector[i]=graphicElement;

なお、次のサンプルでは10個のムービークリップシンボルのクラス名を配列mclistに入れておき、順に名前を取り出してgetDefinitionByName()を使ってクラス参照を作成し、ムービークリップインスタンスを作っています。


//ムービークリップインスタンスを作る
var mc:MovieClip = new (getDefinitionByName(mclist[i]) as Class);

グループエレメントgroupElementができたならば、ここからは今までと同じです。テキストブロックtextBlockを作り、contentプロパティにgroupElementを指定します。そしてcreateTextLine()を使ってtextBlockからテキストラインtextLineを作り、テキストラインを1行ずつ並べて表示します。
テキストブロックには1個にグループ化された10個のグラフィックエレメントがコンテンツとして入っているわけですが、createTextLine()の引数で指定したテキストラインの行幅に入るように、自動的にグラフィックエレメントが並びます。試しにテキストラインの行幅lineWidthを300にして実行した場合と行幅lineWidthを350にした場合を比較するとその違いがわかります。

行幅を300にしてテキストラインを作った場合 行幅を350にした場合
fig2 行幅を300にしてテキストラインを作った場合(左)と行幅を350にした場合(右)。
行幅に合わせて絵の並びが折り返しているのがわかります

[sample] GroupElement_sample1.fla
複数のグラフィックエレメントをグループ化してテキストブロックに納めます。

var mclist:Array = ["baby","bin","biolin","bonsai","charch","cocktail","daia","flower","kayaributa","manekiNeko"];
//グループ化するエレメントのベクターを作る
var groupVector:Vector.<ContentElement> = new Vector.<ContentElement>(mclist.length, true);
for (var i:int=0; i<mclist.length; i++) {
	//ムービークリップインスタンスを作る
	var mc:MovieClip = new (getDefinitionByName(mclist[i]) as Class);
	//グラフィックエレメントを作る
	var graphicElement:GraphicElement = new GraphicElement(mc,mc.width*1.3,mc.height,new ElementFormat());
	//ベクターに値を設定する
	groupVector[i]=graphicElement;
}
//グループエレメントを作る
var groupElement:GroupElement = new GroupElement(groupVector);
//テキストブロックを作る
var textBlock:TextBlock = new TextBlock();
//テキストブロックのコンテンツにグループエレメントを設定する
textBlock.content = groupElement;
//テキストラインの行幅
var lineWidth:Number = 300;
//var lineWidth:Number = 350;
//テキストブロックから最初のテキストラインを取り出して表示する
var textLine:TextLine = textBlock.createTextLine(null,lineWidth);
var pos:Point = new Point(50,100);
//テキストブロックからテキストラインを繰り返し取り出して表示する
while (textLine !=null) {
	textLine.x = pos.x;
	textLine.y = pos.y ;
	addChild(textLine);
	pos.y += textLine.height;
	textLine = textBlock.createTextLine(textLine,lineWidth);
}

テキストエレメントとグラフィックエレメントをグループ化する

複数のグラフィックエレメントを1個にグループ化して表示する方法を示しましたが、これと同じようにテキストエレメントとグラフィックエレメントを1個のグループエレメントにまとめることもできます。次のサンプルでは3個のグラフィックエレメント(grph1、grph2、grph3)と6個のテキストエレメント(str1、str2、str3、name1、name2、name3)を1個のグループエレメントgroupElementにまとめてテキストボックスのコンテンツに設定しています。


//グループ化するエレメントのベクターを作る
var groupVector:Vector.<ContentElement> = new Vector.<ContentElement>();
groupVector.push(str1,grph1,name1,grph2,name2,str2,grph3,name3,str3);
//グループエレメントを作る
var groupElement:GroupElement = new GroupElement(groupVector);

グラフィックエレメントとテキストエレメントをまとめてグループエレメント
fig3 グラフィックエレメントとテキストエレメントをまとめてグループエレメント

ここで勘のいい人はひらめいたことでしょう。複数のグループエレメントをさらに1個のグループエレメントにしたり、グループエレメントをテキストエレメントやグラフィックエレメントとグルーピングして新たなグループエレメントを作ったりすることもできます。そうです。自在にグループエレメントを組み合わせてコンテンツを組み上げることができるわけです。

[sample] GroupElement_sample2.fla
グラフィックエレメントとテキストエレメントをまとめてグループエレメントを作ります。

//グラフィックエレメントを作る
var mc1:MovieClip = new bonsai();
var mc2:MovieClip = new kayaributa();
var mc3:MovieClip = new manekiNeko();
var grphElementFmt:ElementFormat = new ElementFormat();
grphElementFmt.dominantBaseline = TextBaseline.IDEOGRAPHIC_CENTER;
var grph1:GraphicElement = new GraphicElement(mc1,mc1.width*1.3,mc1.height,grphElementFmt);
var grph2:GraphicElement = new GraphicElement(mc2,mc2.width*1.3,mc2.height,grphElementFmt);
var grph3:GraphicElement = new GraphicElement(mc3,mc3.width*1.3,mc3.height,grphElementFmt);
//テキストエレメントを作る
var strElementFmt:ElementFormat = new ElementFormat();
strElementFmt.fontSize = 20;
var nameElementFmt:ElementFormat = new ElementFormat();
nameElementFmt.fontSize = 14;
nameElementFmt.color = 0xFF6655;
var str1:TextElement = new TextElement("みんなでお祭りに行った帰りに、",strElementFmt);
var str2:TextElement = new TextElement("それから、",strElementFmt);
var str3:TextElement = new TextElement("を買って帰りました。楽しかったなあ。",strElementFmt);
var name1:TextElement = new TextElement("盆栽 ",nameElementFmt);
var name2:TextElement = new TextElement("蚊遣り豚 ",nameElementFmt);
var name3:TextElement = new TextElement("招き猫 ",nameElementFmt);
//グループ化するエレメントのベクターを作る
var groupVector:Vector.<ContentElement> = new Vector.<ContentElement>();
groupVector.push(str1,grph1,name1,grph2,name2,str2,grph3,name3,str3);
//グループエレメントを作る
var groupElement:GroupElement = new GroupElement(groupVector);
//テキストブロックを作る
var textBlock:TextBlock = new TextBlock();
textBlock.content = groupElement;
//テキストラインの行幅
var lineWidth:Number = 350;
//テキストブロックから最初のテキストラインを取り出して表示する
var textLine:TextLine = textBlock.createTextLine(null,lineWidth);
var pos:Point = new Point(40,50);
//テキストブロックからテキストラインを繰り返し取り出して表示する
while (textLine !=null) {
	textLine.x = pos.x;
	textLine.y = pos.y ;
	addChild(textLine);
	pos.y += mc1.height+20;
	textLine = textBlock.createTextLine(textLine,lineWidth);
}

ワープロソフトに負けない便利なタブ揃え機能

ところで、TextBlockクラスにはtabStopsというプロパティがあります。これは左揃え、中央揃え、右揃え、小数点揃えといったタブ揃えのマーカーを設定するプロパティです。タブ揃えの位置と種類はTabStopクラスで作ってベクター配列に入れ、tabStopsプロパティに設定します。一方、ストリングデータではタブコードを\tのメタ文字で入力します。


//タブの位置と種類の設定
var tab1:TabStop=new TabStop(TabAlignment.START, 5);
var tab2:TabStop=new TabStop(TabAlignment.CENTER, 120);
var tab3:TabStop=new TabStop(TabAlignment.END, 240);
var tab4:TabStop=new TabStop(TabAlignment.DECIMAL, 330, ".");
var tabStopsVec:Vector.<TabStop> = new Vector.<TabStop>();
tabStopsVec.push(tab1,tab2,tab3,tab4);
//テキストブロックを作る
var textBlock:TextBlock = new TextBlock();
textBlock.content=textElement1;
textBlock.tabStops=tabStopsVec;

なお、tab4を作っている行を見るとわかるように、小数点揃えのタブストップは第3引数でわざわざピリオドを指定しています。このことからも想像が付くように、ここで任意の文字を指定すれば小数点以外の文字で揃えることもできます。

テキストブロックのタブ揃え
fig4 テキストブロックのタブ揃えの設定を利用して整列させています

[sample] TabStop_sample1.fla
テキストブロックにタブ揃えの設定をしてテキストエレメントを整列させます。

//テキストブロックを追加するためのコンテナ
var container:Sprite=new Sprite();
container.graphics.beginFill(0xFFFF32);
container.graphics.drawRect(0,0,360,30);
container.graphics.endFill();
container.graphics.beginFill(0xFFFFCD);
container.graphics.drawRect(0,32,360,90);
container.graphics.endFill();
container.x=20;
container.y=50;
addChild(container);
//表データ
var tabledata:String= "\t左揃え\t中央揃え\t右揃え\t小数点揃え\n"    
+ "\t砂糖\tRED BLUE\tABC\t23.0\n"
+ "\t天ぷら油\tGREEN\t230ミリ\t-0.56\n"
+ "\tみりん\tYELLOW\tビーチ\t123.4円\n";
//フォーマット
var format1:ElementFormat = new ElementFormat();
format1.fontDescription=new FontDescription("Arial");
format1.fontSize=14;
format1.locale="jp";
//テキストエレメントを作る
var textElement1:TextElement=new TextElement(tabledata,format1);
//タブの位置と種類の設定
var tab1:TabStop=new TabStop(TabAlignment.START, 5);
var tab2:TabStop=new TabStop(TabAlignment.CENTER, 120);
var tab3:TabStop=new TabStop(TabAlignment.END, 240);
var tab4:TabStop=new TabStop(TabAlignment.DECIMAL, 330, ".");
var tabStopsVec:Vector.<TabStop> = new Vector.<TabStop>();
tabStopsVec.push(tab1,tab2,tab3,tab4);
//テキストブロックを作る
var textBlock:TextBlock = new TextBlock();
textBlock.content=textElement1;
textBlock.tabStops=tabStopsVec;
//コンテンツデータから最初の1行分の表示オブジェクトを作る
var block_width:Number=1000;
var textLine:TextLine=textBlock.createTextLine(null, block_width);
var xPos=0;
var yPos=0;
//コンテンツデータから1行ずつ取り出して表示する
while (textLine != null) {
	container.addChild(textLine);
	textLine.x=xPos;
	yPos+=textLine.height+8;
	textLine.y=yPos;
	textLine=textBlock.createTextLine(textLine,block_width);
}

最後にオマケを1つ。前回の最後で新テキストエンジンの文字は回転/縮小拡大しても表示されるのが特長であることを示しましたが、もちろん3D回転させることもできます。先のサンプルにz座標と3D回転のプロパティの設定を追加すると3D的に奥行きのある表になります。文字が台形に変形して表示されている点に注目してください。

テキストブロックを3D回転
fig5 テキストブロックは3D回転しても文字が表示されます

TabStop_sample2.fla
先のサンプルにz座標と3D回転のプロパティの設定を追加します。

container.x=5;
container.y=130;
container.z = 40;//Z座標
container.rotationX = 10;//X軸回転
container.rotationY = 40;//Y軸回転
container.rotationZ = -10;//Z軸回転

さて、2回にわたって新テキストエンジンを利用するTextBlockクラスについて紹介してきました。TextBlockクラスを利用すれば、Flashでのテキストの表現が飛躍的に変わることを実感していただけたでしょうか? 発表されたFlash Professional CS5では新テキストエンジンを使うテキストレイアウトフレームワーク(TLF)も標準搭載されました。そろそろ古いテキスト表示は捨て、新テキストエンジンに乗り換えましょう。

関連情報


大重美幸氏写真大重美幸
(おおしげよしゆき)

日立情報システムズ、コミュニケーションシステム研究所を経て独立。株式会社ロクナナ顧問。執筆、講師、ソフトウェア開発を行う。趣味はサーフィンとジョギング。茅ヶ崎在住。著著は約50冊。
twitter : @oshige@as3note

近著:Adobe Flash CS4 詳細!ActionScript 3.0入門ノート[完全改訂版]ActionScript3.0辞典[FlashPlayer10/9対応] ブラウザで無料ではじめるActionScript 3.0 - it's a wonderfl world