【Unity编辑器拓展】GraphView自定义可视化节点

1、创建节点区域脚本

其中的new class UxmlFactory,可以让该元素显示在UI Builder中,我们就可以在Library-Project中看到我们新建的这两个UI元素,就可以拖入我们的UI窗口编辑了

public class NodeTreeViewer : GraphView
{public new class UxmlFactory : UxmlFactory<NodeTreeViewer, UxmlTraits> { }
}

默认的GraphView是一片黑屏。在这里,我们给我们的GraphView窗口添加上网格和拖拽缩放功能。

public class NodeTreeViewer : GraphView
{public new class UxmlFactory : UxmlFactory<NodeTreeViewer, UxmlTraits> { }public NodeTree tree;public Action<NodeView> OnNodeSelected;public NodeTreeViewer(){Insert(0, new GridBackground());this.AddManipulator(new ContentZoomer());this.AddManipulator(new ContentDragger());this.AddManipulator(new SelectionDragger());this.AddManipulator(new RectangleSelector());var styleSheet = AssetDatabase.LoadAssetAtPath<StyleSheet>("Assets/NodeEditor/Editor/UI/NodeTreeViewer.uss");styleSheets.Add(styleSheet);}
}

     uss代码参考,上面代码的uss路径要根据项目实际路径进行设置。 

GridBackground{--grid-background-color: rgb(40,40,40);--line-color: rgba(193,196,192,0.1);--thick-line-color: rgba(193,196,192,0.1);--spacing: 15;
}

2、创建节点和删除选中元素

