!!![Clickのコントロール|http://incubator.apache.org/click/docs/controls.html] Clickでは、クライアントサイドの出力およびサーバサイドの処理を行う数々の豊富なコントロールを提供しています。ここでは、以下の話題について述べていきます。 * [コントロールのインターフェース|click?page=Controls#p1] - コントロールのインターフェースについて * [コントロールのコールバック|click?page=Controls#p2] - コントロールのイベントコールバックの仕組みについて * [コントロールのクラス構成|click?page=Controls#p3] - コントロール関連のJavaクラス * [メッセージプロパティ|click?page=Controls#p4] - コントロールのメッセージプロパティ * [コンテナ|click?page=Controls#p8] - 他のコントロールをまとめることができるコントロールであるコンテナ * [レイアウト|click?page=Controls#p11] - レイアウトオプションの説明とカスタムレイアウトの作成方法 ここでは、コントロール全般についての概略を扱います。個々のコントロールについては[[Clickが提供するコントロールの一覧|ControlList]]や[Javadoc|http://incubator.apache.org/click/docs/click-api/org/apache/click/control/package-summary.html]、[examples|http://incubator.apache.org/click/docs/examples.html]を参照してください。 !!コントロールのインターフェース Clickのコントロールは、ユーザーの入力を処理するサーバサイドのコンポーネントを提供し、そしてユーザーへの表示を行います。Visual BasicのコントロールやDelphiのコンポーネントに相当するものなのです。 コントロールは、onProcessメソッドでユーザーの入力を処理し、toString()メソッドで、表示用HTMLを生成します。コントロールが処理され出力される一連の流れは以下の図1のようになります。 {{ref_image control-post-sequence-diagram.png}} 図1 ポストされたときの処理の流れ - created with Enterprise Architect courtesy [Sparx Systems|http://www.sparxsystems.com.au/] Clickにおけるコントロールは、全てControlインターフェースを実装しなければなりません。 このControlインターフェースは下図2になります。 {{ref_image control-class-diagram.png}} 図2 Control インターフェース図 - created with Enterprise Architect courtesy [Sparx Systems|http://www.sparxsystems.com.au/] Controlインターフェースのメソッドには以下のものがあります。 *[getContext()|http://incubator.apache.org/click/docs/click-api/org/apache/click/Control.html#getContext()] - リクエストの[Context|http://incubator.apache.org/click/docs/click-api/org/apache/click/Context.html]が取得できます。 *[getHtmlImports()|http://incubator.apache.org/click/docs/click-api/org/apache/click/Control.html#getHtmlImports()] - コントロールを使う際に必要となるHTMLヘッダーのimport文を定義します。 *[getId()|http://incubator.apache.org/click/docs/click-api/org/apache/click/Control.html#getId()] - HTML要素のid属性値を定義します。 *[setListener()|http://incubator.apache.org/click/docs/click-api/org/apache/click/Control.html#setListener(java.lang.Object,%20java.lang.String)] - コントロールのコールバックリスナーをセットします。 *[getMessages()|http://incubator.apache.org/click/docs/click-api/org/apache/click/Control.html#getMessages()] - コントロール用のローカライズされたメッセージマップを定義します。 *[getName()|http://incubator.apache.org/click/docs/click-api/org/apache/click/Control.html#getName()]/[setName()|http://incubator.apache.org/click/docs/click-api/org/apache/click/Control.html#setName(java.lang.String)] - ページモデルやフォームフィールドでの名前を定義します。 *[getParent()|http://incubator.apache.org/click/docs/click-api/org/apache/click/Control.html#getParent()]/[setParent()|http://incubator.apache.org/click/docs/click-api/org/apache/click/Control.html#setParent(java.lang.Object)] - コントロールの親コントロールを定義します。 *[onDeploy()|http://incubator.apache.org/click/docs/click-api/org/apache/click/Control.html#onDeploy(javax.servlet.ServletContext)] - Clickの起動時にコントロールに必要なファイルなどのリソースを配置するための設定を行います。 *[onInit()|http://incubator.apache.org/click/docs/click-api/org/apache/click/Control.html#onInit()] - イベントハンドラーの初期化を行います。 *[onProcess()|http://incubator.apache.org/click/docs/click-api/org/apache/click/Control.html#onProcess()] - リクエストのイベントハンドラを処理します。 *[onDestory()|http://incubator.apache.org/click/docs/click-api/org/apache/click/Control.html#onDestroy()] - イベントハンドラーの破棄処理を行います。 *[onDestory()|http://incubator.apache.org/click/docs/click-api/org/apache/click/Control.html#render(org.apache.click.util.HtmlStringBuffer)] - コントロールのHTML表現を生成します。 !!コントロールのコールバック Clickのコントロールは、java.awt.ActionListenerコールバックに似たイベントコールバックの機構を提供します。 Clickは2つの方式のアクションリスナーをサポートします。1つ目はActionListenerインタフェースを利用してコンパイル時タイプセーフを行う方式、二つ目は[setListener(Object,String)|http://incubator.apache.org/click/docs/click-api/org/apache/click/Control.html#setListener(java.lang.Object,%20java.lang.String)]メソッドでコールバックメソッドの名前を指定する方式です。2つ目の方式はコード量が少なくなりますがタイプセーフではありません。 これら2つのアクションリスナー方式は以下のようになります: {{code java public class ActionDemo extends BorderPage { // Uses listener style 1 public ActionLink link = new ActionLink(); // Uses listener style 2 public ActionButton button = new ActionButton(); public ActionDemo() { // Verbose but provides compile time safety link.setActionListener(new ActionListener() { public boolean onAction(Control source) { return onLinkClick(source); } }); // Succinct but typos will cause runtime errors button.setListener(this, "onButtonClick"); } // Event Handlers --------------------------------------------------------- public boolean onLinkClick(Control source) { .. return true; } public boolean onButtonClick() { .. return true; } } }} すべてのコールバック関数はbooleanかjava.lang.Booleanを返す必要があります。 コールバック関数がtrueを返すと、他のコントロールの処理へと処理が続行されます。対してコールバック関数がfalseを返した場合、他のコントロールの処理はこれ以上実行されません。falseを返すことによってあなたは処理を中断し、別ページへのリダイレクトやフォワードによる遷移を効果的に行うことができます。 この実行の仕組みに関しては、[ページが実行される処理の流れ|click?page=Pages#p2]を参照してください。 処理の続行を停止し、別の処理をすることは非常に簡単です。 例えばonRender()で非常にコストのかかるデータベースの処理を実行するとしましょう。イベントハンドラでfalseを返すことで、この処理をスキップし別のページへフォワードすることができます。 !!コントロールのクラス構成 コントロール関連の主要なクラスは、[org.apache.click.control|http://incubator.apache.org/click/docs/click-api/org/apache/click/control/package-summary.html]パッケージで定義されています。このパッケージは、主要なHTML要素に対応するコントロールが含まれています。 拡張コントロール関連のクラスは、[org.apache.click.extras.control|http://incubator.apache.org/click/docs/extras-api/org/apache/click/extras/control/package-summary.html]パッケージで提供されています。Click Extrasのクラスは、サードパーティのフレームワークへの依存性を含むものもあります。 これらコントロールクラスのサブセットは下図3のように表すことができます。 {{ref_image control-package-class-diagram.png}} 図3 パッケージのクラス図 - created with Enterprise Architect courtesy [Sparx Systems|http://www.sparxsystems.com.au/] このなかでも特に要となるのが以下のコントロールです。 * [[ActionLink]] - リスナを呼び出すことが可能なリンク * [Field|http://incubator.apache.org/click/docs/click-api/org/apache/click/control/Field.html] - フォームのフィールドのためのabstractなコントロール. * [[Form]] - 入力フォーム * [[Submit]] - リスナを呼び出すことが可能な送信ボタン * [[TextField]] - リスナを呼び出すことが可能なテキストボックス これらのコントロールクラスは、動作をカスタマイズするために派生することを考慮に入れて設計されています。コントロールの全てのフィールドはprotectedとなっており、アクセサメソッドはpublicになっています。 またこれらのコントロールを組み合わせて、より複雑なコントロールを構築することも可能です。例えば[[CreditCardField]]は、[[Select]]コントロールを利用して複数のカードの種類を出力しています。 !!メッセージプロパティ コントロールで使用するフィールドバリデーションメッセージとHTML整形文字列はプロパティファイルに切り出されます。このプロパティファイルを使用することによって、Clickアプリケーションを個々の言語用にローカライズすることができます。 !メッセージの解決 メッセージは、状況にあわせて取得できるよう、特定の順番で探索されます。 そのコントロールのもの、そのページのもの、アプリケーション全体のものとがあります。 その取得の順序は以下のようになります。 '''ページのメッセージ''' まずページクラスに紐付けされているメッセージを探します。 Loginページの場合、そのメッセージプロパティは以下のファイルで定義されます。 /com/mycorp/page/Login.properties 特定のページでメッセージを調整したい場合には、ここに記述します。 '''ページ全体のメッセージ''' 次にアプリケーション全体のページに対して設定されているメッセージを探します。 /click-page.properties アプリケーション全体のページで使いたいメッセージがあれば、ここに記述します。 '''コントロールのメッセージ''' 次にコントロールに対して紐付けされているメッセージを探します。 CustomTextFieldコントロールに対するメッセージは、以下のファイルに記述します。 /com/mycorp/control/CustomTextField.properties '''アプリケーション全体のコントロールのメッセージ''' ここまでのもので見つけられなかった場合、最後にアプリケーション全体のコントロールに対して 紐付けされているメッセージを探します。 アプリケーション全体のコントロールに対するメッセージは、以下のファイルに記述されます。 /click-control.properties !コントロールのプロパティ click-control.propertiesをカスタマイズする には、クラスパスにこのファイルを追加し、値を設定していくだけです。 このメッセージプロパティをカスタマイズする時には、設定したい値だけでなく、既定で設定してある以下の項目 すべてを記述する必要があります。 {{code java # Click Control messages field-maxlength-error={0} must be no longer than {1} characers field-minlength-error={0} must be at least {1} characters field-required-error=You must enter a value for {0} file-required-error=You must enter a filename for {0} label-required-prefix= label-required-suffix=* label-not-required-prefix= label-not-required-suffix=  not-checked-error=You must select {0} number-maxvalue-error={0} must not be larger than {1} number-minvalue-error={0} must not be smaller than {1} select-error=You must select a value for {0} table-first-label=First table-first-title=Go to first page table-previous-label=Prev table-previous-title=Go to previous page table-next-label=Next table-next-title=Go to next page table-last-label=Last table-last-title=Go to last page table-goto-title=Go to page table-page-banner={0} items found, displaying {1} to {2}. table-page-banner-nolinks= {0} items found, displaying {1} to {2}. table-page-links=[{0}/{1}] {2} [{3}/{4}] table-page-links-nobanner=[{0}/{1}] {2} [{3}/{4}] table-no-rows-found=No records found. table-inline-first-image=/click/paging-first.gif table-inline-first-disabled-image=/click/paging-first-disabled.gif table-inline-previous-image=/click/paging-prev.gif table-inline-previous-disabled-image=/click/paging-prev-disabled.gif table-inline-next-image=/click/paging-next.gif table-inline-next-disabled-image=/click/paging-next-disabled.gif table-inline-last-image=/click/paging-last.gif table-inline-last-disabled-image=/click/paging-last-disabled.gif table-inline-page-links=Page {0} {1} {2} {3} {4} # Message displayed when a error occurs when the application is in "production" mode production-error-message=
The application encountered an unexpected error.
}} !メッセージへのアクセス Fieldクラス及びその派生クラスは階層化されたバリデーションエラーメッセージなどの表示用メッセージに 紐付けされるメッセージリソースをサポートしています。 これらのローカライズされたメッセージは、以下のFieldのメソッドを通じてアクセス可能です。 * [getMessage(String)|http://incubator.apache.org/click/docs/click-api/org/apache/click/control/AbstractControl.html#getMessage(java.lang.String)] * [getMessage(String, Object)|http://incubator.apache.org/click/docs/click-api/org/apache/click/control/AbstractControl.html#getMessage(java.lang.String,%20java.lang.Object)] * getMessage(String, Object[]) * [getMessages()|http://incubator.apache.org/click/docs/click-api/org/apache/click/control/AbstractControl.html#getMessages()] * [setErrorMessage(String)|http://incubator.apache.org/click/docs/click-api/org/apache/click/control/Field.html#setErrorMessage(java.lang.String)] * [setErrorMessage(String, Object)|http://incubator.apache.org/click/docs/click-api/org/apache/click/control/Field.html#setErrorMessage(java.lang.String,%20java.lang.Object)] これらのメソッドは、リクエストのLocaleを利用して、紐付けされた文字列リソースを探します。そしてMessageFormatで文字列の整形を行います。 !!Container [Container|http://incubator.apache.org/click/docs/click-api/org/apache/click/control/Container.html]は他のコントロールを包含することができるコントロールで、コンポーネントの階層をまとめるものです。 Containerではコンポーネントを追加、削除したり他のコントロールを検索したりできます。 以下の一覧はContainerの例です: * [Form|http://incubator.apache.org/click/docs/click-api/org/apache/click/control/Form.html] - デフォルトのフィールドレイアウトやエラーフィードバックを提供するHTMLフォーム。 * [Panel|http://incubator.apache.org/click/docs/click-api/org/apache/click/control/Panel.html] - ページに類似してこのContainerは自身のテンプレートとモデルを提供します。 * [FieldSet|http://incubator.apache.org/click/docs/click-api/org/apache/click/control/FieldSet.html] - 子コントロールの周りにボーダーを描画します。 これらのContainerは図4のように描かれます。 {{ref_image container-package-class-diagram.png}} 次に示すクラスはカスタムコンテナを作成するための便利な拡張ポイントを提供します: *[AbstractContainer|http://incubator.apache.org/click/docs/click-api/org/apache/click/control/AbstractContainer.html] *[AbstractContainerField|http://incubator.apache.org/click/docs/click-api/org/apache/click/extras/control/AbstractContainerField.html] !AbstractContainer カスタムコンテナを簡単に作成することが出来ます。例としてHTML divまたはspan要素を挙げます。 {{code java public class Div extends AbstractContainer { public Div(String name) { super(name); } public String getTag() { // Return the control's HTML tag. return "div"; } } }} 新しく作成したコンテナを試すには以下のようにします:(このテストで使用しているMockContextについては[モックテストサポート|http://incubator.apache.org/click/docs/mock-api/overview-summary.html]ドキュメンテーションに記述されています) {{code java public class Test { public static void main (String args[]) { // Create mock context in which to test the container. MockContext.initContext(); // Create a div instance called "mydiv" String containerName = "mydiv"; Div mydiv = new Div(containerName); // Add a control to the container mydiv.add(new TextField("myfield")); System.out.println(mydiv); } } }} この例を実行すると以下のような出力になります: {{code xml
}} !AbstractContainerField AbstractContainerFieldはFieldを継承しContainerインタフェースを実装しています。これはFieldとContainerの両方が必要な場合に便利な基底クラスとして提供されます。 以下はAbstractContainerFieldを使用した例です: {{code java public class FieldAndContainer extends AbstractContainerField { public FieldAndContainer(String name) { super(name); } // Return the html tag to render public String getTag() { return "div"; } } }} 作成した新しいクラスのテストは以下のようなコード断片になります: {{code java public class Test { public static void main (String args[]) { // Create mock context in which to test the container. MockContext.initContext(); // Create a FieldContainer instance called "field_container" String containerName = "field_container"; FieldAndContainer fieldAndContainer = new FieldAndContainer(containerName); // Add a couple of fields to the container fieldAndContainer.add(new TextField("myfield")); fieldAndContainer.add(new TextArea("myarea")); System.out.println(fieldAndContainer); } } }} このコード断片の実行は以下のようになります: {{code xml
}} !!レイアウト [Form|http://incubator.apache.org/click/docs/click-api/org/apache/click/control/Form.html]のようなコントロールはレイアウトとエラーレポートを自動で行います。そして多くの場合オートレイアウトは十分に良いです。 けれどもカスタムした、または複雑なレイアウトの場合、Formはいつもベストな選択肢ではありません。 カスタムレイアウトを作成するために2つのアプローチがあります。 +テンプレートアプローチ - Velocity、FreeMarkerまたはJSPのようなテンプレートエンジンを使用してレイアウトをHTMLマークアップのように宣言します。 +プログラム可能なアプローチ - Javaでカスタムレイアウトコンポーネントを構築します。このオプションはSwingを使用したコンポーネント構築と類似します。 !テンプレートレイアウト テンプレートアプローチを選択するとページとレイアウトロジックをうまく分離することが出来ます。例: {{code java // EmployeePage.java public EmployeePage extends Page { private Form form; public void onInit() { // Create form Form form = new Form("form"); // Add a couple of fields to the form form.add(new TextField("firstname")); form.add(new TextField("lastname")); form.add(new IntegerField("age")); form.add(new DoubleField("salary")); // Add a submit button to form form.add(new Submit("submit", "Add Employee")); // Add form the page addControl(form); } } }} DIV
とHTMLリスト
    タグを使用したレイアウトを作成したい場合を想像してみます。 以下のようなテンプレートエンジンとしてVelocityを使用した'''employee.htm'''テンプレートを提供することが出来ます。 {{code html ${form.startTag()}
    1. ${form.fields.firstname}
    2. ${form.fields.lastname}
    3. ${form.fields.age}
    4. ${form.fields.salary}
    ${form.fields.submit} ${form.endTag()} }} CSSスタイルシートを使用して上記のマークアップを装飾された見た目のFormに変換することができます。 テンプレートアプローチを使用することには賛否両論あります。 テンプレートアプローチの1つの利点は、レイアウトは明白で必要であれば調整が簡単なことです。例としてdivとオーダーリストを使用する代わりに、テンプレートを変更するだけでテーブルレイアウトに影響を与えます。 テンプレートアプローチの欠点は、冗長なことです。 上記の例ではJavaでフィールドを作成し、それらをテンプレートにマークアップで記述しています。 もし例に新しいフィールドを追加する要件が発生した場合、Pageクラスにもテンプレートにもフィールドを追加する必要があります。 大抵の場合、テンプレートエンジンを使用して'''汎用化された'''レイアウトを利用できます。[Macro.vm|http://incubator.apache.org/click/docs/click-api/org/apache/click/control/Form.html#velocity-macros]はVelocityを使用した汎用Formレイアウトの例です。 !プログラム化レイアウト テンプレートアプローチで紹介した冗長性と戦う場合、プログラム化アプローチを採用して、普通のJavaといくつかのClickクラス群を使用してカスタムレイアウトを構築できます。 Click extras では[HtmlForm|http://incubator.apache.org/click/docs/click-api/org/apache/click/extras/control/HtmlForm.html]と[HtmlFieldSet|http://incubator.apache.org/click/docs/click-api/org/apache/click/extras/control/HtmlFieldSet.html]という名前のこの条件に当てはまる2つの役立つクラスを提供しています。 FormやFieldSetが描画で使用するTableレイアウトと違い、HtmlFormとHtmlFieldSetはそれに追加されたコントロールを順に描画し、どんな余分なマークアップも追加しません。HtmlFormの例は以下のようになります。 カスタムレイアウトを作成する場合、HTMLコンストラクトList