4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

[Unity]EditorGUILayout.ObjectFieldのPickerのフィルタに予め文字列を設定したい

Posted at

Qiitaには初投稿になります
よろしくお願いします
#背景
インスペクター上でよく見かけるこれ↓
tempsnip.png
(右の◎でTextureやらGameObjectやらを選択してセットできる)
これの名前がObjectFieldという名前らしいです。
優れモノで選択するときはこんな感じに↓
Selector.PNG

インタラクティブに選べます。
この選択画面ObjectPickerやらObjectSelectorと呼ばれているみたいです。
この画面の上部の文字入力欄に
SelectorInput.PNG
文字を入力するとファイル名でフィルタリングをしてくれるのですが、Pickerを開いた段階でフィルタリングしたい!
#前提
UnityのEditor拡張です

環境

  • Unity 2017.3.f1
  • JetBrains Rider

#ObjectFieldについて
Editor拡張でObjectFieldを表示するときは
ドキュメント

これを使って、

public static Object ObjectField(Object obj, Type objType, bool allowSceneObjects, params GUILayoutOption[] options);


 public class TestEditor:EditorWindow
    {
        private Sprite back;
        private void OnGUI()
        {
            Sprite newSprite =
                (Sprite) EditorGUILayout.ObjectField(back, typeof(Sprite),
                    false);
            if(newSprite!=null)back=newSprite;
        }

こんな感じでObjectField表示します。
上のドキュメントのobjTypeで設定したTypeで表示するオブジェクトを制約できます。

objTypeを設定すれば設定したいオブジェクトを大体は絞り込めるようになるんですが、画像とか多くなってくると設定するのもひと手間になってくるので予め文字列をフィルタに入れるようにして探しやすくします。
#reflectionを用いたフィルタ文字列の設定
元々、この投稿にあるソースを改良したのでこちらを読んでくれればいいのですが、
ObjectField Asset Browser, How to open it with code, not the objectfield

上の記事での質問は「ObjectFieldを使わないであのPickerを使いてえ!」
に対して
ObjectSelectorをリフレクションを使って(ObjectSelectorは公開されていないので参照できません)取ってくる。
というものになります。

でObjectSelectorのソースinternal string searchFilterという変数があったのでそれをObjectSelectorを表示されるときに一緒に設定しました。(サンキューBunny83)

以下にBunny83さんのソースに自分が少し追加したソースコードを示します.


using UnityEditor;
using System.Reflection;
 
public static class ObjectSelectorWrapper
{
    private static System.Type T;
    private static bool oldState = false;
    static ObjectSelectorWrapper()
    {
        T = System.Type.GetType("UnityEditor.ObjectSelector,UnityEditor");
    }

    //追加した部分
    public static void SetFilterString(string filter)
    {
          if (filter == null) filter = String.Empty;
        FieldInfo field = T.GetField("m_SearchFilter", BindingFlags.SetProperty|  BindingFlags.Instance | BindingFlags.NonPublic|BindingFlags.Public);
        field.SetValue(Get(),filter);

    }
    
    //追加した部分終わり
     
    private static EditorWindow Get()
    {
        PropertyInfo P = T.GetProperty("get", BindingFlags.Public | BindingFlags.Static);
        return P.GetValue(null,null) as EditorWindow;
    }
    public static void ShowSelector(System.Type aRequiredType)
    {
        MethodInfo ShowMethod = T.GetMethod("Show",BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
        ShowMethod.Invoke(Get (), new object[]{null,aRequiredType,null, true});
    }
    public static T GetSelectedObject<T>() where T : UnityEngine.Object
    {
       
        MethodInfo GetCurrentObjectMethod =  ObjectSelectorWrapper.T.GetMethod("GetCurrentObject",BindingFlags.Static | BindingFlags.Public);
        return GetCurrentObjectMethod.Invoke(null,null) as T;
    }
    public static bool isVisible
    {
        get 
        {
            PropertyInfo P = T.GetProperty("isVisible", BindingFlags.Public | BindingFlags.Static);
            return (bool)P.GetValue(null,null);
        }
    }
    public static bool HasJustBeenClosed()
    {
        bool visible = isVisible;
        if (visible != oldState && visible == false)
        {
            oldState = false;
            return true;
        }
        oldState = visible;
        return false;
    }
}

#使い方
先ほどのTestEditorに適用してみます


using UnityEditor;
using UnityEngine;


    public class TestEditor:EditorWindow
    {
        [MenuItem("Test/Test")]
        static void Open()
        {
            GetWindow<TestEditor>();
            
        }
        private Sprite back;
        private void OnGUI()
        {
            Sprite newSprite =
                (Sprite) EditorGUILayout.ObjectField(back, typeof(Sprite),
                    false);
            if (ObjectSelectorWrapper.isVisible)
            {
                ObjectSelectorWrapper.SetFilterString("arrow");
            }

        }
    }

objectfield.gif
こんな感じで事前にフィルタができます

#注意
Reflectionは特定のメソッド、フィールドに依存するためUnity側の変更によっては動かないこともありますので注意してください
TestEditorでの実装は若干問題があります。それはPickerの文字列フィルタへの挿入が他のObjectFieldでも作用してしまうことがあります。
なので、このObjectFieldがクリックされたらって実装しようと思ったんですけどGUIの特定ができなくて投げました(涙目)
すまぬ…

もしこんな方法があるよ~ってのがある方はコメントお願いします。
…まあObjectFieldに固執せずObjectFiedlっぽいの実装してGUI.Buttonでやればいいと思うんですが…

4
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?