今回はサブロールアウトに合わせてサイズを自動調整するロールアウトの作り方です。
SubRolloutコントロールの追加、開閉によって親サイズを変更します。
サンプルロールアウト
サンプルコード
TRLib_ResizeableRollout.ms (2.9 KB)
以下は実際に動かしてみたサンプルになります。
ボタンスイッチをONにすると対応するサブロールアウトが子に追加され、サブロールアウトのサイズによってダイアログのサイズ、下部ボタンの位置も自動的に調整されています。
また、下部のGetボタンを押すと、サブロールアウト内の各パラメータをMessageBoxで表示する事が出来ます。
サブロールアウト テンプレート
初めに、サブロールアウト側のコードを説明します。
rollout rltSub1 "Sub1" width:190 height:32 category:1 --- 1. カテゴリの指定
(
local resizeCallback -- 2. コールバック変数
checkbox chkOpt "Option" pos:[8,8] width:152 height:16
-- 3. サイズ変更イベント
on rltSub1 rolledUp isOpen do
(
if resizeCallback != undefined do
resizeCallback()
)
)
-- 以下、必要な数だけロールアウト定義
- カテゴリの指定
ロールアウト作成時にcategoryパラメータを設定します。
こうすることで、サブロールアウトが追加された時に、自動的に順番を整列してくれるようになります。例えば、category:1のロールアウトを後から追加した場合でも、category:2より前に追加してくれます。 -
コールバック変数
この変数は親ロールアウトのresize関数を格納するための変数です。
サブロールアウト作成時に、親からresize関数オブジェクトを受け取って格納します。 -
サイズ変更イベント
サブロールアウトが畳まれたり開かれたりした時に発生します。
親のresize関数を実行してサイズを変更させます。
以上です。
基本的にはrolledUpイベントを親に伝搬する以外は、特別な機能は持っていません
親ロールアウト テンプレート
次に親ロールアウトを説明します。
実際の定義順所とは違うのですが、分かりやすいように部分的にまとめて紹介します。
初期化部分
rollout rltMain "Main Rollout" width:200 height:180
(
-- ロールアウト変数定義
local self
local subRollouts
local btmControls
-- コントロール定義
subRollout srFloater "" pos:[-1,40] width:206 height:102
checkbutton ckbSub1 "Sub1" pos:[10,10] width:60 height:20
checkbutton ckbSub2 "Sub2" pos:[70,10] width:60 height:20
checkbutton ckbSub3 "Sub3" pos:[130,10] width:60 height:20
button btnGet "Get" pos:[10,150] width:90 height:20
button btnClose "Close" pos:[100,150] width:90 height:20
-- ロールアウト初期化
on rltMain open do
(
self = rltMain
subRollouts = #(rltSub1, rltSub2, rltSub3)
btmY = srFloater.pos.y + srFloater.height
btmControls = (for c in self.controls where c.pos.y > btmY collect c)
resize()
)
主にロールアウトの定義と変数の初期化を行っています。
各変数の意味
- self
- 自分自身のインスタンスを代入する為の変数です。
過去の記事でもまとめていますが、同じロールアウトの定義コードを複数回実行した時に、自分自身への参照を保持する為に使用します。
これが無いと、destroyDialog等で後から起動したロールアウトを削除してしまったりします。 - subRollouts
- サブロールアウトのインスタンスを追加しておく為の配列です。
これもselfと同じく、同一ロールアウトを複数起動した時に、子を確実に参照する為に必要になります。 - btmControls
- subRolloutコントロールより下にあるコントロールを記憶しておく為の配列です。
中身は初期化イベント内で自動的に格納しています。
初期化イベント
自分自身のインスタンスの保持、子の保持、subRollout以下のロールアウトの検索を行っています。
最後にresize()イベントを呼び出して、自身のサイズを初期化していますが、resize()イベントについては後で説明します。
子ロールアウトの追加・削除部分
-- サブロールアウト追加関数
fn addSub rlt =
(
addSubRollout srFloater rlt
rlt.resizeCallback = resize
)
-- サブロールアウト削除関数
fn removeSub rlt =
(
removeSubRollout srFloater rlt
)
-- 切り替えボタンON/OFFイベント
on ckbSub1 changed state do
(
if state then
addSub subRollouts[1]
else
removeSub subRollouts[1]
resize()
)
-- ckbSub2, 3は省略
- addSub
- サブロールアウトを追加した後、対象のresizeCallback変数に、自身のresize関数を渡しています。
注意すべきでは、resize関数の実行結果ではなく、関数オブジェクトそのものを渡しているという点です。
これによって、子は親のresize関数を自由に呼び出せるようになります。
ロールアウトは仕様上、画面に表示された直後に自身の変数を初期化してしまうので、必ずこのタイミングで渡す必要があります。 - removeSub
- removeSubRolloutをラップしているだけなので、ほぼ存在意義は無いのですが、addSubと対になるように作成してあります。
- 切り替えボタンON/OFFイベント
- 状態によってaddSub, removeSubを呼び出し、最後にresize()関数を呼び出して自身のサイズを調整しています。
サイズ変更部分
-- サイズ変更関数
fn resize =
(
local lastHeight = srFloater.height
local maxHeight = 1000
local subsHeight = 4
for rlt in srFloater.rollouts do
(
if rlt.open then
subsHeight += (rlt.height + 25)
else
subsHeight += 21
)
subsHeight = amin subsHeight maxHeight
srFloater.height = subsHeight
local offsetY = subsHeight - lastHeight
self.height += offsetY
for c in btmControls do
c.pos.y += offsetY
)
ここまで何度も登場したresize関数です。
子ロールアウトのサイズを計算して、subRolloutコントロールの高さ、自身の高さ、subRolloutより下にあるコントロールのY座標を調整しています。
maxHeightはサブロールアウトの高さの上限を設定しています。
この場合、子ロールアウトの高さが1000を超えても、subRolloutは高さ1000に制限されます。
この関数は以下の場所で呼び出されます。
- 親ロールアウトの初期化イベント
- 子ロールアウトの追加・削除後(親側で呼び出し)
- 子ロールアウトの開閉イベント(子側で呼び出し)
下部ボタンイベント部分
-- Getボタン クリックイベント
on btnGet pressed do
(
local opt = subRollouts[1].chkOpt.checked
local items = subRollouts[2].rdoItems.state
local msg = try subRollouts[3].edtMsg.text catch ""
ss = StringStream ""
format "Option: %nn" opt to:ss
format "Items: %nn" items to:ss
format "Text: '%'" msg to:ss
messageBox (ss as string) title:"Result" beep:false
)
-- Closeボタン クリックイベント
on btnClose pressed do
(
destroyDialog self
)
)
createDialog rltMain
- Getボタン
- 子ロールアウトのコントロールから値を取得して表示しています。
ロールアウト内の各コントロールは、public要素として外部に公開されている為、普通に外部から参照できます。 - Closeボタン
- 自分自身を削除しています。
ここで、destroyDialog rltMain のようにしてしまうと、ロールアウトを多重起動していた場合に、後から起動した方のロールアウトを削除する事になってしまいます。
最後に
少々長くなってしまいましたが、一度作っておけば何度も使い回せるので、実際に使うときはさほどめんどくさくはありません。
使う側から見ても、Windowsアプリでよく見るタイプの配置になりますので、直感的に使えて良いかなと思います。
今回作成したコードは特に使用制限などしませんので、自由に改変したり組み込んだりして使ってもらってOKです。