Unity错误记录——UIDocument重新激活后,脚本内编写的UI交互失效

如题,本人使用UITookit编写了一个UXML的UI界面后,将其搭载到了一个UIDocument对象上,并将该对象作为UI相机的子对象以实现UI界面与相机绑定。

在为UIDocument编写交互用的C#时,采用了下面的错误做法,导致UIDocument在随UI相机一同被禁用后,所编写的交互功能全部失效:

using System.Xml.Linq;
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;

public class ModuleUI : MonoBehaviour
{
    private VisualElement rootVisualElement; // 用于获取根视图元素
    private Button selectedButton; // 用于记录当前选中的按钮
    private GameObject lastDisabledObject;   // 记录被隐藏的构件

    public static Button uploadButton;
    public static Button createButton;
    public static Button rotateButton; 
    public static Button translateButton;
    public static Button zoomButton; 
    public static Button distanceButton;
    public static Button selectButton;
    public static Button roamingButton;
    public static Button resetButton;
    
    public static Button HSButton;
    public static GroupBox HSIBox;
    public static Label objectName;
    public static Label objectLength;
    public static Label objectWidth;
    public static Label objectHeight;

    public static StyleColor defaultColor;
    public static StyleColor pressedColor = new(Color.blue); // 蓝色
    public static bool onButton = false; // 标记鼠标在按钮上的悬停状态

    private void start()
    {
        // 获取根视图元素
        rootVisualElement = GetComponent<UIDocument>().rootVisualElement;
        // 获取全部的按钮元素
        uploadButton = rootVisualElement.Q<Button>("UploadBut");
        createButton = rootVisualElement.Q<Button>("CreateBut");
        rotateButton = rootVisualElement.Q<Button>("Button1");
        translateButton = rootVisualElement.Q<Button>("Button2");
        zoomButton = rootVisualElement.Q<Button>("Button3");
        distanceButton = rootVisualElement.Q<Button>("Button4");
        selectButton = rootVisualElement.Q<Button>("Button5");
        roamingButton = rootVisualElement.Q<Button>("Button6");
        resetButton = rootVisualElement.Q<Button>("ResetBut");
        // 获取GroupBox元素及其子元素
        HSIBox = rootVisualElement.Q<GroupBox>("HSIBox");
        HSButton = HSIBox.Q<Button>("HSBut");
        objectName = HSIBox.Q<Label>("ObjectName");
        objectLength = HSIBox.Q<Label>("ObjectLength");
        objectWidth = HSIBox.Q<Label>("ObjectWidth");
        objectHeight = HSIBox.Q<Label>("ObjectHeight");
    }

    void Start()
    {
        // 获取所有的按钮元素
        var buttons = rootVisualElement.Query<Button>();
        // 为每个按钮添加鼠标悬停和离开事件
        buttons.ForEach(button => {
            button.RegisterCallback<MouseEnterEvent>(evt => {
                onButton = true;
            });
        });
        buttons.ForEach(button => {
            button.RegisterCallback<MouseLeaveEvent>(evt => {
                onButton = false;
            });
        });

        // 文件上传按钮的功能实现 
        uploadButton.clicked += OpenFileByWin32.OpenFile;
        // 模型生成按钮的功能实现
        /*createButton.clicked += () => BackgroundModify(createButton);*/
        // 模型旋转按钮的状态修改
        rotateButton.clicked += () => BackgroundModify(rotateButton);
        // 模型平移按钮的状态修改
        translateButton.clicked += () => BackgroundModify(translateButton);
        // 模型缩放按钮的状态修改
        zoomButton.clicked += () => BackgroundModify(zoomButton);
        // 自动测距按钮的状态修改 
        distanceButton.clicked += () => BackgroundModify(distanceButton);
        // 选中组件按钮的状态修改
        selectButton.clicked += () => BackgroundModify(selectButton);
        // 显隐组件按钮的状态修改 
        HSButton.clicked += () => ButtonModify(HSButton);
        // 室内漫游按钮的功能实现
        roamingButton.clicked += FirefighterController.CharacterShow;
        roamingButton.clicked += () => CameraController.SwitchCamera("view_Camera");
        // 初始时隐藏部分UI元素
        resetButton.style.display = DisplayStyle.None;
        HSIBox.style.display = DisplayStyle.None;

    }

