XUL Tutorial:Manipulating Lists
出典: MDC
XUL では、リストボックスを操作するために、いくつか専用のメソッドが用意されています。
目次 |
[編集] リストの操作
リストボックス (listbox) 要素には、中の項目を取得したり操作したりするメソッドがいくつか用意されています。
これらを使わず、標準の DOM 関数の方を使用して、リストボックスを操作しても問題はないのですが、
専用関数の方が若干簡単で、かつ (意識しなくても) 正しい操作を行うことができるため、
可能な限り、リストボックス専用関数の方を利用することを推奨します。
リストの末尾に、新たに項目を追加するには、appendItem() 関数を使用します。
この関数は、文字列ラベルを引数にとることを除いて、DOM の appendChild() 関数と類似していますが、リストを構成する要素のどれに追加すればよいのかについて悩まずに済みます。
以下に例を示します。
<script>
function addItem(){
document.getElementById('thelist').appendItem("Thursday", "thu");
}
</script>
<listbox id="thelist"/>
<button label="Add" oncommand="addItem();"/>
appendItem() は、2 つの引数をとり、1 つめの label には「Thursday」を、 2 つめの value には「thu」を渡しています。
この 2 つの引数は、listitem 要素の、label 属性と value 属性に対応しています。
この value はオプションで、項目にスクリプトからアクセスするときのみに使用する専用の値を結びつけたいときに使用します。
また、同様に新たな項目を挿入するための insertItemAt() 関数と、既存の項目を削除する removeItemAt() 関数も存在します。
これらの構文は以下のようになります。
list.insertItemAt(3, "Thursday", "thu"); list.removeItemAt(3);
insertItemAt() 関数には、新規の項目を挿入する位置を示す引数が追加で必要です。
新規の項目は、インデックスとして指定された位置に挿入されます。
つまり、この例では、新規項目は、位置「3」に挿入され、元々あった項目は位置「4」にずれることになります。
最初の項目は、位置「0」であることに留意してください。
また、removeItemAt() 関数は、インデックスとして指定された項目を取り除きます。
これらの 3 つのメソッドは、リスト以外のいくつかの XUL 要素でも利用可能で、同じ流儀で項目を扱うことができます。
実は、これらのメソッドは、nsIDOMXULSelectControlElement インターフェイスに含まれているため、
このインターフェイスを実装している全ての XUL 要素が、これらのメソッドを持っていることになります。
そこに含まれる要素としては、menulist、radiogroup、tabs があります。
例えば、メニューリストに新規項目を追加する場合も、リストボックスと同じ構文を使うことが可能です。
また、これらの関数を利用した場合は、状況に応じて、適切な種類の要素が追加されます。
[編集] リスト項目の選択
nsIDOMXULSelectControlElement インターフェイスには、他にも 2 つのプロパティ selectedIndex と selectedItem が用意されています。
前者は、選択されている項目のインデックスを返し、後者は選択されている要素を返します。
具体的には、メニューリストに対して selectedItem を呼び出した場合、選択された menuitem が返ります。
また、選択されている項目が無い場合は、selectedIndex は -1 を返し、 selectedItem は null を返します。
[編集] 選択された項目を取得する
この 2 つのプロパティは、主として select イベントの処理から参照されます。 以下に、例を示します。
<listbox id="thelist" onselect="alert(this.selectedItem.label);"> <listitem label="Short"/> <listitem label="Medium"/> <listitem label="Tall"/> </listbox>
リスト内の項目が選択されたときに、リストボックスに対して、select イベントが発生します。
このとき、select ハンドラは、リスト内で選択された項目のラベルを含んだアラートを表示します。
なお、ハンドラの処理では、select イベントが発生したことを契機に呼び出されるため、呼び出されたときには、必ず項目は選択されているものと見なしてもかまいませんが、
それ以外の処理では、まず selectedItem が null でないことを確認してから、処理を続けるようにする必要があります。
また、select イベントは、radiogroup 要素内のラジオボタンが選択された場合や、
tabs 要素内のタブが選択された場合にも発生します。
しかしながら、メニューリストでは select イベントは発生しません。
そのかわり、項目が選択されたときの処理のために command イベントを利用することが可能です。
tabs 要素を処理する場合は、tabbox 要素の関数を利用する方が便利な場合がしばしばあります。
具体的には、tabs 要素にも selectedIndex プロパティがあり、選択されているタブのインデックスを返しますが、
選択項目を取得する場合は、通常タブボックスの selectedTab プロパティの方を利用します。
あるいは、selectedPanel プロパティによって、選択されているパネル、つまりタブに結びつけられている内容を取得することも可能です。
[編集] 選択範囲を変更する
上記の選択に関するプロパティは、すべて選択を変更するために新たな値を代入することが可能です。
次の例では、radiogroup 要素の selectedIndex プロパティを、テキスト入力欄に入力された値で変更します。
このコードは、UI をフールプルーフにするために必要な、入力値が範囲外でないかをチェックするような処理は行っていません。
この手のエラーチェックは、実際のアプリケーションを作成するときには、確実に追加しておくべきだと思います。
<script>
function doSelect(){
var val = document.getElementById('number').value;
val = Number(val);
if (val != null)
document.getElementById('level').selectedIndex = val - 1;
}
</script>
<hbox align="center">
<label value="Enter a number from 1 to 3:"/>
<textbox id="number"/>
<button label="Select" oncommand="doSelect();"/>
</hbox>
<radiogroup id="level">
<radio label="Excellent"/>
<radio label="Good"/>
<radio label="Poor"/>
</radiogroup>
リストボックスは、複数項目の選択のために nsIDOMXULMultiSelectControlElement インターフェイスもサポートします。
このインターフェイスには、複数項目の選択を取り扱うための専用関数がいくつか用意されています。
例えば、 selectedItems プロパティは、選択状態の項目のリストを保持し、 selectedCount プロパティはその項目数を保持しています。
これらのプロパティは、リストの内容を繰り返し、各項目に対して何らかの処理を行ためによく利用されます。
選択項目のリストに対して繰り返し処理を行うときには注意が必要です。
処理中にリスト内の項目を変更した場合、リストの内容は変更され、選択を取り扱うプロパティは異なる値を返すようになるかもしれません。
リストを操作する場合、項目を使用する方が、インデックスを使用するよりも便利な理由の 1 つはここにあります。
[編集] 選択項目を削除する
選択項目を正しく削除する方法を、以下の例に示します。
<script>
function deleteSelection(){
var list = document.getElementById('thelist');
var count = list.selectedCount;
while (count--){
var item = list.selectedItems[0];
list.removeItemAt(list.getIndexOfItem(item));
}
}
</script>
<button label="Delete" oncommand="deleteSelection();"/>
<listbox id="thelist" seltype="multiple">
<listitem label="Cheddar"/>
<listitem label="Cheshire"/>
<listitem label="Edam"/>
<listitem label="Gouda"/>
<listitem label="Havartie"/>
</listbox>
while ループ内では...
- 最初に選択項目 (selectedItem) のインデックス 0 の値を取得しています。項目が削除されて、配列のサイズが小さくなっても、最初の選択項目は常に取得可能だからです。
- 次に、
removeItemAt()関数を使用して、取得した項目を削除しますが、この関数にはインデックスを渡す必要があります。 - このため、
getIndexOfItem()関数を利用して、項目からインデックスへの変換を行います。なお、逆にインデックスから項目を求めるには、getItemAtIndex()関数を用います。
nsIDOMXULMultiSelectControlElement インターフェイスには、項目の選択状態を変更するためのメソッドも用意されています。
具体的には、addItemToSelection() 関数は、そのとき選択されている項目は残したまま、項目を 1 つ選択されている状態に追加します。
また、removeItemFromSelection() 関数は、選択されている項目群から 1 項目を除外します。
[編集] リストのスクロール
リストボックス (listbox) の行数が表示枠を超えるような場合、利用者がリストのスクロールを行えるようにスクロールバーが表示されます。
このときスクロール位置は、リストボックスの 2 つのメソッドによって調整することが可能です。
scrollToIndex() メソッドは、指定された行へスクロールを行います。
このときスクロールは、対象行が項目リストの末尾近くにあるときを除いて、その行が表示枠の上端に位置するように行われます。
ensureIndexIsVisible() メソッドも、同様に指定された行を表示するようにスクロールを行いますが、項目がすでに表示されている場合は何もしません。
つまり、前者の関数は特定の行へのスクロールに、後者は行が見えるようにするために利用します。
また、インデックスの代わりに項目を引数にとる ensureItemIsVisible() メソッドもあります。
以下の例で、スクロール位置をいろいろ変えながら、2 つの関数の効果の違いを比べてみてください。
<button label="scrollToIndex"
oncommand="document.getElementById('thelist').scrollToIndex(4);"/>
<button label="ensureIndexIsVisible"
oncommand="document.getElementById('thelist').ensureIndexIsVisible(4);"/>
<listbox id="thelist" rows="5">
<listitem label="1"/>
<listitem label="2"/>
<listitem label="3"/>
<listitem label="4"/>
<listitem label="5"/>
<listitem label="6"/>
<listitem label="7"/>
<listitem label="8"/>
<listitem label="9"/>
<listitem label="10"/>
<listitem label="11"/>
<listitem label="12"/>
</listbox>
次のセクションでは、XUL ボックスオブジェクトについて見ていきます。