GhPythonのValueListを自動生成する

5 min read読了の目安(約4900字

ValueListの中身をいちいち書くのめんどくさい

GrasshopperでValueListを使うとき、あらかじめ入力したいデータは決まっているのにいちいち入力するの結構大変ですよね。
特にGhPythonなどのプログラムにinputとしてValueListを使いたい場合、ValueListを書き換えられてしまったらエラーの原因になります。
この記事ではValueListをGhPythonに繋ぐと、Pythonコード内のListがValueListに反映されるようなコードを書いていきます。

つくるもの

今回想定するケースは下記の通りです。

  • GhPythonのプログラムにあらかじめValueListにしたいリストを書いておく
  • ValueListをInputに繋ぐと自動的にリストが書き換わる

GhPythonコンポーネントの準備

GhPythonをこのように設定します。

Input Access Type hint
from_valuelist Item str

反映させるリスト

シンプルにこのようなリストにします。

"りんご" = "Apple"
"オレンジ" = "Orange"
"バナナ" = "Banana"
"ぶどう" = "Grape"

ValueListの中身を自動生成する

コードを書いていきます。
先に全体を書いて、特徴的な部分を解説していきます。

# -*- coding: utf-8 -*-
import Grasshopper

def define_valuelist(name, keys, vals):
    component = ghenv.Component
    for input in component.Params.Input:
        if input.Name == name:
            srcs = input.Sources
            for src in srcs:
                attr = src.Attributes
                comp_obj = attr.GetTopLevel.DocObject
                if type(comp_obj) == Grasshopper.Kernel.Special.GH_ValueList:
                    if [val.Name for val in comp_obj.Values] == keys:
                        pass
                    else:
                        comp_obj.Values.Clear()
                        for i,key in enumerate(keys):
                            item = Grasshopper.Kernel.Special.GH_ValueListItem(key, "\"{0}\"".format(vals[i]))
                            comp_obj.Values.Add(item)
                        comp_obj.SelectItem(0)
                        comp_obj.Name = "Types"
                        comp_obj.NickName = "Types"
                        comp_obj.ListMode = Grasshopper.Kernel.Special.GH_ValueListMode.DropDown
                        comp_obj.ExpireSolution(True)
                else:
                    continue
        else:
            continue
    return

if __name__ == "__main__":
    keys = ["りんご","オレンジ","バナナ","ぶどう"]
    vals = ["Apple","Orange","Banana","Grape"]
    define_valuelist("from_valuelist", keys, vals)
    selected_value = from_valuelist

1. 関数の引数を設定

define_valulistという関数を作っていきます。
引数は下記の通りです。

引数 内容
name 中身を書き換える対象となるコンポーネントの入力名
keys ValueListに設定するkeyのリスト
vals ValueListに設定するvalueのリスト
def define_valuelist(name, keys, vals):
    return

if __name__ == "__main__":
    keys = ["りんご","オレンジ","バナナ","ぶどう"]
    vals = ["Apple","Orange","Banana","Grape"]
    define_valuelist("from_valuelist", keys, vals)
    selected_value = from_valuelist

2. コンポーネントの情報を取得する

まずは現在使っているコンポーネントの情報を取得します。
コンポーネント自身はghenv.Componentで取得でき、その中の情報は下記のように書いていきます。
入子状になっていて複雑なので各行ごとに説明を入れていきます。

component = ghenv.Component
# component.Params.Input = コンポーネントのインプットリスト
for input in component.Params.Input:
    # .Name = input名
    if input.Name == name:
        # .Sources = inputに入力されているコンポーネントのリスト
        srcs = input.Sources
        for src in srcs:
            # .Attributes = inputに入力されているコンポーネントの情報
            attr = src.Attributes
            # .GetTopLevel.DocObject = ValueListのオブジェクトを取得
            comp_obj = attr.GetTopLevel.DocObject

3. ValueListにデータを入れる

コンポーネントがValueListの時のみデータを入れていきます。
ポイントは一度中身をクリアしてから追加するところです。

if type(comp_obj) == Grasshopper.Kernel.Special.GH_ValueList:
    # すでに同じ値がある場合はパス
    if [val.Name for val in comp_obj.Values] == keys:
        pass
    else:
        # ValueListの中身をクリア
        comp_obj.Values.Clear()
        for i,key in enumerate(keys):
            # ValueListのアイテムを追加
            item = Grasshopper.Kernel.Special.GH_ValueListItem(key, "\"{0}\"".format(vals[i]))
            # アイテムの値を追加
            comp_obj.Values.Add(item)
        # 選択を先頭にリセット
        comp_obj.SelectItem(0)
        # ValueListのプロパティを設定
        comp_obj.Name = "Types"
        comp_obj.NickName = "Types"
        comp_obj.ListMode = Grasshopper.Kernel.Special.GH_ValueListMode.DropDown
        comp_obj.ExpireSolution(True)
else:
    continue

4. 実装

では実際に使ってみます。
ValueListを取り出して繋いでみると...

ちゃんとリストが反映されてますね!

他の選択肢もしっかり入っています。

さいごに

大量かつあらかじめ選択肢が決まっている場合はこのように自動化するとUIとしてもわかりやすくなりますよね。
DBと接続するとハードコーディングする必要がなくなってよりスマートだと思います。

参考

Value List values (set by Python script) report being “None”