UIX開発者ガイド | ![]() 目次 |
![]() 前へ |
![]() 次へ |
このトピックでは、UIXの中心的なビジュアル・コンポーネントであるページについて説明します。UIXにおけるページの意味、ページの定義方法、およびユーザー・インタフェースとしてのページのレンダリング方法などを示します。ここでは、次の項目について説明します。
Web上で、ページの概念は非常に明確です。最も単純なページは、Webブラウザで解析されレンダリングされたHTML要素の集合です。ただし、Webアプリケーション開発のコンテキストにおいてページの概念は、ページの定義およびレンダリング方法やページを表示するデバイスによって、より複雑なものになります。
UIXにおいてページは、アプリケーションのユーザー・インタフェースの論理表示形式の1単位です。ページが論理的な単位とされているのは、ほとんどの特長(表示可能なページのパーツやそれらの関係など)が定義されていますが、ページの表示方法がすべて定義されているとはかぎらないからです。たとえば、同じ論理ページをHTMLページまたはWML(Wireless Markup Language)ページとして、あるいは音声インタフェースを介して表示できます。
UIXページがユーザー・インタフェースの1単位にすぎないのは、アプリケーションが通常、関連パーツの複数の単位で構成され、各単位は個別のページとして表示できるためです。たとえばページは、広範なタスク・フローの1ステップを表す場合があります。
Webアプリケーションの様々な側面を開発するため個別のUIXテクノロジが使用できることから、これらの区別はUIXでは重要なものとなります。ページ作成のための主となるUIXテクノロジがUIX Componentsです。UIX Componentsについては、このトピックで説明します。ページ間のアプリケーション・フロー管理のためのテクノロジがUIX Controllerです。UIX Controllerについては、「UIX Controllerの概要」で詳しく説明します。必要とする機能がかぎられている場合はこれらのテクノロジを単独で使用できます。また、Webアプリケーションのこれらの側面の開発を単純化する場合は、まとめて使用することもできます。
UIXでは、論理ページは階層になっている一連のコンポーネント(ユーザー・インタフェース・ノードと呼ばれる)で構成されています。ボタン、イメージ、表およびテキスト・フィールドなどの表示コンポーネントを定義するノードや、他のノードのレイアウトおよび外観を決定し、その動作も管理するノードなどがあります。UIXでは多数の共通ノードが提供されますが、カスタム・ノードを定義および作成することも可能です。
ノードは親と子を持つことができます。複数のノードで、ページの論理構造を表すツリー状の構造を構成します。たとえば、図3-1はユーザー・インタフェース・ノードの論理階層を示しています。図3-2は、HTMLページとしてレンダリングされた階層を示します。(簡潔にするため、この図では、このページの定義方法の詳細の一部が省略されています。省略されたものの詳細は、後述の「レイアウト、子およびロールについて」を参照してください。また、実際のコードを調べる場合は「ユーザー・インタフェース・ノード・ツリーの作成例」を参照してください。)
図3-1: UIXページにおけるノードの論理階層
図3-2: UIXページにおけるノードのビジュアル階層
用語についての注意: ボタンやタブなどのビジュアルUIXユーザー・インタフェース・コンポーネントは、すべてユーザー・インタフェース・ノードです。ただし、UIXでは、ユーザー・インタフェース・コンポーネントであると一般に理解されていない他のユーザー・インタフェース・ノードも提供されます。たとえば、stackLayout
ノードはその子ノード(text
およびimage
のユーザー・インタフェース・コンポーネントなど)の配置方法を管理しますが、それ自体は表示されません。このため、このガイド内で、「ユーザー・インタフェース・コンポーネント」と「ユーザー・インタフェース・ノード」を同義で使用するセクションもありますが、コンテキストによっては別個のものとして説明するセクションもあります。「ユーザー・インタフェース・ノード」は通常、論理ページを構成するノードの説明に用いられます。「ユーザー・インタフェース・コンポーネント」は通常、表示可能なユーザー・インタフェース・コンポーネントの説明に用いられます。ユーザー・インタフェース・ノードまたはコンポーネントをJavaコンテキストで説明するとき、「UINode
」や「bean」という用語が使用される場合があります。これらのJava用語の詳細は、後述の「Javaでのユーザー・インタフェース・ノードの作成」を参照してください。
ユーザー・インタフェース・ノードは機能によって異なりますが、共通する特長もあります。
ユーザー・インタフェース・ノードは、名前およびネームスペースの2つのプロパティによって一意に識別されます。同じタイプのノードは、そのタイプの他のすべてのノードと同じ機能を備えています。また、1つのタイプの中には多数のノードがあります。たとえば、button
ノードはすべて同じタイプですが、この中には多数のボタンが存在します。
名前プロパティは内容を表します。つまり、button
ノードの名前はすべてbutton
であり、image
ノードの名前はすべてimage
です。ただし、開発者がノードを定義して類似した名前を付ける場合があるため、これらの名前が競合しないようにするメカニズムが必要になります。このメカニズムがネームスペースであり、XMLの標準機能です。
ネームスペースは、名前をグループ(スペース)に分けるために使用する一意の文字列です。ネームスペースに含まれるメンバーは一意になります。ユーザー・インタフェース・ノードを定義する各開発者は、最初に一意のネームスペース文字列を定義する必要があります。確実に一意にするために、ネームスペースを表す文字列として、ネームスペースを定義する開発者が所有しているURLを選択する場合がよくあります。たとえば、UIX Componentsのネームスペースはhttp://xmlns.oracle.com/uix/ui
という文字列になります。この文字列が選択されたのは、そのURLを所有しているのはUIX開発チームのみであることが明らかなためです。このURLに実際にデータを用意したり、ユーザーがURLにアクセスできるようにしたりする必要はありません。URLを選択するのは、一意性を確保するための簡単な方法です。
ネームスペースおよびそのネームスペース内の要素の名前の組合せが、一意のペアになります。UIX Componentsのネームスペース(http://xmlns.oracle.com/uix/ui
)内のbutton
という名前のノードもそのようなペアの1つです。このため、その他のネームスペース(http://www.example.org
など)にあるbutton
ノードと区別できます。このように、開発者は名前の競合を憂慮することなく要素を定義できます。
ネームスペースは標準のXMLテクノロジです。詳細は、World Wide Web ConsortiumのWebサイト(http://www.w3.org)を参照してください。
タイプによって一意に識別される以外に、ユーザー・インタフェース・ノードには、特定のノード・インスタンスを示す属性、すなわちプロパティもあります。たとえば、ボタン・ノードには、ボタンのテキスト、ボタンをアクティブにしたときのリンク先、ボタン使用の可否を示す属性が付きます。
前述したように、ノードは子を持つことができます(必須ではありません)。ボタンは子ノードを持つ必要がありません。一方、ヘッダー・コンポーネントは、そのヘッダーの下にグループ化されているすべてのノードを表す子を持っています。
ノードのもう1つの大きな特長は、レンダリングできることです。つまり、論理エンティティであるノードで出力を生成でき、その出力によってノードがHTMLコードなどで表されます。レンダリングのメカニズムについてはこのトピックで後述します。
UINode
JavaインタフェースUIXには、ユーザー・インタフェース・ノードに対応するJavaクラスが組み込まれています。これらのクラスは、oracle.cabo.ui
パッケージのベースUINode
インタフェースを実装します。UINode
インタフェースには、すでに説明した特長に対応する次のメソッドが含まれます。
public String getNamespaceURI();
public String getLocalName();
public int getIndexedChildCount(RenderingContext context);
public UINode getIndexedChild(RenderingContext context, int childIndex);
public Enumeration getAttributeNames(RenderingContext context);
public Object getAttributeValue(RenderingContext context, AttributeKey attrKey);
public void render(RenderingContext context)
throws IOException;
これらのUINode
メソッドおよびこの他のいくつかのメソッドの詳細は、後述します。ただし、このインタフェースが不変、つまり読取り専用であることに注意してください。UINode
では名前、ネームスペース、属性、子へのアクセスを可能にする必要がありますが、このインタフェースを介してそれらを変更することはできません。不変であることによって、UIXはマルチスレッド・サーバー環境でより快適に動作します。
uiXML文書にある多数の要素(すべてではない)は、文書がUIXで処理されるときにユーザー・インタフェース・ノードに変換されます。その他の要素は、ユーザー・インタフェース・ノード要素が受け取るデータの指定など、ユーザー・インタフェース・ノード要素のサポートのために使用されます。
次に、ボタンを定義するuiXML要素の例を示します。
<button xmlns="http://xmlns.oracle.com/uix/ui" text="OK"/>
ここで
button
はuiXML要素の名前です。button
のユーザー・インタフェース・コンポーネント(ノード)を定義します。
xmlns="http://xmlns.oracle.com/uix/ui"/
はボタン・コンポーネントのネームスペースを識別します。より正確に言えば、"http://xmlns.oracle.com/uix/ui"/
はbutton
要素のxmlns
属性の値です。
text="OK"
はbutton
要素のテキスト属性を宣言します。属性の値は「OK」で、このテキストはボタンにレンダリングされます。
UIXでは高レベルのユーザー・インタフェース・ノードが多数提供されており、これによって、ページがレンダリングされる際に高度なユーザー・インタフェース・コンポーネントが作成されます。ただし、基本的なUIX文書を作るだけであれば高レベルのノードは必要ありません。最低限のページ・コンテンツのための単純なノード(テキスト・ノードおよび様々なHTMLノード)がUIXによって提供されるためです。テキスト・ノードによってページのテキストが作成され、HTMLノードによってHTMLがページに直接レンダリングされます。次に、これらの単純なノードの1つを使用して簡単なuiXML文書を作成する例を示します。
<text xmlns="http://xmlns.oracle.com/uix/ui"
text="hello, world"/>
この文書についての注意点は、次のとおりです。
文書のルート要素である<text>
要素は、この文書のただ1つの要素です。
<text>
要素のxmlns="http://xmlns.oracle.com/uix/ui"
属性により、この要素とこの要素に含まれるすべての下位要素がネームスペースとして"http://xmlns.oracle.com/uix/ui"
をデフォルトとします。これが前述したUIX Componentsのネームスペースです。ネームスペースは階層的に設定できるので、ネームスペースを宣言しない要素には上位要素のネームスペースが適用されます。
<text>
要素には、実際のテキストをUIXに対して指定する1つの属性text="hello, world"
が含まれます。
次の例では、基本的なHTML要素を使用してページを作成するuiXMLを示します。(書式のインデントは、要素の親子関係を明確にするために使用されています。必須ではないので注意してください。)
<div xmlns="http://www.w3.org/TR/REC-html40">
Hello world.
<ul>
<li>First HTML list element</li>
<li>Second HTML list element</li>
</ul>
</div>
追加される内容は次のとおりです。
新しいユーザー・インタフェース・ノードがこのページで使用されています。<div>
要素は標準のHTML DIV要素で、子をブロックにグループ化します。ここでルート・ノードとして使用され、テキストといくつかのHTMLの追加ユーザー・インタフェース・ノードが含まれます。生成されたページには、これらの<ul>
要素および<li>
要素によって、HTML形式の2つのリスト項目を含む番号なしリストが含まれます。
ルートの<div>
要素で異なるネームスペース宣言が使用されています。HTMLのネームスペースxmlns="http://www.w3.org/TR/REC-html40"
が指定されます。UIXのページ・レンダリング・フレームワークでは、HTMLのネームスペースで宣言されるすべての要素は、テキストに変換された後で、またはHTMLのテキスト規則に準拠するようにUIXによってエスケープされた後で、レンダリング時に出力に直接渡されます。
この場合、<li>
要素には対応する</li>
要素が必要となるので注意してください。これはHTML規則とは異なります。終了タグを挿入しないと、整形式文書に関するXML規則の違反になります。このため、UIX文書に含まれるHTMLは、実際にはXHTML(HTML形式の1つ、つまり適切な形式のXML)である必要があります。
前述した例は、UIXページで宣言される最も単純なユーザー・インタフェース・ノード(テキストとHTML)を示していますが、UIX Componentsで提供される高レベル・ノードを追加すると興味深いコンテンツが生成されます。ここで、最も基本的なUIX Componentsのノードの1つであるボタンを、前述の例に追加します。
<div xmlns="http://www.w3.org/TR/REC-html40"
xmlns:ui="http://xmlns.oracle.com/uix/ui">
Hello world.
<ul>
<li>First list element</li>
<li>Second list element</li>
</ul>
<ui:button text="Push me" destination="http://www.example.org"/>
</div>
追加される内容は次のとおりです。
2番目のネームスペース宣言がルートの<div>
要素に追加されています。これはUIX Componentsのネームスペース、"http://xmlns.oracle.com/uix/ui"
です。さらに、:ui
がxmlns
属性の名前の最後に追加され、xmlns:ui
となっています。<div>
で宣言した最初のネームスペースが、その要素および含まれる要素のデフォルトであることは変わりませんが、ネームスペース規則に従い接頭辞としてui:"
を名前に付ければ、含まれる要素でUIX Componentsのネームスペースを使用することも可能です。これは便利なメカニズムで、文書内の離れた場所で長い属性を使用するかわりに、異なるネームスペースを要素で簡単に宣言できます。
text
およびdestination
の2つの属性を含むUIX Componentsの<button>
要素が追加されています。これらの属性はボタンの2つのプロパティを示しています。これはUIX Componentsのネームスペース内にあることに注意してください。その他の要素はHTMLのネームスペース内にあります。このページがレンダリングされると、文字列が「Push me」というボタンもページに表示されます。このボタンを押すとURLのhttp://www.example.org
がアクティブになります。
ボタンは、UIX Componentsで使用可能な最も単純なユーザー・インタフェース・ノードの1つです。さらに複雑なノードについての説明は、このガイドで後述します。
uiXMLによるユーザー・インタフェース・ノードの作成も簡単ですが、Javaコードで直接作成することもできます。UIXのすべてのリリースにUINode
の作成に使用できるクラスが含まれています。(UINode
はユーザー・インタフェース・ノードの定義に使用されるJavaインタフェースであることに注意してください。)これらすべてのクラスは、oracle.cabo.ui.beans
パッケージおよびそのサブパッケージにあります。ただし、例外があり、単純なテキスト・ノードはoracle.cabo.ui.TextNode
に、HTMLのUINodeはoracle.cabo.ui.html.HTMLWebBean
にあります。Java用語との一貫性を高めるため、UINode
インタフェースをJavaで実装するクラスのほとんどは、JavaBeans標準に関連して、検出可能なコード単位であるBeanと呼ばれます。
UINodeをJavaで作成するには、通常、作成するノードのタイプを表すクラスのインスタンスを構築します。たとえば、ボタン・ノードを作成する場合、ButtonBean
のインスタンスを作成します。ノードに属性を設定するには、設定する属性にマップするBeanで使用可能ないずれかのsetterメソッドをコールします。たとえば、次のコードでは、前述の例のページのコンテンツ領域はuiXMLではなくJavaで作成されています。
import oracle.cabo.ui.TextNode;
import oracle.cabo.ui.html.HTMLWebBean;
import oracle.cabo.ui.beans.nav.ButtonBean;
// ... skipping class declaration
HTMLWebBean div = new HTMLWebBean("div");
// the text node is the first child of the "div"
TextNode helloText = new TextNode("hello, world");
div.addIndexedChild(helloText);
// the unordered list is next
HTMLWebBean unorderedList = new HTMLWebBean("ul");
div.addIndexedChild(unorderedList);
// the unordered list gets two list item children
// note that the list item text is added as text nodes here
HTMLWebBean firstListItem = new HTMLWebBean("li");
firstListItem.addIndexedChild(new TextNode("First list element"));
HTMLWebBean secondListItem = new HTMLWebBean("li");
secondListItem.addIndexedChild(new TextNode("Second list element"));
unorderedList.addIndexedChild(firstListItem);
unorderedList.addIndexedChild(secondListItem);
// finally create the UIX Components ButtonBean with our two attributes
ButtonBean button = new ButtonBean();
button.setText("Push me");
button.setDestination("http://www.example.org");
div.addIndexedChild(button);
次のセクションで説明しますが、ノードの作成に使用するのがuiXMLかJavaコードかに関係なく、結果は同じになります。
ユーザー・インタフェース・ノードは、uiXMLページの作成に使用される基本的な構成ブロックです。ページ自体は、階層的なノードのツリーを構成して作成されます。このトピックの後半では、このような(論理ページを表す)ツリーの構成と、それを物理的出力としてレンダリングする方法について説明します。
ノード階層の作成が可能なのは、多数のノードが親として他のノード(子)をサポートできるためです。前述の例では、<button>
要素(ノード)が<div>
要素の子になります。子ノードを他のノードの親にすることによって、さらに複雑な構造を構成できます。すべてのユーザー・インタフェース・ノードが他のノードの親になれるわけではなく、これは該当ノードのタイプに大きく依存します。たとえば、論理ページのボタンは、通常、他のコンテンツを中に持つことはできません。このため、ボタン・ノードも子を持つことができません。
一部のユーザー・インタフェース・ノードでは子ノードを持つことが不可能ですが、一連の子ノードの管理を特に目的として設計されたノードもあります。このようなノードはしばしばレイアウト・ノードと呼ばれます。レイアウト・ノードにより、生成されたページに何かが表示されるかどうかは場合によって異なりますが、含んでいる子ノードの位置を常に管理しています。レイアウト・ノードの一般的な例の1つがスタック・レイアウト・ノードです。これは複数の子ノードを含み、それらのノードを、ユーザー向けに生成されるページで上から下に垂直方向に配置します。レイアウト・ノードのその他の例については、UIX ComponentsのuiXML要素のリファレンス・ドキュメントに説明があります。
ユーザー・インタフェース・ノード・ツリーでは、指定のノードに親は1つのみとは規定されません。ノードは、同じツリー内の複数の場所で他のノードの子として追加できます。これにより、あるページの1つのセクションの指定をツリー内の別の部分に簡単に複製することができます。同じページの複数の場所に同一コンテンツがある場合にはこれが役立ちます。
ノード・ツリーの定義方法に関係なく、最終的には、サーバーに存在する一連のJavaオブジェクトになります。これらのオブジェクトそれぞれがoracle.cabo.ui.UINode
です。Javaオブジェクトの実際のツリーは、次のいずれかの方法で作成されます。
uiXMLを使用してツリーを指定した場合、uiXML文書をJavaオブジェクトのツリーに変換する必要があります。この場合、次のような2つの簡単な方法があります。
UIX Controllerフレームワークを使用してアプリケーション・フローを管理している場合は、UIX文書を自動的にJavaオブジェクトのツリーに変換するユーティリティ・クラスがUIX Controllerに含まれています。
UIX Controllerを使用しないでアプリケーション・フローを管理しているときに、uiXML文書をJavaオブジェクトのツリーに変換する必要がある場合は、ユーティリティ・クラスのoracle.cabo.ui.xml.UINodeUtils
を使用できます。このクラスのメソッド(createUINode()
)は、通常使用されるSAXライブラリから、Java File
またはJava InputSource
を取得し、UIXに基づいたJavaオブジェクト・ツリーをその入力に作成します。
Java Beanクラスを使用してノード・ツリーを作成した場合は、変換は必要ありません。Java のUINode
インタフェースを実装するJavaクラスとしてすでにBeanが存在しているためです。ツリーを作成するコードをコンパイルして実行すると、ツリーが使用できるようになります。
すべてのツリーのエントリ・ポイントは、ルート・ノードと呼ばれます。これは、ノード・ツリー階層の最上位の親であり、UINodeUtils.createUINode()
メソッドの結果として返されるUINodeでもあります。ただし、最も重要なのは、このノードからレンダリング・プロセス(エンド・ユーザーに対して出力を生成するためのツリーの使用方法)が開始されるということです。UINodeツリーを作成した後は、アプリケーション全体の存続期間はメモリーに保存するようにしてください。UIXテクノロジ・スタックは、ページ・レンダリングが何回必要になっても、再作成や変更することなく同じツリーを再利用するよう設計されています。これにより、ユーザー・インタフェースを生成するためのUIX Componentsのページの使用にかかるパフォーマンス・コストが削減されます。ノード・ツリーの再利用の詳細は、このトピックおよび後続のトピックで説明します。
ページ内の子の位置を管理するユーザー・インタフェース・ノードは、レイアウト・ノード(コンテキストによってはレイアウト・コンポーネント、レイアウト要素または単純にレイアウト)と呼ばれます。例としてはstackLayout
、borderLayout
、pageLayout
およびtable
などがあります。UIXには、レイアウトでの子の配置に2つの主要な方法があります。1番目の方法では、子は単純に順番どおり次々と配置されます。2番目の方法では、子は、上、下、左、右などのように定義済の特定の位置に配置されます。順番どおり配置される子は「索引付けされた子」と呼ばれます。特定の指定された位置に配置される子は「名前の付けられた子」と呼ばれます。これらの用語はその位置にある子を指し示す場合に便利ですが、子自体の固有プロパティを指しているわけではありません。たとえば、4つのイメージを、索引付けされた子として垂直方向に配置できます。また、名前の付けられた子としてレイアウトの上、下、左、右に配置することもできます。イメージ自体は単なるイメージのままですが、レイアウトにおけるロールを示すため、それらは索引付けされた子または名前の付けられた子と呼ばれます。
uiXMLでロールを定義するには、ロール要素と呼ばれる1つ以上の要素を使用して、子の配置方法をレイアウトで示す必要があります。ロール要素はユーザー・インタフェース・ノードではありません。これはむしろ、親ノードとその子ノード間の調整役として機能します。たとえば、次に示すのが埋込みuiXML要素のリストです。
<borderLayout>
<top>
<image ... />
</top>
<left>
<text ... />
</left>
<right>
<text ... />
</right>
</borderLayout>
これらの要素がこの階層を構成します。
図3-3: uiXMLの親要素、ロール要素、子要素のツリー
次に、作成されるノード・ツリーを示します。
図3-4: UIXユーザー・インタフェース・ノードのツリー
UIX Java APIにはロールと同等のものはありません。子は、setTop()
、setBottom()
およびaddIndexedChild()
などのメソッドを使用して直接配置されます。
索引付けされた子が使用されるのは、親ノードに子ノードが格納されている順序のみに基づいて、子ノードを管理する必要がある場合です。それ以外の場合、子は同様に扱われます。索引付けされた子をサポートするノードの一例は、stackLayout
ノードです。スタック・レイアウトでは、子は上から下に垂直方向に配置されますが、このために必要な唯一の情報は管理対象の子の順序です。
uiXMLで索引付けされた子を指定するには、親要素の中に<contents>
要素を挿入してから、<contents>
の中に子要素を追加します。<contents>
要素は、索引付けされた子をレイアウトに追加する際に必要なロール要素です。また、索引付けされた子を追加する際に使用できる唯一のロール要素でもあります。
索引付けされた子の要素を、配置する順序で<contents>
の下に列記します。たとえば、次のuiXML文書では、3つの索引付けされたボタンの子を管理するスタック・レイアウトが示されます。
<stackLayout xmlns="http://xmlns.oracle.com/uix/ui">
<contents>
<button text="Indexed child 1"
destination="http://www.example.org"/>
<button text="Indexed child 2"
destination="http://www.example.org"/>
<button text="Indexed child 3"
destination="http://www.example.org"/>
</contents>
</stackLayout>
Javaコードでは、ほとんどのBeanで使用可能なaddIndexedChild()
メソッドを使用して、同じ索引付けされた子を追加できます。
import oracle.cabo.ui.beans.layout.StackLayoutBean;
import oracle.cabo.ui.beans.nav.ButtonBean;
// ... skipping class declaration
StackLayoutBean parentStack = new StackLayoutBean();
parentStack.addIndexedChild(new ButtonBean("Indexed child 1",
"http://www.example.org"));
parentStack.addIndexedChild(new ButtonBean("Indexed child 2",
"http://www.example.org"));
parentStack.addIndexedChild(new ButtonBean("Indexed child 3",
"http://www.example.org"));
名前の付けられた子は、子の順序以外のコンテキストが必要になる親子関係を作成するために使用されます。たとえば、境界レイアウト・ノードでは、その子はtop、bottom、left、rightなどの領域に配置されます。子の順序は子が表示される特定の領域を示さないため、これらの子は、位置を示すロールを使用して追加される必要があります。
uiXMLで名前の付けられた子を指定するには、親の中に適切なロール要素を挿入してから、そのロールの中に子要素を挿入します。レイアウト要素は、(索引付けされた子を追加する場合は)1つの<contents>
ロールしか含むことができませんが、(名前の付けられた子を追加する場合は)個別の名前付きロールを示すために複数のロールを含むこともできます。名前付きロールに指定できる直接の子は1つのみです。
名前の付けられたテキストの子が4つの領域にある境界レイアウト・ノードは、次のようになります。この例のロール要素は<top>
、<bottom>
、<right>
および<left>
です。
<borderLayout xmlns="http://xmlns.oracle.com/uix/ui">
<top>
<text text="Top text"/>
</top>
<bottom>
<text text="Bottom text"/>
</bottom>
<right>
Right text
</right>
<left>
Left text
</left>
</borderLayout>
名前の付けられた子を親の下にリスト表示する順序は関係ないので注意してください。また、この例は、テキストを必ずしも<text>
ノードに指定する必要がないことも示しています。表示するテキストがロール要素の内側に適切に指定されているかぎり、leftやrightテキストの子の場合のようにuiXMLファイルに直接入力することもできます。
同様の結果を得るJavaコードでは、通常、Beanに用意されている名前の付けられた子を設定する特殊なメソッドを利用します。
import oracle.cabo.ui.TextNode;
import oracle.cabo.ui.beans.layout.BorderLayoutBean;
// ... skipping class declaration
BorderLayoutBean parentBorder = new BorderLayoutBean();
parentBorder.setTop(new TextNode("Top text"));
parentBorder.setBottom(new TextNode("Bottom text"));
parentBorder.setRight(new TextNode("Right text"));
parentBorder.setLeft(new TextNode("Left text"));
レイアウトの中には、索引付けされた子と名前の付けられた子の両方をサポートするものがあります。名前の付けられた子は指定された位置に配置され、索引付けされた子はレイアウトの適切な位置に順序通りに配置されます。次の例で、イメージは名前の付けられた子であり、レイアウトの上、下、左、右に配置されます。テキスト文字列は索引付けされた子であり、レイアウトの中央で順番どおりに左から右へと配置されます。
<borderLayout> <top> <image source="images/globalhelp.gif"/> </top> <bottom> <image source="images/warnl.gif"/> </bottom> <end> <image source="images/cobrand.gif"/> </end> <start> <image source="images/info.gif"/> </start> <contents> <text text="This is the first sentence. " /> <text text="This is the second sentence. " /> <text text="This is the third sentence. " /> </contents> </borderLayout>
注意: uiXMLで、索引付けされた子と名前の付けられた子を識別する個別の手段が用意されているのはなぜでしょうか。名前の付けられた子がない場合、たとえば、子の右側への配置を指定する唯一の方法は、右ということを表す索引番号を選択することです。認識しやすい名前を使用した方が、より直観的に作業できます。索引付けされた子がない場合、定義済の名前がすべての子に順番どおりに付与される必要があり、その数は無限に増えていく可能性があります。
このセクションでは、ビジュアル・ページ設計をノード・ツリーに変換する際に必要なものに関する、より包括的な例を示します。この例は、図3-1および図3-2のイラストに基づいています。
最初に、目標の設計の希望レイアウトを調べ、それを論理ノード・ツリーに分割します。図3-5に、コンテンツをグループ分けするいくつかのヘッダー・ノードと、サンプルのテキストおよびイメージを含む設計を示します。
図3-5: UIXページにおけるノードのビジュアル階層
図3-6では、同じ設計の階層が、明解なノード・ツリーとして論理的に構成されています。ノード・ツリーが決定すると、ツリーを作成するコードを開発できます。
図3-6: UIXページにおけるノードの論理階層
このようなツリーを作成するuiXMLコードは、次のとおりです。名前の付けられた子または索引付けされた子のあるレイアウトの定義にuiXMLを使用するときは、子の配置方法を指定するロール要素を使用する必要があるので注意してください。次の例は索引付けされた子のみを示しているため、ロール要素<contents>
が各レイアウト要素に使用されます。
<header xmlns="http://xmlns.oracle.com/uix/ui"
text="Header 1">
<contents>
<stackLayout>
<contents>
This is sample text. This is sample text.
<header text="Header 2">
<contents>
<stackLayout>
<contents>
This is more sample text, for the
purpose of the demonstration.
<image source="shapes.gif" shortDesc="Three Shapes"/>
</contents>
</stackLayout>
</contents>
</header>
</contents>
</stackLayout>
</contents>
</header>
同じノード・ツリーを作成するJavaコードは、次のとおりです。
// -- Create a tree of UIX Components Beans --
// Create the first header.
HeaderBean header1 = new HeaderBean("Header 1");
// Create the text for the first header.
TextNode text1 =
new TextNode("This is sample text. This is sample text.");
// Create a stack layout for laying out the first header's
// children vertically.
StackLayoutBean stackLayout1 = new StackLayoutBean();
//Add the text as a child of the stack layout
stackLayout1.addIndexedChild(text1);
// Add the stack layout as the child of the fist header
header1.addIndexedChild(stackLayout1);
// Create the second, nested header
HeaderBean header2 = new HeaderBean("Header 2");
// Create the contents of the second header - some text and an image.
TextNode text2 =
new TextNode("This is more sample text, for the purpose of the
demonstration.");
ImageBean image = new ImageBean("shapes.gif", "Three Shapes");
// Create a stack layout for laying out the children of the second
// header.
StackLayoutBean stackLayout2 = new StackLayoutBean();
// Add the children to the second stack layout, and add the stack
// layout as the child of the second header.
stackLayout2.addIndexedChild(text2);
stackLayout2.addIndexedChild(image);
header2.addIndexedChild(stackLayout2);
// Add the second header as a child of the first stack layout (which
// is the child of the first header).
stackLayout1.addIndexedChild(header2);
ノード・ツリーが定義されサーバー上に作成されたら、ユーザーが実際に見られる(聞ける)ようにするため、ツリーをクライアントにレンダリングする必要があります。UIXレンダラを使用して、エンド・ユーザーに対して表示されるHTML、WMLまたはその他の出力形式に、ノード・ツリーをレンダリングできます。
通常、クライアントに送信される出力は、ノード・ツリーの指定に使用されるUIXコードの容量を大幅に上回ります。たとえば、UIX Componentsは簡単なUIXコード・セグメントを、複雑なHTML要素グループとしてレンダリングする可能性があります。これがUIXの特長の1つです。つまり、単純な指定が複雑な出力コードに変換されるため、開発者は複雑なコードを意識する必要がありません。
サーバー上に存在するノード・ツリーをレンダリングするためには、そのツリーのルート・ノードでrender()
メソッドをコールし、それをRenderingContext
に渡す必要があります。
UINode.render(RenderingContext context)
これを実行するには、まずRenderingContext
を作成し、それを適切に構成します。
RenderingContext
についてoracle.cabo.ui.RenderingContext
は、ノード・ツリーの1回のレンダリングのために、UIX Componentsにステートフル情報を提供する、サーバーで使用されるクラスです。ノード・ツリーは一度作成されると、アプリケーションの存続期間中サーバーで使用されます。RenderingContext
によって、存続期間の短い、レンダリングごとの情報がすべてカプセル化されます。
典型的なページ・レンダリング・プロセスは次のとおりです。
RenderingContext
を作成します。render(RenderingContext context)
メソッドにRenderingContext
を渡します。RenderingContext
が廃棄されます。render(RenderingContext context)
メソッドがルート・ノードに対してコールされると、UIX Componentsの内部レンダラ・クラスが引き継ぎ、出力の生成に必要な作業を実行します。このプロセスの詳細は、このトピックで後述します。
UIX Controllerを使用してアプリケーション・フローを管理する場合は、リクエストごとにRenderingContext
が自動的に作成され、ページのノード・ツリーをレンダリングするために使用されます。UIX Controllerを使用しない場合、これらのステップをユーザーが実行するか、デバッグ時にUIXのテスト・クラスおよびデモ・クラスを使用する必要があります。便利なクラスの1つとしてoracle.cabo.ui.test.UIXTest
があり、これは引数として .uix
ファイルのパスを取得するJavaアプリケーションで、そのファイルのレンダリング結果を表示するブラウザ・ウィンドウを開きます。
ただし、開発タスクがページ作成のみの場合は、このガイドの次のトピックに進んでください。
RenderingContext
メソッド基本的にRenderingContext
クラスは、ページのレンダリング中に必要になるその他のコンテキストおよびプロパティのリポジトリとして使用されます。ほとんどのコンテキストやプロパティについてはここで説明しますが、UIX Componentsの内部コードのみで使用されるものや、高度なUIXコンポーネントの機能に関するトピックで説明するものなど、その他のメソッドもあります。このトピックで説明するRenderingContext
メソッドの概要は次のとおりです。
public interface RenderingContext
{
// Some methods not listed...
// ...
public OutputMethod getOutputMethod() throws IOException;
public Agent getAgent();
public LocaleContext getLocaleContext();
public ErrorLog getErrorLog();
public DataObject getDataObject(String namespaceURI, String name);
public RendererManager getRendererManager();
// ...
}
OutputMethod
すべてのRenderingContext
で、UIXのレンダリング・コードに、そのレンダラで生成される出力の宛先を指定する必要があります。oracle.cabo.ui.io.OutputMethod
はこのためにも使用されます。
OutputMethod
は、UIXのレンダリング・コードが、1回のレンダラで出力を生成する際に利用するインタフェースです。作成時に、OutputMethod
の実装は、Webサーバーの応答ストリームまたはファイル・システム上のファイルなど、出力先に接続されます。次に、UIXのレンダラ(たとえば、UIXのボタン・ノードの出力を生成するレンダラ)で、RenderingContext
からOutputMethod
にアクセスし、それに対してメソッドをコールして、要素、コメント、テキストをストリームまたはファイルに書き込みます。
コアのOutputMethod
の一部は、特殊な処理やテキスト・エスケープを実行します。これにより、生成されるすべての出力が宛先に対して適切であることが保証されます。例としては、oracle.cabo.ui.io.HTMLOutputMethod
やoracle.cabo.ui.io.XMLOutputMethod
があります。これらは、レンダラによる出力を調整し、HTMLおよびXMLの書式規則に準拠するようにします。
その他のOutputMethod
は、ユーティリティとしてのみ使用され、コアの実装をラップします。
oracle.cabo.ui.io.DebugOutputMethod
クラスは、別のOutputMethod
をラップし、追加のデバッグ・フィードバック(ノードが適切に使用されていない場合またはレンダラ・コールが均衡化されていない場合の警告など)を提供するために作成できます。
oracle.cabo.ui.io.PrettyPrinter
クラスも、別のOutputMethod
をラップするために作成されますが、生成される要素がこの機能によってネストおよびインデントされ、出力が読みやすくなります。
これらのユーティリティOutputMethod
はどちらも開発時に使用できます。アプリケーションが本番サーバーにデプロイされると、関連するパフォーマンスの低下を回避するために削除されます。
次のサンプル・コードでは、既存のJava PrintWriter
に対して結果を生成する、ラップされたOutputMethod
が作成されます。
public OutputMethod createOutputMethod()
{
// supply a print writer which will receive the rendering output
PrintWriter myPrintWriter = getPrintWriter();
OutputMethod coreOutputMethod = new HTMLOutputMethod(myPrintWriter);
// wrap that core OutputMethod with utility methods if you desire
return new PrettyPrinter(new DebugOutputMethod(coreOutputMethod));
}
oracle.cabo.share.agent.Agent
クラスは、このレンダリングの対象であるターゲット・デバイスのすべての情報を格納します。ターゲットになるのは、一般のWebブラウザ、携帯情報端末、またはUIX Componentsプロジェクトがサポートするその他のエージェントです。
OutputMethod
と同じく、Agent
インタフェースもUIX Componentsのレンダラが出力を生成する際に使用されます。最適なレンダリング結果を得るため、UIX Componentsのレンダラは、通常、与えられたAgent
情報に基づいて生成する出力を調整します。たとえば、複雑なデータ表ノードは、性能の低いブラウザでは、自動的に高性能ブラウザよりも単純な方法でレンダリングされます。また、ターゲット・プラットフォームの特長も考慮されます。
現在、Agent
は、次の状況に対応します。
ただし、本当に必要な場合にこの情報を使用するかどうかはUIX Componentsの内部レンダリング・コードによって決まります。たとえば、ブラウザとバージョン番号の多数の組合せで、まったく同じ内容がレンダリングされることもあります。
LocaleContext
は、現在のレンダリングの対象であるロケールに基づいてコンテンツを調整するために、UIX Componentsの内部レンダリング・クラスによって使用されます。最もわかりやすい例は、UIX Componentsのコードによって、コンテンツが指定のロケールに対応するように翻訳されることです。また、LocaleContext
ではデフォルトの日付および時刻書式に関する情報もUIX Componentsのレンダラに提供されます。
LocaleContext
が作成されるときに、java.util.Locale
に基づいてほとんどの情報をデフォルト値として設定しますが、特定のレンダラで別の日付書式を使用する場合などは、ロケールの固有の機能をオーバーライドすることもできます。
ErrorLog
はOutputMethod
に非常に似ており、UIX Componentsのレンダラは、ページのレンダリング中に検出されるエラーを記録するための集中インタフェースとして使用します。UIX Componentsは、コンソール(oracle.cabo.share.error.BaseErrorLog
)またはサーブレット・エラー・ログ(oracle.cabo.share.error.ServletErrorLog
)にレンダリングするErrorLog
インタフェースの実装を提供します。
RenderingContext
には、所定のレンダリングでノード・ツリーのコンテンツを変更する動的データを格納するためのメソッドも含まれています。これは、ノード・ツリーが変わらない場合にも、各ユーザーに異なるコンテンツを生成するメカニズムです。このトピックの詳細は、「データ・バインド」を参照してください。
UIX Componentsによって提供されるRenderingContext
インタフェースの2つの実装は、oracle.cabo.ui.RootRenderingContext
およびoracle.cabo.ui.ServletRenderingContext
です。これらの両方のクラスは、多くのコンテキスト情報にデフォルト値を設定しますが、様々なサブコンテキストをカスタマイズすることもできます。
RootRenderingContext
をインスタンス化するのは、レンダリング情報を完全に制御する必要があり、Webアプリケーションの管理にJavaサーブレットを使用しない場合のみにしてください。デフォルトでは、次のように初期化されます。
OutputMethod
としてデフォルト値は設定されません。作成時に渡すか、createOutputMethod()
メソッドをオーバーライドして生成する必要があります。OutputMethod
がない場合は、レンダリングを実行できません。Agent
は不明なHTMLエージェントになります。LocaleContext
はサーバー自体のロケール情報になります。ErrorLog
は、デフォルトでは、検出するすべてのエラーをJavaのSystem.err
ストリームに出力します。ただし、ストリームが構成されている必要があります。ただし、Javaサーブレットを使用してWebアプリケーションを実行するか、JavaServer Pages(JSP)を生成している場合は特に、必ずServletRenderingContext
を使用する(またはUIX Controllerで構成する)ことになります。ServletRenderingContext
では、ServletRequest
またはJSPのPageContext
から収集できる情報から収集されたコンテキストをデフォルト設定にします。
PageContext
が指定されている場合は、OutputMethod
はJSPの出力ストリームに基づきます。また、サーブレットを使用している場合は、PrintWriter
に渡す必要があります。OutputMethod
がない場合は、レンダリングを実行できません。Agent
は、リクエストまたは渡されるコンテキストのプロパティに基づいて自動的に構成されます。LocaleContext
も、リクエストまたはコンテキストに基づいて自動的に構成されます。ErrorLog
は、サーブレットの適切なエラー・ログに設定されます。最後に、指定したリクエストに対してServlet
に基づいたページの設定およびレンダリングを行うサンプル・コードを次に示します。
public void renderStartPage(
Servlet servlet,
ServletRequest request,
ServletResponse response,
PrintWriter out
) throws IOException
{
ServletRenderingContext context = new ServletRenderingContext(servlet, request, response, out);
UINode rootNode = getStartPageTree();
rootNode.render(context);
}
このセクションでは、UIX ComponentsがUINodeツリーおよびRenderingContext
をエンド・ユーザー向けの出力に変換するプロセスについて説明します。ここで示す資料は、情報提供を目的とするもので、UIX Componentsのページ・レンダリング・フレームワークを使用するための必須知識ではありません。
レンダリングは、UINode.render()
のコールで開始しますが、このメソッドで直接発生することはほとんどありません。かわりに、UINode
ではRenderer
を使用してコンテンツを書き込みます。Renderer
クラスは、次の処理を行う小規模なJavaインタフェースです。
UINode
からの属性の取得
UINode
をRenderer
に連結する方法を説明します。UINode
は、ネームスペースおよび名前の文字列のペアによって識別されます。偶然の一致ではなく、UIXのRendererManager
クラスではネームスペースと名前によってRenderer
を検出することができます。また、RenderingContext
にはgetRendererManager()
メソッドがあります。このため、ほとんどの場合、UINode
がレンダリングのために実行する処理は、RendererManager
を取得し、これを使用してRenderer
を取得して、制御をRenderer
に渡すことだけです。
Renderer
が制御を得ると、UINode
と対話し必要に応じて属性および子を取得し、出力を記述する必要がある場合はOutputMethod
をコールします。UINode
は、出力の内容を認識も確認もしません。要求された際に属性および子をRenderer
に渡すだけです。
Renderer
は、常に子UINode
のレンダリングを要求できます。ここで、UINode.getIndexedChild()
またはUINode.getNamedChild()
をコールして子を取得し、その子に対してUINode.render()
をコールします。プロセスがその子から新たに開始されます。つまり、独自のRenderer
を取得し、それが孫を取得し、同じ処理が繰り返されます。
この設計には次のいくつかの含意があります。
Renderer
を置き換えると、同じネームスペースおよび名前ですべてのUINode
の動作を完全に変更できます。
RendererManager
を置き換えると、ページ全体の出力を完全に変更できます。つまり、1つのUINode
ツリーを再利用して、別のユーザー・エージェントに異なるルック&フィールで出力できます。同じツリーを使用して、デスクトップWebブラウザおよびハンドヘルド・デバイス両方に対して調整されたHTMLを出力できます。
Renderer
は、子がレンダリングされるタイミングだけでなく、子がレンダリングされるかどうかも制御します。このため、索引付けされた子または名前の付けられた子を追加するだけでは、その子が表示されることは保証されません。Renderer
が、その子を明示的に要求する必要があります。
Renderer
では、ButtonBean
、LinkBean
またはその他のBeanクラスを認識するのではなく、単に、UINode
のみを認識します。つまり次のことを意味します。
UINode
を直接実装するだけで、新しいレンダラを作成する必要はありません。
Renderer
は、UINode
に値を設定できません。つまりUINode
ツリーがレンダリングされても、それが変更されることはありません。
Renderer
は、常に子UINode
に、Renderer
を直接取得するかわりに自身をレンダリングすることを要求するため、UINode
は必ずしもRenderer
を使用する必要はありません。ただし、レンダリング・コードを別のクラスに分けておくとわかりやすくなります。
ページのレンダリングについてのUIX機能の詳細は、後続のトピックで説明します。