うにてぃブログ

主にUnityとC#に関する記事を書いていきます

【Unity】EditorWindow をモーダルとして表示する際の問題

EditorWindow クラスに以下のメソッドがあったため、これを利用すればモーダルウィンドウとして表示できると思い利用してみたところ、TreeView が想定と異なる挙動をしたためその解決方法を記述します

    /// <summary>
    ///   <para>Show the EditorWindow as a floating modal window.</para>
    /// </summary>
    public void ShowModalUtility()
    {
      this.ShowWithMode(ShowMode.ModalUtility);
      this.MakeModal();
    }

モーダルウィンドとは以下のものを示します

モーダルウィンドウは、元のウィンドウの上に別枠で表示されるウィンドウのことです。 指定された操作を完了、もしくはキャンセルするまでずっと表示され続け、他のウィンドウに移ることができません。

おかしな挙動

以下の通り、Expand や Collapse した際の反映がが遅れてしまっています

f:id:hacchi_man:20211218231016g:plain:w400

検証に用いたスクリプトは記事の最後に添付しておきます

原因

公式リファレンスを見てみたところ、以下のように記述されていました

Note: You do not need to use EditorWindow.GetWindow before using this function to show the window.

つまり、ShowModalUtility を呼び出す際には GetWindow を利用しないということです

実際に記述したスクリプトを見てみると、GetWindow を呼び出してからの ShowModalUtility を行っています

    private static void Show()
    {
        var window = GetWindow<ModalWindow>();
        window.ShowModalUtility();
    }

これを、公式リファレンスを元に書き換えるとこうなります

    private static void Show()
    {
        var window = CreateInstance(typeof(ModalWindow)) as ModalWindow;
        window.ShowUtility();
    }

確認

先程の修正を行い、モーダルウィンドウを表示させてみると想定通りの挙動となりました

f:id:hacchi_man:20211218232120g:plain:w400

スクリプト

using UnityEditor;
using UnityEditor.IMGUI.Controls;
using UnityEngine;
 
public class ModalWindow : EditorWindow
{
    [MenuItem("Tools/ModalSample")]
    private static void Show()
    {
        var window = GetWindow<ModalWindow>();
        window.ShowModalUtility();
    }
     
    [SerializeField]
    private TreeViewState _state;
    private SampleTreeView _treeView;
     
    private void Init()
    {
        if (_state == null) 
            _state = new TreeViewState();
        if (_treeView == null) 
            _treeView = new SampleTreeView(_state);
    }
 
    private void OnGUI()
    {
        Init();
             
        var rect = GUILayoutUtility.GetRect(0, 0, position.width, position.height);
        _treeView.OnGUI(rect);
    }
}
 
public class SampleTreeView : TreeView
{
    public SampleTreeView(TreeViewState state) : base(state)
    {
        Reload();
    }
 
    protected override TreeViewItem BuildRoot()
    {
        var root = new TreeViewItem(0, -1, "Root");
        for (var i = 1; i < 5; i++)
        {
            var item = new TreeViewItem(i, 0, i.ToString());
            for (var j = 1; j < 5; j++)
            {
                var child = new TreeViewItem(i * 5 + j, 1, i + "_" + j);
                item.AddChild(child);
            }
            root.AddChild(item);
        }
         
        SetupDepthsFromParentsAndChildren(root);
 
        return root;
    }
}