    private void BackgroundModify(Button evt)
    {
        if (selectedButton != null && selectedButton != evt)
        {
            selectedButton.style.backgroundColor = defaultColor;
        }

        if (evt.style.backgroundColor != pressedColor)
        {
            selectedButton = evt;
            defaultColor = evt.style.backgroundColor;
            evt.style.backgroundColor = pressedColor;

            if (HSIBox.style.display == DisplayStyle.Flex)
            {
                HSIBox.style.display = DisplayStyle.None;
            }
            else if (resetButton.style.display == DisplayStyle.Flex)
            {
                resetButton.style.display = DisplayStyle.None;
                resetButton.clicked -= ModelController.RetCamera;
            }

            switch (evt.name)
            {
                case "Button1":
                case "Button2":
                case "Button3":     
                    resetButton.style.display = DisplayStyle.Flex;
                    resetButton.clicked += ModelController.RetCamera;
                    break;
                case "Button5":
                    HSIBox.style.display = DisplayStyle.Flex;
                    break;
            }
        }
        else
        {
            evt.style.backgroundColor = defaultColor;
            switch (evt.name)
            {
                case "Button1":
                case "Button2":
                case "Button3":
                    resetButton.style.display = DisplayStyle.None;
                    resetButton.clicked -= ModelController.RetCamera;
                    break;
                case "Button5":
                    objectName.text = "组件名称:";
                    objectLength.text = "组件水平长度:";
                    objectWidth.text = "组件水平宽度:";
                    objectHeight.text = "组件垂直高度:";
                    HSIBox.style.display = DisplayStyle.None;
                    break;
            }
        }
    }

    private void ButtonModify(Button evt)
    {
        if (evt.style.backgroundColor != pressedColor)
        {
            // 记录隐藏的构件
            lastDisabledObject = ClickController.currentSelectedObject;
            // 隐藏当前选中的构件
            ClickController.currentSelectedObject.SetActive(false);
            // 更换改按钮状态
            defaultColor = evt.style.backgroundColor;
            evt.style.backgroundColor = pressedColor;
            evt.text = "显示";
        }
        else
        {
            // 显示上次隐藏的构件
            lastDisabledObject.SetActive(true);
            // 更换改按钮状态
            evt.style.backgroundColor = defaultColor;
            evt.text = "隐藏";
        }
    }
}

出现错误的原因有两个:

  1. 我们获取到的元素在脚本被禁用一次后,下次重新启用就会丢失(删改代码测试得到,例如根视图元素 rootVisualElement 在脚本重新启用后必须得再次检索),底层原因未知。
  2. 我们为 button.clicked 设定的回调函数,在禁用后重新激活就会失效,所有需要重新绑定。

要解决上面两个问题其实很简单,就是要弃用 Start 方法,改为重载 OnEnable 方法,下面是修改后的代码:

using System.Xml.Linq;
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;

public class ModuleUI : MonoBehaviour
{
    private VisualElement rootVisualElement; // 用于获取根视图元素
    private Button lastButton; // 用于记录当前选中的按钮
    private GameObject lastDisabledObject;   // 记录被隐藏的构件

    public static Button uploadButton;
    public static Button createButton;
    public static Button rotateButton; 
    public static Button translateButton;
    public static Button zoomButton; 
    public static Button distanceButton;
    public static Button selectButton;
    public static Button roamingButton;
    public static Button resetButton;
    
    public static Button HSButton;
    public static GroupBox HSIBox;
    public static Label objectName;
    public static Label objectLength;
    public static Label objectWidth;
    public static Label objectHeight;

    public static StyleColor defaultColor;
    public static StyleColor pressedColor = new(Color.blue); // 蓝色
    public static bool onButton = false; // 标记鼠标在按钮上的悬停状态

