listbox」タグアーカイブ

4DのDrug and Drop

4D Drug & Drop

ひとつの画面に複数の画像を表示する仕組みを考えていた。画像は外部ファイルを想定、多くて10個くらいあるのだが、要望としては代表的な画像を2個登録したい、ということだった。例えば画像は2個と限定してピクチャー変数を2つ配置しておけば、ドラッグ&ドロップを2回やれば画像登録ができる。操作も実装も簡単だ。しかしプログラマーとしては、3個以上の画像がありうるのに2個に制限して良しとするのは敗北感がある。

そこで考えた。リストボックスがいいんじゃないか?リストボックスなら画像をいくら追加しても大丈夫。行が増えていけば勝手にスクロールしてくれる。画像の数を制限しなくて済む。画像は別テーブルに保存すれば良い。

いつものようにリストボックスの上に[+]と[ー]のボタンを置いて、[+]クリックで表示されたダイアログにピクチャー変数を配置してドラッグ&ドロップしてもらって、という仕様で実装した。

これだとダイアログボックスを開いて閉じるのが面倒。もともとの要望の通り、ピクチャー変数を2個、配置しておけば、ドラッグ&ドロップを2回やれば画像登録ができる。その方がユーザは簡単だ。同じように簡単な操作で複数の画像を登録する方法はないのだろうか?

リストボックスに画像をドロップすればいいのでは?

リストボックスに画像をドロップしたら行が増えていくようにすれば操作性は悪くない。ドロップのたびに行を追加、削除するときは[ー]ボタン。増やしたり減らしたり、縦スクロールなら実装も簡単そうだ。

ただリストボックスに画像をドロップしても標準的な機能では受け取ってくれない。リストボックスのOnDropイベントにコードを書くことになる。OnDropで配列要素を増やして、画像列に取得した画像を代入すればいい。と、ここまでわかったところで気がついた。一般に4DでDrug&Dropをい実装する場合は、フォームオブジェクトが勝手に処理してくれるからコードを書く必要がない。マニュアルサイトを見ても、イベントを取得したあと、ドロップされたコンテンツをどうやって受け取るか、よくわからない。

とりあえずリストボックスにイベントハンドラを書いて。

ドロップされた画像はドラッグ&ドロップ専用のペーストボードから取得するそうです。

GET PICTURE FROM PASTEBOARD($picture)

OnDropで呼ばれるコードはこれ。

リストボックスに行を追加したり、自動スクロールさせたり、ついでにドロップされたファイルのパスを取り出したり、している。

ドロップされた直後に行を選択して、自動スクロールさせていてる

4D リストボックスから開くフォームの次前ボタン

4Dのリストボックスから開いたフォームに、「次前(つぎまえ、と読む)」を実装する

リストボックスの選択行の詳細を表示した時、次のレコードに移動するには、一度フォームを閉じてリストボックスに戻り、次の行をダブルクリックなどでレコードを表示する。これではユーザは不便。それでフォームに[次][前]ボタンを配置して、リストボックスに戻らなくても隣のレコードを表示できるように、という要望にお応えするのだ。

実装方法

たとえばvKA01_lstKAというリストボックスがある。キー配列はvKA01_lstKA_IDとすると、次前はこのvKA01_lstKA_IDの配列中から隣のKA_IDを取得して、そのレコードをロードして表示する、ような実装をする。これでリストボックスに表示されているレコードを行ったり来たりする動きになる。

実装箇所

修正が必要なのは次の箇所。

1)フォームに◁▶︎のようなボタンと現在の位置を2/30のような形式で表示するテキストが必要

フォームにオブジェクトを配置、現在の位置はvKA02_varIndexに表示、メッセージはSetControlsValues_PrevNext(後述)で作成する。

2)呼び出し元、たぶんKA01_btnModのようなボタンメソッド

次前しなければ$ka_idは変更されない値だったが、次前を実装するとフォームが閉じた時に変化していることがある。選択されている行番号も同様だ。戻ってきた時、最後に選択されているはずの行の内容を保存したり、リストボックスでその行を選択したりするために、フォームで次前が行われた結果の$ka_idと行番号を返してもらう必要がある。よってこれらはポインタで渡す。引数は次の3つ。

  • $ka_idのポインタ
  • 配列vKA01_lstKA_IDのポインタ
  • 選択されている行番号のポインタ
KA01_btnModの例

3)呼び出される側、KA02_Input_Mod

KA02_Displayする前に、配列のポインタ、行番号、$ka_idをプロセス変数に保持、ゲッターセッターを用意。_DisplayでOKされたら、フォームを表示する前のKA_IDと閉じた時のKA_IDは次前で変化している可能性があるため、Acceptの際にゲッターでKA_IDを取得してからレコードを保存する。リストを再作成してから、変化した行番号をゲッターで取得してリストボックスの行を選択し直す。

KA02_Input_Modの例

4)一番前に来たら前ボタン、一番後ろに来たら次ボタンをディスエイブルにするために、SetControlsValuesにSetControlsValues_PrevNextを追加

SetControlsValuesの例

5)次前ボタン(KA02_brnNext)

次前の際に、レコードを保存するかどうかは設計が必要だ。次のようなケースがある。

  • A)問答無用で保存(いわゆる自動保存)
  • B)問答無用でキャンセル(保存しない、変更内容は失われる)
  • C)変更していたら自動保存、変更していなければ保存しない
  • D)変更していたらアラートでお知らせしてから保存、変更していなければアラートせずに保存しない

理想を言えばDだが、Aでも成立するケースは多い。ユーザからの強い要望でBというケースもあったので決めつけることのないように。次の実装はAの自動保存。

KA02_brnNextの例、KA02_brnPrevは24、26行目の「+1」を「-1」に変えるだけ。

ネーミングおよびJCL4Dについては「4Dアプリ開発ガイド」を参照。