GhPythonのValueListを自動生成する
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”
Discussion