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

2023-11-13

如题,本人使用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 = "隐藏";
        }
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

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

  • RocketMQ第五篇 RocketMQ API基本使用

    目录 生产者Product 消费者Consumer 前面已经学习了Rocket的基本知识 以及搭建MQ单机版和集群环境 下面开始进行实际开发 根据前面下载的RocketMQ源码 开展讲解RocketMQ 的基本使用 生产者Product 在

随机推荐

  • Python实战

    转载自Python研究者 作者阿辰 今天教大家如何爬取新浪网新闻数据 通过词云可视化展示新闻关键词 快速了解最新的新闻热点 这里爬取了2500条新闻数据进行演示 PS 这里采集的主要是国内最新新闻数据 写这篇文章的时候是4月26号 所以获取
  • 解决Spring的UnsatisfiedDependencyException异常的方法

    解决Spring的UnsatisfiedDependencyException异常的方法 1 引言 在使用Spring框架进行开发时 经常会遇到UnsatisfiedDependencyException异常 这个异常通常是由于依赖注入失败
  • 僵尸进程的查找及僵尸进程的kill

    首先我们来看看什么是僵尸进程 之前的学习过程中时这样理解僵尸进程的 子进程先于父进程退出 并将退出原因保留在pcb中 因此退出后不会自动释放所有资源 子进程退出后操作系统会通知父进程子进程退出了 你去获取一下原因 再完全释放子进程资源 若父
  • 软件测试基础知识(7)——因果图法

    因果图法 定义 因果图法是一种利用图解法分析输入的各种组合情况 从而设计测试用例的方法 它适合于检查程序输入条件的各种组合情况 特点 1 考虑输入条件的相互制约及组合关系 2 考虑输出条件对输入条件的制约关系 因果图法产生的背景 等价类划分
  • 高可用集群HA、LVS+Keepalived、健康检测

    keepalived是集群管理中保证集群高可用 HA 的一个服务软件 其功能类似于heartbeat 用来防止单点故障 2 工作原理 keepalived是以VRRP协议为实现基础的 当backup收不到vrrp包时就认为master宕掉了
  • 快速排序c++实现

    思想 用过一趟排序将要排序的数据分割成独立的两部分 其中一部分的所有数据都比另外一部分的所有数据要小 然后再对这两部分重复此步骤 直到整个数组变成有序序列 对一个数组实现一趟快速排序的过程 1 定义两个变量 一个指向数组最前 一个指向最后
  • uniapp开发的scroll-view的x轴滑动两端不能够完全显示的修改

    uniapp开发多端应用 做一个scroll view后 在h5可以完全显示 app也可以 就是在小程序端两侧都不能够完全显示 把官方简单的示例代码复制下来调试 发现问题在于scroll view层的class的width 如果设置成100
  • HC-05(ZS-040)蓝牙模块使用详情(蓝牙模块配置、手机蓝牙控制单片机、蓝牙与蓝牙之间的通信)含51、32程序

    HC 05是一款主从一体化的蓝牙模块 因此其使用起来比较方便 只需要进行简单的配置即可 本文就手把手的介绍小白入手模块后如何使用 对于模块使用 1 蓝牙配置 2 手机与蓝牙的传输 3 手机通过蓝牙模块控制单片机 4 一对蓝牙之间主 从传输数
  • java随机抽题系统_随机抽取试题(java+sql 2005)

    import java awt BorderLayout import java util import java awt event import java awt Container import java awt EventQueue
  • 强啊,点赞业务缓存设计优化探索之路。

    背景 内容点赞业务在得物社区中是一个非常高频的业务场景 功能本身复杂度不高 但是业务场景多 QPS高 而且由于社区的用户体量 整体点赞的数据量非常大 其中最核心 对响应性能要求最高的主要是 用户是否点赞内容 和 内容点赞数 场景 在得物社区
  • fgets 函数详解

    描述 C 库函数 char fgets char str int n FILE stream 从指定的流 stream 读取一行 并把它存储在 str 所指向的字符串内 当读取 n 1 个字符时 或者读取到换行符时 或者到达文件末尾时 它会
  • PID ------------------------------------

    28条消息 位置式PID和增量式PID的区别 转载 zhangfengmei1987的博客 CSDN博客 位置式pid 28条消息 自动驾驶 PID实现轨迹跟踪 python实现 C 实现 CHH3213的博客 CSDN博客 轨迹跟踪 P
  • webpack 插件实战笔记(一)

    cnpm init 111Air webpackSerial1 i cnpm init This utility will walk you through creating a package json file It only cove
  • FCOS代码复现错误集合

    在我复现无锚框检测神网络 FCOS时 官方代码 FCOS master令我头疼不已 现将问题总结如下 仅供参考 1 from fcos core import C 遇到这个问题抓耳挠腮了好久 尝试过各种方法 最后不得已 在文件所在目录下重新
  • 图像处理中涉及的灰度图、彩色图以及深度图概念

    图像处理中涉及最多的概念就是图像的类型 为了很好的理解图像的概念以及处理图片 我们就需要对常见的图像具有一定的概念 我们首先介绍一下生活中常见的图像格式 1 bmp格式 这是一种不常见的图像格式 一般为无损图像 没有对图像进行压缩 占用的存
  • Java 脱敏工具类总结

    开发过程中 会遇到很多敏感数据的显示 这样不太安全 就需要用到相关的脱敏工具进行脱敏之后再显示 总结部分脱敏工具 package com li info import org apache commons lang3 StringUtils
  • pycharm的setting里面找不到我们用conda配置好的环境

    原因 电脑里面有多个python版本导致 我们目前添加的python并不是我们anaconda中python的版本 解决办法 在pycharm里面 使用setting里面的Add选项里 可以找到我们配置的所有环境 然后添加进去 具体如下图所
  • sql server将字符串转换为 uniqueidentifier 时失败

    sql server将字符串转换为 uniqueidentifier 时失败 sql server查询中出现 将字符串转换为 uniqueidentifier 时失败异常 原因为id设置为uniqueidentifier 字段 在where
  • shell day3

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

    如题 本人使用UITookit编写了一个UXML的UI界面后 将其搭载到了一个UIDocument对象上 并将该对象作为UI相机的子对象以实现UI界面与相机绑定 在为UIDocument编写交互用的C 时 采用了下面的错误做法 导致UIDo