2.1 创建节点类

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEditor.Experimental.GraphView;
using UnityEngine;public class NodeView : UnityEditor.Experimental.GraphView.Node
{public Node node;public Port input;public Port output;public Action<NodeView> OnNodeSelected;public NodeView(Node node){this.node = node;this.title = node.name;this.viewDataKey = node.guid;style.left = node.position.x;style.top = node.position.y;CreateInputPorts();CreateOutputPorts();}//创建输入端口private void CreateInputPorts(){input = InstantiatePort(Orientation.Vertical, Direction.Input, Port.Capacity.Multi, typeof(bool));if(input != null ){input.portName = "";inputContainer.Add(input);}}//创建输出端口private void CreateOutputPorts(){output = InstantiatePort(Orientation.Vertical, Direction.Output, Port.Capacity.Multi, typeof(bool));if (output != null){output.portName = "";outputContainer.Add(output);}}//选中该节点时传递事件public override void OnSelected(){base.OnSelected();if( OnNodeSelected != null ){OnNodeSelected?.Invoke(this);}}//设置生成时位置public override void SetPosition(Rect newPos){base.SetPosition(newPos);node.position.x = newPos.xMin;node.position.y = newPos.yMin;}}

2.2 节点区域创建节点和删除选中元素功能 

//重写该方法,可以添加右键菜单按钮public override void BuildContextualMenu(ContextualMenuPopulateEvent evt){var types = TypeCache.GetTypesDerivedFrom<Node>();foreach (var type in types){evt.menu.AppendAction($"创建节点/{type.Name}", a => CreateNode(type));}evt.menu.AppendAction("删除选中元素", DeleteSelecteNode);}//删除选中元素,节点或者连线private void DeleteSelecteNode(DropdownMenuAction action){DeleteSelection();}//创建节点private void CreateNode(Type type){Node node = tree.CreateNode(type);CreateNodeView(node);}private void CreateNodeView(Node node){NodeView nodeView = new NodeView(node);nodeView.OnNodeSelected = OnNodeSelected;AddElement(nodeView);}

3、设置节点元素输出端可连接端口

public override List<Port> GetCompatiblePorts(Port startPort, NodeAdapter nodeAdapter){return ports.ToList().Where(endpost => endpost.direction != startPort.direction && endpost.node != startPort.node).ToList();}

4、打开或者重新展示已有内容

internal void PopulateView(NodeTree tree){this.tree = tree;graphViewChanged -= OnGraphViewChange;DeleteElements(graphElements.ToList());graphViewChanged += OnGraphViewChange;tree.nodes.ForEach(n => CreateNodeView(n));tree.nodes.ForEach(n =>{var children = tree.GetChildren(n);children.ForEach(c =>{NodeView parentView = FindNodeView(n);NodeView childView = FindNodeView(c);Edge edge = parentView.output.ConnectTo(childView.input);AddElement(edge);});});}

5、当节点区域元素改变时,实现对应逻辑数据的修改

该方法在打开或展现时注册事件

private GraphViewChange OnGraphViewChange(GraphViewChange graphViewChange){if(graphViewChange.elementsToRemove != null){graphViewChange.elementsToRemove.ForEach(elem => { NodeView nodeview = elem as NodeView;if(nodeview != null){tree.DeleteNode(nodeview.node);}Edge edge = elem as Edge;if(edge != null){NodeView parentView = edge.output.node as NodeView;NodeView childView = edge.input.node as NodeView;tree.RemoveChild(parentView.node, childView.node);}});}if(graphViewChange.edgesToCreate != null){graphViewChange.edgesToCreate.ForEach(edge =>{NodeView parentView = edge.output.node as NodeView;NodeView childView = edge.input.node as NodeView;tree.AddChild(parentView.node, childView.node);});}return graphViewChange;}

6、完整代码

运行时代码Runtime Code

6.1 Node

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public abstract class Node : ScriptableObject
{public enum State { Running, Waiting}public State state = State.Waiting;public bool started = false;public List<Node> children = new List<Node>();[HideInInspector] public string guid;[HideInInspector] public Vector2 position;public Node OnUpdate(){if(!started){OnStart();started = true;}Node currentNode = LogicUpdate();if(state != State.Running){OnStop();started = false;}return currentNode;}public abstract Node LogicUpdate();public abstract void OnStart();public abstract void OnStop();}

6.2 NormalNode

using System.Collections;
using System.Collections.Generic;
using UnityEngine;[CreateAssetMenu]
public class NormalNode : Node
{[TextArea]public string dialogueContent;public override Node LogicUpdate(){// 判断进入下一节点条件成功时 需将节点状态改为非运行中 且 返回对应子节点if (Input.GetKeyDown(KeyCode.Space)){state = State.Waiting;if (children.Count > 0){children[0].state = State.Running;return children[0];}}return this;}public override void OnStart(){Debug.Log(dialogueContent);}public override void OnStop(){Debug.Log("OnStop");}
}

6.3 NodeTree

using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;[CreateAssetMenu]
public class NodeTree : ScriptableObject
{public Node rootNode;public Node runningNode;public Node.State treeState = Node.State.Waiting;public List<Node> nodes = new List<Node>();public virtual void Update(){if(treeState == Node.State.Running && runningNode.state == Node.State.Running){runningNode = runningNode.OnUpdate();}}/// <summary>/// 对话树开始的触发方法/// </summary>public virtual void OnTreeStart(){treeState = Node.State.Running;runningNode.state = Node.State.Running;}/// <summary>/// 对话树结束的触发方法/// </summary>public void OnTreeEnd(){treeState = Node.State.Waiting;}#if UNITY_EDITORpublic Node CreateNode(System.Type type){Node node = ScriptableObject.CreateInstance(type) as Node;node.name = type.Name;node.guid = GUID.Generate().ToString();nodes.Add(node);if (!Application.isPlaying){AssetDatabase.AddObjectToAsset(node, this);}AssetDatabase.SaveAssets();return node;}public Node DeleteNode(Node node){nodes.Remove(node);AssetDatabase.RemoveObjectFromAsset(node);AssetDatabase.SaveAssets();return node;}public void RemoveChild(Node parent, Node child){parent.children.Remove(child);}public void AddChild(Node parent, Node child){parent.children.Add(child);}public List<Node> GetChildren(Node parent){return parent.children;}
#endif
}

6.4 NodeTreeRunner

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class NodeTreeRunner : MonoBehaviour
{public NodeTree tree;void Start(){}void Update(){if(Input.GetKeyDown(KeyCode.P)){tree.OnTreeStart();}if(tree != null && tree.treeState == Node.State.Running){tree.Update();}if(Input.GetKeyDown(KeyCode.D)){tree.OnTreeEnd();}}
}

可视化编辑器代码 Editor

6.5 Uxml和Uss

NodeEditor Uxml

<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" xsi="http://www.w3.org/2001/XMLSchema-instance" engine="UnityEngine.UIElements" editor="UnityEditor.UIElements" noNamespaceSchemaLocation="../../../../UIElementsSchema/UIElements.xsd" editor-extension-mode="True"><Style src="NodeEditor.uss" /><ui:VisualElement style="flex-grow: 1; flex-direction: row;"><ui:VisualElement name="LeftDiv" style="flex-grow: 0.3;"><ui:Label text="Inspector" display-tooltip-when-elided="true" name="Inspector" style="font-size: 15px; -unity-font-style: bold;" /><uie:ObjectField label="NodeTree" name="NodeTree" style="flex-grow: 0; flex-shrink: 0; min-width: auto; align-items: stretch; flex-wrap: nowrap; flex-direction: row; width: auto; max-width: none;" /><InspectorViewer style="flex-grow: 1;" /></ui:VisualElement><ui:VisualElement name="RightDiv" style="flex-grow: 0.7;"><ui:Label text="NodeTreeVirwer" display-tooltip-when-elided="true" name="NodeTreeVirwer" style="-unity-font-style: bold; font-size: 15px;" /><NodeTreeViewer focusable="true" style="flex-grow: 1;" /></ui:VisualElement></ui:VisualElement>
</ui:UXML>

NodeTreeViewer Uss

GridBackground{--grid-background-color: rgb(40,40,40);--line-color: rgba(193,196,192,0.1);--thick-line-color: rgba(193,196,192,0.1);--spacing: 15;
}

编辑器面板代码

6.6 NodeEdtor

using System;
using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.UIElements;public class NodeEditor : EditorWindow
{public NodeTreeViewer nodeTreeViewer;public InspectorViewer inspectorViewer;public ObjectField nodeTreeObj;[MenuItem("MyWindows/NodeEditor")]public static void ShowExample(){NodeEditor wnd = GetWindow<NodeEditor>();wnd.titleContent = new GUIContent("NodeEditor");}public void CreateGUI(){// Each editor window contains a root VisualElement objectVisualElement root = rootVisualElement;// Import UXMLvar visualTree = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>("Assets/NodeEditor/Editor/UI/NodeEditor.uxml");visualTree.CloneTree(root);var styleSheet = AssetDatabase.LoadAssetAtPath<StyleSheet>("Assets/NodeEditor/Editor/UI/NodeEditor.uss");root.styleSheets.Add(styleSheet);nodeTreeViewer = root.Q<NodeTreeViewer>();inspectorViewer = root.Q<InspectorViewer>();nodeTreeObj = root.Q("NodeTree") as ObjectField;nodeTreeObj.objectType = typeof(NodeTree);nodeTreeViewer.OnNodeSelected = OnNodeSelectionChanged;}private void OnNodeSelectionChanged(NodeView view){inspectorViewer.UpdateSelection(view.node);}private void OnSelectionChange(){NodeTree tree = Selection.activeObject as NodeTree;if (tree){nodeTreeViewer.PopulateView(tree);nodeTreeObj.value = tree;}else{nodeTreeViewer.CloseNodeTreeViewer();nodeTreeObj.value = null;}}}

6.7 NodeTreeViewer 

using BehaviorDesigner.Runtime.Tasks.Unity.UnityInput;
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEditor.Experimental.GraphView;
using UnityEngine;
using UnityEngine.UIElements;public class NodeTreeViewer : GraphView
{public new class UxmlFactory : UxmlFactory<NodeTreeViewer, UxmlTraits> { }public NodeTree tree;public Action<NodeView> OnNodeSelected;private Vector2 curMousePos;ContentZoomer contentZoomer;ContentDragger contentDragger;public NodeTreeViewer(){Insert(0, new GridBackground());contentZoomer = new ContentZoomer();this.AddManipulator(contentZoomer);contentDragger = new ContentDragger();this.AddManipulator(contentDragger);this.AddManipulator(new SelectionDragger());this.AddManipulator(new RectangleSelector());var styleSheet = AssetDatabase.LoadAssetAtPath<StyleSheet>("Assets/NodeEditor/Editor/UI/NodeTreeViewer.uss");styleSheets.Add(styleSheet);this.RegisterCallback<MouseDownEvent>(OnMouseDown);}private void OnMouseDown(MouseDownEvent evt){Debug.Log(evt.localMousePosition);curMousePos = evt.localMousePosition;Debug.Log(contentZoomer.scaleStep);Debug.Log(contentZoomer.referenceScale);//Debug.Log(contentDragger.p)}public override void BuildContextualMenu(ContextualMenuPopulateEvent evt){var types = TypeCache.GetTypesDerivedFrom<Node>();foreach (var type in types){evt.menu.AppendAction($"创建节点/{type.Name}", a => CreateNode(type));}evt.menu.AppendAction("删除选中元素", DeleteSelecteNode);}private void DeleteSelecteNode(DropdownMenuAction action){DeleteSelection();}private void CreateNode(Type type){Node node = tree.CreateNode(type);node.position = curMousePos;CreateNodeView(node);}private void CreateNodeView(Node node){NodeView nodeView = new NodeView(node);nodeView.OnNodeSelected = OnNodeSelected;AddElement(nodeView);}internal void PopulateView(NodeTree tree){this.tree = tree;graphViewChanged -= OnGraphViewChange;DeleteElements(graphElements.ToList());graphViewChanged += OnGraphViewChange;tree.nodes.ForEach(n => CreateNodeView(n));tree.nodes.ForEach(n =>{var children = tree.GetChildren(n);children.ForEach(c =>{NodeView parentView = FindNodeView(n);NodeView childView = FindNodeView(c);Edge edge = parentView.output.ConnectTo(childView.input);AddElement(edge);});});}public void CloseNodeTreeViewer(){this.tree = null;graphViewChanged -= OnGraphViewChange;DeleteElements(graphElements.ToList());}private GraphViewChange OnGraphViewChange(GraphViewChange graphViewChange){if(graphViewChange.elementsToRemove != null){graphViewChange.elementsToRemove.ForEach(elem => { NodeView nodeview = elem as NodeView;if(nodeview != null){tree.DeleteNode(nodeview.node);}Edge edge = elem as Edge;if(edge != null){NodeView parentView = edge.output.node as NodeView;NodeView childView = edge.input.node as NodeView;tree.RemoveChild(parentView.node, childView.node);}});}if(graphViewChange.edgesToCreate != null){graphViewChange.edgesToCreate.ForEach(edge =>{NodeView parentView = edge.output.node as NodeView;NodeView childView = edge.input.node as NodeView;tree.AddChild(parentView.node, childView.node);});}return graphViewChange;}NodeView FindNodeView(Node node){return GetNodeByGuid(node.guid) as NodeView;}public override List<Port> GetCompatiblePorts(Port startPort, NodeAdapter nodeAdapter){return ports.ToList().Where(endpost => endpost.direction != startPort.direction && endpost.node != startPort.node).ToList();}}

6.8 NodeView

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEditor.Experimental.GraphView;
using UnityEngine;public class NodeView : UnityEditor.Experimental.GraphView.Node
{public Node node;public Port input;public Port output;public Action<NodeView> OnNodeSelected;public NodeView(Node node){this.node = node;this.title = node.name;this.viewDataKey = node.guid;style.left = node.position.x;style.top = node.position.y;CreateInputPorts();CreateOutputPorts();}private void CreateInputPorts(){input = InstantiatePort(Orientation.Vertical, Direction.Input, Port.Capacity.Multi, typeof(bool));if(input != null ){input.portName = "input";inputContainer.Add(input);}}private void CreateOutputPorts(){output = InstantiatePort(Orientation.Vertical, Direction.Output, Port.Capacity.Multi, typeof(bool));if (output != null){output.portName = "output";outputContainer.Add(output);}}public override void OnSelected(){base.OnSelected();if( OnNodeSelected != null ){OnNodeSelected?.Invoke(this);}}public override void SetPosition(Rect newPos){Debug.Log(newPos);base.SetPosition(newPos);node.position.x = newPos.xMin;node.position.y = newPos.yMin;}}

6.9 InspectorViewer

using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;public class InspectorViewer : VisualElement
{public new class UxmlFactory : UxmlFactory<InspectorViewer, UxmlTraits> { }Editor editor;public InspectorViewer(){//this.AddManipulator(new drag)}internal void UpdateSelection(Node node){Clear();UnityEngine.Object.DestroyImmediate(editor);editor = Editor.CreateEditor(node);IMGUIContainer container = new IMGUIContainer(() =>{if (editor.target){editor.OnInspectorGUI();}});Add(container);}}

【Unity UIToolkit】UIBuilder基础教程-制作简易的对话系统编辑器 3步教你玩转Unity编辑器扩展工具_unity uibuilder-CSDN博客

[Unity] GraphView 可视化节点的事件行为树(二) UI Toolkit介绍,制作事件行为树的UI_unity graphview-CSDN博客 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/389628.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

一文了解一下 MindSpeed,MindSpeed 是专为华为昇腾设备设计的大模型分布式加速套件。

https://gitee.com/ascend/MindSpeed Gitee Ascend/MindSpeed 项目&#xff0c;MindSpeed 是针对华为昇腾设备的大模型加速库。 MindSpeed 是专为华为昇腾设备设计的大模型加速库&#xff0c;旨在解决用户在大模型训练过程中遇到的显存资源不足等挑战。该库借鉴了 Megatron、D…

福建聚鼎:现在的装饰画还赚钱不

在轻风拂面的清晨&#xff0c;或在星光璀璨的夜晚&#xff0c;人们常常沉浸于对艺术的思考。装饰画作为艺术的一种表现形式&#xff0c;既丰富了人们的精神世界&#xff0c;又装点了生活的每一个角落。但在这个快速变化的时代&#xff0c;一个引人深思的问题浮出水面&#xff1…

前端-如何通过docker打包Vue服务成镜像并在本地运行(本地可以通过http://localhost:8080/访问前端服务)

1、下载安装docker&#xff0c;最好在vs code里安装docker的插件。 下载链接&#xff1a;https://www.docker.com/products/docker-desktop &#x1f389; Docker 简介和安装 - Docker 快速入门 - 易文档 (easydoc.net) 2、准备配置文件-dockerfile文件和nginx.conf文件 do…

postman查询单条数据Get方法,无任何输出,idea后端也没有任何数据和提示的解决方法

问题描述&#xff1a; 正常使用postman测试&#xff0c;输入内容没有错误&#xff0c;但是却没有任何消息 后端也是&#xff0c;没有任何消息&#xff1a; 解决方法&#xff1a; 问题的原因主要是因为postman&#xff1a; 我们只需要新建一个页面&#xff0c;把刚才的查询语…

《C语言程序设计 第4版》笔记和代码 第十二章 数据体和数据结构基础

12.1从基本数据类型到抽象数据类型 1 所有的程序设计语言都不能将所有复杂数据对象作为其基本数据类型&#xff0c;因此需要允许用户自定义数据类型&#xff0c;在C语言中&#xff0c;就存在构造数据类型&#xff08;复合数据类型&#xff09;。 2 结构体是构造数据类型的一种…

记录|如何统一管理多个同一个对象?

目录 前言一、对象就用对象数组管理更新时间 前言 自己的感想 一开始&#xff0c;自己没弄懂C# winform中的testBox是什么&#xff0c;导致创建多个testBox的时候要用很笨的方法来进行管理。 就是下面这种&#xff1a;用数组一个一个掉用里面的单独属性。 string[] str new …

芋道以开源之名行下作之事 恬不知耻 标榜自己开源 公开源码+sql 不用再加入知识星球

资源 链接: https://pan.baidu.com/s/1TeuxbAUfLQ5_BqMBF1kniQ?pwdcqud 提 取码: cqud 依次为后端、补充版的sql、前端 此文档内安装部署等一应俱全

反序列化靶机serial漏洞复现 超详细教程

环境搭建 漏洞环境&#xff1a;https://www.vulnhub.com/entry/serial-1,349/ 下载后使用Vmware打开 创建新的虚拟机&#xff1a; 选择客户机版本为Ubuntu 64位&#xff1a; 一直下一步&#xff0c;知道选择使用现有磁盘&#xff1a; 选择下载的vmdk磁盘文件&#xff1a; 开机…

24年电赛——自动行驶小车(H题)完赛感受

前言&#xff1a; 笔者大二&#xff0c;也算是第一次正式的打电赛省赛&#xff08;大一电赛的时候还没接触32&#xff0c;校赛的时候就被刷下去了。。。&#xff09;。经过一年的学习&#xff0c;三天两夜的校赛、两天一夜的七校联赛终于是挺到了省赛。比赛过程中真的是有太多感…

Git、Gitlab以及分支管理

分布式版本控制系统 一、Git概述 Git是一种分布式版本控制系统&#xff0c;用于跟踪和管理代码的变更。它由Linus torvalds创建的&#xff0c;最初被设计用于Linux内核的开发。Git 允许开发人员跟踪和管理代码的版本&#xff0c;并且可以在不同的开发人员之间进行协作。 Githu…

浏览器用户文件夹详解 - WebData(八)

1.WebData简介 1.1 什么是WebData文件&#xff1f; WebData文件是Chromium浏览器中用于存储用户表单数据、自动填充信息和支付信息的一个重要文件。每当用户在浏览器中填写表单或保存支付信息时&#xff0c;这些数据都会被记录在WebData文件中。通过这些记录&#xff0c;浏览…

【C语言】C语言期末突击/考研--指针(一篇就够)

目录 一、指针的本质&#xff08;间接访问原理&#xff09; 1.1.指针的定义 1.2.取地址操作符与取值操作符&#xff0c;指针本质 二、指针的传递使用场景 2.1.什么是指针的传递 2.2.指针的传递使用场景 三、指针的偏移使用场景 3.1.指针的偏移 3.2.指针与一维数组 四…

【多线程】阻塞队列

&#x1f3c0;&#x1f3c0;&#x1f3c0;来都来了&#xff0c;不妨点个关注&#xff01; &#x1f3a7;&#x1f3a7;&#x1f3a7;博客主页&#xff1a;欢迎各位大佬! 文章目录 1. 阻塞队列是什么2. 简单使用阻塞队列3. 阻塞队列的应用场景——生产者消费者模型3.1 生产者消…

bootStrap中操作行详情,删除,修改等操作

点击列表某一行的操作按钮&#xff0c;结合swtich case 出发不同操作

spring boot 实现 Stream 钉钉事件订阅

1: 参考链接 https://open.dingtalk.com/document/orgapp/develop-stream-mode-push-server 2&#xff1a;钉钉开放平台订阅配置 配置之后运行一下上面提供的链接 里面的main方法&#xff0c;验证通道 3&#xff1a;订阅启动方式 EventListenerThread eventListenerThrea…

nvm管理node版本问题处理集合

windows上通过nvm管理node版本&#xff0c;通过nvm安装node&#xff0c;报错了&#xff0c;信息&#xff1a; > Could not retrieve https://nodejs.org/dist/latest/SHASUMS256.txt. Get > https://nodejs.org/dist/latest/SHASUMS256.txt: dial tcp 104.20.23.46:443: …

如何通过阿里云服务器部署hexo博客(超详细)

&#x1f44f;大家好&#xff01;我是和风coding&#xff0c;希望我的文章能给你带来帮助&#xff01; &#x1f525;如果感觉博主的文章还不错的话&#xff0c;请&#x1f44d;三连支持&#x1f44d;一下博主哦 &#x1f4dd;点击 我的主页 还可以看到和风的其他内容噢&#x…

软件测试20个基础面试题及答案

什么是软件测试&#xff1f; 答案&#xff1a;软件测试是指在预定的环境中运行程序&#xff0c;为了发现软件存在的错误、缺陷以及其他不符合要求的行为的过程。 软件测试的目的是什么&#xff1f; 答案&#xff1a;软件测试的主要目的是保证软件的质量&#xff0c;并尽可能…

【C++】类和对象两个必看题

这两个题只有一句代码的差别。 看题目之前我先说一下怎么看汇编指令。 第一题&#xff1a;下面程序运行结果是&#xff1f; A.编译报错 B.运行崩溃 C.正常运行 #include <iostream> using namespace std; class A { public:void Print(){cout << "A::Pri…

【数据结构初阶】二叉树与堆(一)

文章目录 一、树的基础概念1、节点与度数2、树的度与高度3、引入&#xff1a;数组下标为何从0开始4、祖先节点5、树是递归定义的6、树与非树的区别7、代码表示 二、二叉树2.1、满二叉树2.2、完全二叉树2.3、完全二叉树的存储 三、堆 一、树的基础概念 1、节点与度数 节点分为…