    private void OnEnable()
    {
        /*Debug.Log("I do en");*/
        // 获取根视图元素
        rootVisualElement = GetComponent<UIDocument>().rootVisualElement;
        // 获取全部的按钮元素
        uploadButton = rootVisualElement.Q<Button>("UploadBut");
        createButton = rootVisualElement.Q<Button>("CreateBut");
        rotateButton = rootVisualElement.Q<Button>("Button1");
        translateButton = rootVisualElement.Q<Button>("Button2");
        zoomButton = rootVisualElement.Q<Button>("Button3");
        distanceButton = rootVisualElement.Q<Button>("Button4");
        selectButton = rootVisualElement.Q<Button>("Button5");
        roamingButton = rootVisualElement.Q<Button>("Button6");
        resetButton = rootVisualElement.Q<Button>("ResetBut");
        // 获取GroupBox元素及其子元素
        HSIBox = rootVisualElement.Q<GroupBox>("HSIBox");
        HSButton = HSIBox.Q<Button>("HSBut");
        objectName = HSIBox.Q<Label>("ObjectName");
        objectLength = HSIBox.Q<Label>("ObjectLength");
        objectWidth = HSIBox.Q<Label>("ObjectWidth");
        objectHeight = HSIBox.Q<Label>("ObjectHeight");

        // 获取根视图元素
        rootVisualElement = GetComponent<UIDocument>().rootVisualElement;
        // 获取所有的按钮元素
        var buttons = rootVisualElement.Query<Button>();
        // 为每个按钮添加鼠标悬停和离开判定
        buttons.ForEach(button =>
        {
            button.RegisterCallback<MouseEnterEvent>(evt =>
            {
                onButton = true;
            });
        });
        buttons.ForEach(button =>
        {
            button.RegisterCallback<MouseLeaveEvent>(evt =>
            {
                onButton = false;
            });
        });

        // 文件上传按钮的功能实现 
        uploadButton.clicked += OpenFileByWin32.OpenFile;
        // 模型生成按钮的功能实现
        /*createButton.clicked += () => BackgroundModify(createButton);*/
        // 模型旋转按钮的状态修改
        rotateButton.clicked += () => BackgroundModify(rotateButton);
        // 模型平移按钮的状态修改
        translateButton.clicked += () => BackgroundModify(translateButton);
        // 模型缩放按钮的状态修改
        zoomButton.clicked += () => BackgroundModify(zoomButton);
        // 自动测距按钮的状态修改 
        distanceButton.clicked += () => BackgroundModify(distanceButton);
        // 选中组件按钮的状态修改
        selectButton.clicked += () => BackgroundModify(selectButton);
        // 显隐组件按钮的状态修改 
        HSButton.clicked += () => ButtonModify(HSButton);
        // 室内漫游按钮的功能实现
        roamingButton.clicked += FirefighterController.CharacterShow;
        roamingButton.clicked += () => CameraController.SwitchCamera("view_Camera");
        // 隐藏部分UI元素
        resetButton.style.display = DisplayStyle.None;
        HSIBox.style.display = DisplayStyle.None;
    }

    private void BackgroundModify(Button evt)
    {
        if (lastButton != null && lastButton != evt)
        {
            lastButton.style.backgroundColor = defaultColor;
        }

        if (evt.style.backgroundColor != pressedColor)
        {
            lastButton = evt;
            defaultColor = evt.style.backgroundColor;
            evt.style.backgroundColor = pressedColor;

            if (HSIBox.style.display == DisplayStyle.Flex)
            {
                HSIBox.style.display = DisplayStyle.None;
            }
            else if (resetButton.style.display == DisplayStyle.Flex)
            {
                resetButton.style.display = DisplayStyle.None;
                resetButton.clicked -= ModelController.RetCamera;
            }

            switch (evt.name)
            {
                case "Button1":
                case "Button2":
                case "Button3":     
                    resetButton.style.display = DisplayStyle.Flex;
                    resetButton.clicked += ModelController.RetCamera;
                    break;
                case "Button5":
                    HSIBox.style.display = DisplayStyle.Flex;
                    break;
            }
        }
        else
        {
            evt.style.backgroundColor = defaultColor;
            switch (evt.name)
            {
                case "Button1":
                case "Button2":
                case "Button3":
                    resetButton.style.display = DisplayStyle.None;
                    resetButton.clicked -= ModelController.RetCamera;
                    break;
                case "Button5":
                    objectName.text = "组件名称:";
                    objectLength.text = "组件水平长度:";
                    objectWidth.text = "组件水平宽度:";
                    objectHeight.text = "组件垂直高度:";
                    HSIBox.style.display = DisplayStyle.None;
                    break;
            }
        }
    }

    private void ButtonModify(Button evt)
    {
        if (evt.style.backgroundColor != pressedColor)
        {
            // 记录隐藏的构件
            lastDisabledObject = ClickController.currentSelectedObject;
            // 隐藏当前选中的构件
            ClickController.currentSelectedObject.SetActive(false);
            // 更换改按钮状态
            defaultColor = evt.style.backgroundColor;
            evt.style.backgroundColor = pressedColor;
            evt.text = "显示";
        }
        else
        {
            // 显示上次隐藏的构件
            lastDisabledObject.SetActive(true);
            // 更换改按钮状态
            evt.style.backgroundColor = defaultColor;
            evt.text = "隐藏";
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值