SubRolloutに合わせて自動的にサイズを変えるロールアウト

投稿者: | 2016/02/21

今回はサブロールアウトに合わせてサイズを自動調整するロールアウトの作り方です。

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()
    )
)
-- 以下、必要な数だけロールアウト定義
  1. カテゴリの指定
    ロールアウト作成時にcategoryパラメータを設定します。
    こうすることで、サブロールアウトが追加された時に、自動的に順番を整列してくれるようになります。例えば、category:1のロールアウトを後から追加した場合でも、category:2より前に追加してくれます。

  2. コールバック変数
    この変数は親ロールアウトのresize関数を格納するための変数です。
    サブロールアウト作成時に、親からresize関数オブジェクトを受け取って格納します。

  3. サイズ変更イベント
    サブロールアウトが畳まれたり開かれたりした時に発生します。
    親の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です。

コメントを残す

メールアドレスが公開されることはありません。