DTPab

印刷やデザイン、アドビ製アプリやスクリプトなど、雑多な技術ブログ

SUI:項目数に応じて自動で増減させるタブ

おいおい、UXPやらずにまだScriptUIいじってんの? という内なる声を、職場はまだInDesign 2024に移行しきれていないのでしかたないだろ、となだめるこの頃。

前段

スクリプトの動作設定をスクリプト自身に行わせて、設定ファイルを書き出して次の起動時にその内容を読み取る…みたいなことをよくやります。そういうときに、設定したい項目がどんどん増えて、終いにはモニタに表示しきれずに下部が見切れてしまうなんてことがおそらく起こる。

このまま増え続けると下が見切れる

全員同じモニタを使っているわけではないので、そのうちAさんだけ下が見切れるとか、そんなことになる。そうなってから対応よろしくねってなってしまうのは、現スクリプト担当としては忍びないので少し手を加えることにしました。

項目をタブに分配する

例えば、20項目を基準にタブで区切る。21項目めからは次のタブ、41項目めからはその次のタブ…というような感じがいいなと。
配列でイメージすると、項目の[0][19]がタブ1、[20][39]がタブ2、という具合。

配列の要素を任意の要素数に分配した二重配列を作るには

ちょっと本題から逸れますが(さっさと結論を知りたい方は飛ばしてください)…前にこんなポストをしました。

[0, 1, 2, 3, 4, 5, 6, 7, 8]という配列があったとして、これを[[0, 1, 2], [3, 4, 5], [6, 7, 8]]とするように、for文でうまく仕分けたいというとき。これは3つの要素で分けたけど、4つや5つ…と、あとからかんたんに仕分ける要素数を変えられるようにしたい。

このとき考えたのは、商と剰余を使ってこんな感じ。

これを今回の「タブに分配する」ことに応用します。

SUIのタブパネル

注意点は以前の記事を参照。

uske-s.hatenablog.com

コード

var len = 32;
var checkItems = Array(len);

for (i = 0; i < len; i++){
    checkItems[i] = "チェック項目" + (i + 1);
}

var prefItems = []; // チェックボックスの要素を入れる配列

(function () {
    var dlg = new Window("dialog", "チェック項目リスト");
    dlg.add("statictext", undefined, "オンにした項目が実行されます");
    var tbp = dlg.add("tabbedpanel");
    var tbArray = [];
    var limitAsTab = 20; // ひとつのタブに表示する項目数
    tbp.alignChildren = ["fill", "fill"];
    for (var i = 0; i < checkItems.length; i++) {
        if (i % limitAsTab === 0) {
            var tbIndex = Math.floor(i / limitAsTab);
            tbArray.push(tbp.add("tab", undefined, tbIndex + 1));
            tbArray[i / limitAsTab].alignChildren = "left";
        }
        prefItems.push(tbArray[tbIndex].add("checkbox", undefined, checkItems[i]));
    }

    // ボタン設定
    var buttonGroup = dlg.add("group");
    var cancelBtn = buttonGroup.add("button", undefined, "キャンセル");
    var saveBtn = buttonGroup.add("button", undefined, "保 存", { name: "ok" });
    cancelBtn.onClick = function () {
        dlg.close(2);
    }
    saveBtn.onClick = function () {
        dlg.close(1);
    }
    var dlgResult = dlg.show(); // 1:保存 2:キャンセル(ESCキーでも2が返る)
    if (dlgResult === 2) { return; } // キャンセルされたら終了
})();

要素数はまぁいいとして、1タブでの表示数はlimitAsTab変数に整数を入れて制御します。
チェックボックスのオブジェクト自体はprefItemsに配列として入っています。

動作イメージ

要素数32、1タブでの表示数20

要素数151、1タブでの表示数15

見た目(タブのサイズとか)はいい感じに設定してください。

まとめ

要素数がいくつであれ、自動でタブを増減できるSUIでした。
ポイントは、現在の要素のインデックスを元に、振り分けるタブのインデックスを割り出すMath.floor(i / limitAsTab)部分ですかね。これでi / limitAsTabの商を求めたところでしょうか。

仮にlimitAsTab = 20のとき、i = 0からi = 19までは0番目のタブ、i = 20から1番目のタブになるになるので、タブのインデックスはi / limitAsTabの商というわけです。

タブには単純に番号を表示していますが、こちらは1から始まるインデックスにしています。ユーザー側は0から始まるインデックスに慣れていないと思ったのでちょっとした配慮です。