このドキュメントでは、次のトピックについて説明します。
ツリービューコントロールは、階層形式でデータを表示するために使用します。 階層内の各ノードは、ツリービュー項目として内部的に表されます。 以下の図は、7 つのツリービュー項目を持つ 3 つの階層を表示する、簡単なツリービュー(任意のチェックボックス付き)です。
上記のツリービューコントロールには、[+/- ボタン(b)]、[行(l)]、[ルート行(r)]、および[チェックボックス(c)]の各 STYLE
フラグが設定されています。
階層間の各項目の高さとインデントは、それぞれ ITEM-H
属性および SPACING
属性で設定できます。 これらのどちらかがゼロの場合、デフォルト設定が使用されます。
ツリービュー項目のイメージは、「イメージリストコントロールの操作」で説明しているように、ツリービューコントロールにイメージリストコントロールを作成および関連付け、(項目ごとに)必要なイメージを、インデックスおよび/またはイメージハンドルを使用してイメージリストから選択することによって定義できます。
ツリービューコントロールでは小さいイメージしか使用されないため、リストビューコントロールと同じイメージリストを使用していない限り、イメージリストコントロールの[大きいイメージ(L)]スタイルを設定する必要はないことに注意してください。
リストビューコントロールとは異なり、ツリービューコントロールで選択できる項目は 1 つのみです。 現在の選択項目(存在する場合)は、ツリービューコントロールの(読み取り専用の)SELECTED-SUCCESSOR
属性をクエリすることによって取得できます。
また、ユーザーによる選択の他に、プログラムで項目の SELECTED
属性を設定したりクリアしたりすることにより、項目を選択したり選択を解除したりできます。
項目が選択されると、ツリービューコントロールの CLICK
イベントが発生します(抑制されていない場合)。このとき、対応する項目のハンドルがコントロールの ITEM
属性に設定されます。
項目をダブルクリックすると、ツリービューコントロールの ACTIVATE
イベントが発生します(抑制されていない場合)。 このイベントをアプリケーションで制御する場合、通常は選択された項目上でユーザー定義のデフォルトのアクションを実行します。この項目のハンドルは、ツリービューコントロールの ITEM
属性または SELECTED-SUCCESSOR
属性で取得できます。 選択された項目に対し、デフォルトでない他のアクションも使用できることに注意してください。ただし、これらのアクションは通常、他のメカニズムによってアクセスされます。 例えば、これらはアプリケーションが表示するコンテキストメニューに(通常、デフォルトのアクションと一緒に)リストされます。
[ダブルクリック展開(d)]STYLE
フラグが設定されている場合、子項目を持つツリービュー項目をダブルクリックすると、子項目が展開されアクティブ化されます。
また、ACTIVATE
イベントは、キーボードを使用してトリガすることもできます。 このためには、次の 2 つの方法のいずれかを使用します。
ツリービューコントロールの ACCELERATOR
属性に定義されているキーまたはキーの組み合わせを押す。 現時点で、コントロールにフォーカスがなくてもかまいません。
ツリービューコントロールにフォーカスがある場合、Enter キーを押す。 この方法は、ダイアログにデフォルトのプッシュボタンが含まれておらず、プッシュボタンに[OK ボタン (O)]の STYLE
フラグが設定されていない場合にのみ機能します。
どちらの場合も、項目が選択されていないと ACTIVATE
イベントは発生しません。
適切にソートできるようにするために(次のセクションを参照)ツリービュー項目のデータを英数字にする必要はありません。デフォルトは英数字ですが、項目の FORMAT
属性でサポートされている定義済みのタイプを使用できます。 また、項目の EDIT-MASK
属性を設定することによって、項目に編集マスクを適用できます。 ユーザーに表示される項目のラベルは、関連付けられている編集マスク(存在する場合)が適用された、項目の内部データの英数字表記になります。 編集マスクが使用されている場合、項目の内部データと表示データ間の変換は、MOVE EDITED
ステートメントと互換性があります。 それ以外の場合、内部データと表示されたデータ間およびその逆の変換は、データを Natural スタックにコピーしたり、Natural スタックからコピーする場合に発生する変換と互換性があります(STACK TOP DATA
および INPUT
ステートメントを参照)。 例えば、数値は、現在の小数点文字を使用して(DC
パラメータで定義されたように)表示されます。必要に応じて、負の場合は先頭にマイナスを付けることができます。日付値は、DTFORM
パラメータで定義されたフォーマットで表示されます。論理値は、真の場合は "X" として、偽の場合は空白として表示されます。
英文字以外のツリービュー項目の使用例を以下に示します。
PROCESS GUI ACTION ADD WITH PARAMETERS HANDLE-VARIABLE = #TVITEM-DATE TYPE = TREEVIEWITEM PARENT = #TV-1 STRING = '+123.456' FORMAT = FT-DECIMAL EDIT-MASK = '+ZZZ,ZZ9.999' END-PARAMETERS GIVING *ERROR
この場合、指定した項目ラベル(STRING
属性値)は、指定した編集マスク(+ZZZ,ZZ9.999)と互換性のあるフォーマットの有効な数値である必要があります。 ラベルは内部的に、指定したフォーマット FT-DECIMAL(= P10.5)に対応するデータタイプと長さに変換されます。
ツリービュー項目の基となるデータには直接アクセスできないことに注意してください。 項目のデータは、項目のラベル経由でのみ設定または取得できます。
ツリービュー項目は、SORT-ITEMS
アクションを呼び出すことにより、ソートされた順序で挿入することも、挿入後に明示的にソートすることもできます。 ツリービューコントロールまたは挿入するツリービュー項目の SORTED
属性が TRUE
に設定されている場合、項目はアルファベットの昇順で挿入されます。 挿入後にソートする場合、内部データに応じて、項目は任意で昇順または降順でソートされます(最後のセクションを参照)。 詳細については、SORT-ITEMS
アクションのドキュメントを参照してください。 ソート対象の項目の基本となるフォーマット(FORMAT
属性で定義)を比較可能なタイプに設定するのは、プログラマの責任であることに注意してください。 例えば、整数値と浮動小数点値は一緒に使用できますが、整数値と日付値は一緒に使用できません。
ツリービューコントロールのラベル編集プロセスは、リストビューコントロールと同じです。 このため、この内容の詳細については、「ツリービューおよびリストビューコントロールでのラベル編集」を参照してください。
SORTED
属性が設定されている場合でも、ラベル編集の操作が完了した後は、項目の順序付けが自動的に再実行されることはありません。 これが必要な場合は、以下の例に従って操作してください。 まず、後で使用する変数をいくつか定義します。
01 #CONTROL HANDLE OF GUI 01 #ITEM HANDLE OF TREEVIEWITEM 01 #SORTITEM HANDLE OF TREEVIEWITEM
また、ツリービューコントロールの名前は #TV-1
であるとします。
ツリービューコントロールの AFTER-EDIT
イベントでは、(まだ完了していない)編集プロセスに影響があるため、非同期で順序付けを再実行できません。 代わりに、#SORTITEM
変数を設定し、編集プロセスの完了後に順序付けを再実行するよう指定します。 この処理は、ツリービュー項目をソートする場合にのみ実行する必要があります。
#CONTROL := *CONTROL #ITEM := #CONTROL.ITEM IF #CONTROL.SORTED OR #ITEM.SORTED #SORTITEM := #ITEM ELSE #SORTITEM := NULL-HANDLE END-IF
この例では、ツリービューコントロール自体が提供しているデフォルトのソート(アルファベットの昇順)を使用することが想定されていることに注意してください。
項目の順序付け再実行の実際の作業は、ダイアログの IDLE
イベントで非同期的に行われます。
IF #SORTITEM <> NULL-HANDLE PROCESS GUI ACTION SORT-ITEMS WITH #SORTITEM.PARENT GIVING *ERROR RESET #SORTITEM END-IF
コントロールに単一のコンテキストメニューのみを使用する場合、表示するコンテキストメニューのハンドルをコントロールの CONTEXT-MENU
属性に設定し、そのままにしておきます。 ただし、ツリービューコントロールに複数のコンテキストメニューを表示する必要があることがよくありますが、このアプローチでは柔軟性が足りません。
上記の問題に対応するために、CONTEXT-MENU
イベントが導入されました(上記の同じ名前の属性と混同しないように注意してください)。 このイベント(無効にされていない場合)は、CONTEXT-MENU
属性が評価される直前にターゲットのコントロールで発生します。これによって、アプリケーションは最初に、適切なコンテキストメニューのハンドルにこの属性をダイナミックに設定できます。
例として、ダイアログエディタで 2 つのコンテキストメニューを定義したとします。1 つは項目に関連するコマンドが組み込まれている #CTXMENU-ITEMS
で、もう 1 つは汎用コマンド(表示モードの切り替えなど)が組み込まれている #CTXMENU-DEFAULT
です。 この場合、次の CONTEXT-MENU
イベントを使用することができます。
#CONTROL := *CONTROL IF #CONTROL.SELECTED-SUCCESSOR <> NULL-HANDLE #CONTROL.CONTEXT-MENU := #CTXMENU-ITEMS ELSE #CONTROL.CONTEXT-MENU := #CTXMENU-DEFAULT END-IF
ローカルデータの定義は以下のように想定されています。
01 #CONTROL HANDLE OF GUI
この例では、項目が占めている位置をユーザーが右クリックすると、コンテキストメニュー #CTXMENU-ITEMS
が表示されます。それ以外の場合は、#CTXMENU-DEFAULT
が表示されます。
この手法をさらに活用して、選択された項目のタイプに固有のコンテキストメニューを表示することもできます。
ツリービュー項目が展開または圧縮されると、イベントが抑制されていなければ、コントロールの EXPAND
イベントまたは COLLAPSE
イベントがそれぞれ発生します。 多数あるイベントの中のこれらのイベントにより、ツリービュー項目をオンデマンドでダイナミックに追加したり削除したりできます。
例えば、以下のコードは、EXPAND
イベントに応答して 3 つの項目をダイナミックに作成する方法を示しています。 このコードでは、項目を入力する位置に、空の STRING
属性値を持つダミーのプレースホルダ項目がすでに配置されているものとしています。 プレースホルダは、ダイアログエディタでスタティックに定義することも、ツリービュー項目を最初に作成するときにダイナミックに定義することもできます。 プレースホルダの目的は、"+" ボタン([+/- ボタン(b)]STYLE
によってボタン表示が有効に設定されている場合)が親ノードの隣に確実に表示されるようにすることです。
以下の EXPAND
イベントコードでは、変数 #TGT-ITEM
にツリービュー項目のハンドルが設定されているものとしています。このツリービュー項目の下に、ツリービュー項目がダイナミックに作成されます。
#CONTROL := *CONTROL #ITEM := #CONTROL.ITEM IF #ITEM = #TGT-ITEM #TVITEM-DYN := #ITEM.FIRST-CHILD IF #TVITEM-DYN <> NULL-HANDLE AND #TVITEM-DYN.STRING = ' ' PROCESS GUI ACTION DELETE WITH #TVITEM-DYN GIVING *ERROR FOR #I 1 3 COMPRESS 'Dynamic Item' #I INTO #A PROCESS GUI ACTION ADD WITH PARAMETERS HANDLE-VARIABLE = #TVITEM-DYN TYPE = TREEVIEWITEM PARENT = #ITEM STRING = #A END-PARAMETERS GIVING *ERROR END-FOR END-IF END-IF
ローカルデータの定義は以下のように想定されています。
01 #CONTROL HANDLE OF GUI 01 #ITEM HANDLE OF TREEVIEWITEM 01 #TVITEM-DYN HANDLE OF TREEVIEWITEM 01 #TGT-ITEM HANDLE OF TREEVIEWITEM 01 #I (I4) 01 #A (A) DYNAMIC
上記のコードではまず、展開する項目がターゲット項目かどうかを確認します。 ターゲット項目の場合、最初の子の STRING
属性をクエリして、プレースホルダが存在するかどうかを確認します。 プレースホルダが存在する場合、そのプレースホルダは削除され、3 つのツリービュー項目がダイナミックに作成されます。 挿入される項目の STRING
属性値は、SORTED
属性が設定されたツリービューでもコードが正しく動作するように、後で変更するのではなく、作成時に設定します。
リソースを節約するために、ダイナミックに作成した項目を COLLAPSE
イベントハンドラ内で削除して、別のプレースホルダ項目で置き換えることもできます。
#CONTROL := *CONTROL #ITEM := #CONTROL.ITEM IF #ITEM = #TGT-ITEM PROCESS GUI ACTION DELETE-CHILDREN WITH #ITEM GIVING *ERROR PROCESS GUI ACTION ADD WITH PARAMETERS /* placeholder TYPE = TREEVIEWITEM PARENT = #ITEM END-PARAMETERS GIVING *ERROR END-IF
ドラッグ & ドロップをサポートするための基本的な手法については、「クリップボードおよびドラッグ & ドロップの使用」に記載されています。
マウスカーソルの下にある項目(存在する場合)の SELECTED
属性を(必要に応じて)設定して強調表示し、後で元の選択状態(設定されていた場合)に戻すのは、プログラマの責任であることに注意してください。
以下の例は、ラベルを変更するための、別のアプリケーション(ワードパッドなど)からツリービュー項目へのテキストのドラッグ & ドロップをサポートする、ドロップターゲットとして動作するツリービューコントロールのコードを示しています。
まず最初に、ドロップモードをツリービューコントロールに適切に設定します。 ダイアログエディタの[ツリービューコントロール属性]ウィンドウで、[ドロップモード]選択ボックスを[コピー + 移動]に設定します。 これにより、ダイアログの生成ソースコード内で、コントロールの DROP-MODE
属性が DM-COPYMOVE
に設定されます。
次に、以下で使用される必要なローカルの変数を定義する必要があります。
01 #CONTROL HANDLE OF GUI 01 #DROP-ITEM HANDLE OF GUI 01 #ITEM HANDLE OF GUI 01 #SELECTED HANDLE OF GUI 01 #AVAIL (L) 01 #X (I4) 01 #Y (I4)
これを行った後、必要なイベントハンドラを記述することができます。 処理を開始する論理的な場所は、DRAG-ENTER
イベントです。
#CONTROL := *CONTROL #CONTROL.CLIENT-HANDLE := #CONTROL.SELECTED-SUCCESSOR PROCESS GUI ACTION INQ-FORMAT-AVAILABLE WITH CF-TEXT #AVAIL GIVING *ERROR IF #AVAIL #CONTROL.SUPPRESS-DRAG-DROP-EVENT := NOT-SUPPRESSED ELSE #CONTROL.SUPPRESS-DRAG-DROP-EVENT := SUPPRESSED END-IF
上記のコードではまず、後で項目の選択状態を元に戻すために、現在選択されている項目のハンドルをコントロールの CLIENT-HANDLE
属性に保存します。 その後、イベントハンドラはドラッグドロップクリップボードでテキストを使用できるかどうかを確認します。 使用できる場合、ドロップを可能にするために DRAG-DROP
イベントの抑制が解除されます。 それ以外の場合、このイベントを無効にしてドロップを禁止し、ドロップアンドドラッグカーソルが表示され"ない"ようにします。
外部データをツリービューコントロール上にドラッグしているときにドロップの強調表示を行うには、DRAG-OVER
イベントハンドラを使用します。
#CONTROL := *CONTROL IF #CONTROL.SUPPRESS-DRAG-DROP-EVENT = NOT-SUPPRESSED PROCESS GUI ACTION INQ-DRAG-DROP WITH 3X #X #Y GIVING *ERROR PROCESS GUI ACTION INQ-ITEM-BY-POSITION WITH #CONTROL #X #Y #ITEM GIVING *ERROR IF #ITEM <> #DROP-ITEM #DROP-ITEM := #ITEM IF #DROP-ITEM <> NULL-HANDLE #DROP-ITEM.SELECTED := TRUE END-IF END-IF END-IF
上述したコードにより、次の処理が実行されます。
DRAG-ENTER
イベントでドロップが許可されていない場合、ドロップの強調表示は不要なため、このイベントは無視されます。
ドロップが許可されている場合、INQ-DRAG-DROP
アクションを呼び出して現在のドロップ位置を把握します。
INQ-ITEM-BY-POSITION
アクションを使用して、現在のドロップ位置にあるツリービュー項目(存在する場合)を把握します。 この項目を #DROP-ITEM
に保存します。
カーソルの下にあるツリービュー項目(存在する場合)の SELECTED
属性を TRUE
に設定して、この項目を選択し、ドロップの強調表示を行います。
実際のドロップを実行するために、DRAG-DROP
イベントハンドラが提供されています。
IF #DROP-ITEM <> NULL-HANDLE PROCESS GUI ACTION GET-CLIPBOARD-DATA WITH CF-TEXT #DROP-ITEM.STRING GIVING *ERROR END-IF #CONTROL := CONTROL /* "parameter" for subroutine below PERFORM RESET-SELECTION
ドロップターゲットのツリービュー項目が存在する場合、上記のコードはドラッグドロップクリップボードからテキストを取得して項目のキャプションに直接設定します。 その後、ツリービューコントロールの選択状態を元に戻します。 このためには、以下に記述するコードのように、RESET-SELECTION
サブルーチンを使用します。
#ITEM := #CONTROL.CLIENT-HANDLE IF #ITEM <> NULL-HANDLE /* Restore original selection: #ITEM.SELECTED := TRUE ELSE /* Nothing was originally selected, /* so clear any existing selection: #ITEM := #CONTROL.SELECTED-SUCCESSOR #ITEM.SELECTED := FALSE END-IF RESET #DROP-ITEM
他のイベントハンドラのロジックと合わせるために、#DROP-ITEM
もリセットして、ドロップ項目がないことを示します。
最後に、ユーザーがドラッグ操作をキャンセルした場合、またはドロップを実行せずにツリービューコントロールの境界線の外に出た場合は、DRAG-LEAVE
イベントハンドラを使用します。
#CONTROL := CONTROL /* "parameter" for subroutine below PERFORM RESET-SELECTION
上記のコードは、ドロップの強調表示(行われている場合)をクリアして元の選択状態に戻すために、前述のインラインサブルーチンを呼び出しているだけです。