创建自定义数据类型

小部件使我们能够控制和可视化不同类型的数据。 该数据可以是整数或双精度甚至Java对象。 为这些类型的数据创建一个容器类会帮助小部件显示它们。 如果窗口小部件将处理单个字段数据类型(例如,双精度,数组或字符串),则无需创建自己的数据类。

创建数据类

在此示例中,我们将为 2D 点及其 x 和 y 坐标创建自定义数据类型。为了创建自定义数据类型类,它必须扩展抽象类`ComplexData <https://github.com/wpilibsuite/shuffleboard/blob/main/api/src/main/java/edu/wpi/first/shuffleboard /api/data/ComplexData.java>`_.您的自定义数据类还必须实现 asMap() 方法,该方法将表示的数据作为简单地图返回,如下所述,带有 @Override 批注:

import edu.wpi.first.shuffleboard.api.data.ComplexData;

import java.util.Map;

public class MyPoint2D extends ComplexData<MyPoint2D> {

   private final double x;
   private final double y;

   //Constructor should take all the different fields needed and assign them their corresponding instance variables.
   public MyPoint2D(double x, double y) {
      this.x = x;
      this.y = y;
   }

   @Override
   public Map<String, Object> asMap() {
      return Map.of("x", x, "y", y);
   }
}

覆盖默认的“equals”和“hashcode”方法也是一种很好的做法,以确保不同的对象在其字段相同时被认为是等效的。 asMap() 方法应该返回以简单 Map 对象表示的数据,因为它将被映射到它对应的 NetworkTables 条目。在这种情况下,我们可以将点表示为其 X 和 Y 坐标,并返回一个包含它们的“地图”。

import edu.wpi.first.shuffleboard.api.data.ComplexData;

import java.util.Map;

public final class MyPoint2D extends ComplexData<MyPoint2D> {

   private final double x;
   private final double y;

   // Constructor should take all the different fields needed and assign them to their corresponding instance variables.
   public Point(double x, double y) {
      this.x = x;
      this.y = y;
   }

   @Override
   public Map<String, Object> asMap() {
      return Map.of("x", this.x, "y", this.y);
   }
 }

可以添加其他方法来检索或编辑字段和实例变量,但是,优良作法是使这些类不可变以防止更改源数据对象。 相反,您可以创建一个新的副本对象,而不是操纵现有对象。 例如,如果要更改点的y坐标,则可以定义以下方法:

public MyPoint2D withY(double newY) {
   return new MyPoint2D(this.x, newY);
}

这将创建一个新的MyPoint2D对象,并以新的y坐标返回它。 更改x坐标时也可以这样做。

创建数据类型

可以创建两种不同的数据类型:仅具有一个字段(即单个数字或字符串)的简单数据类型,以及具有多个数据字段(即多个字符串,多个数字)的复杂数据类型。

为了定义一个简单的数据类型,该类必须用所需的数据类型扩展“ SimpleDataType<DataType>”类,并使用“ getDefaultValue()”方法。 在此示例中,我们将使用double作为我们的简单数据类型。

public final class MyDoubleDataType extends SimpleDataType<Double> {

   private static final String NAME = "Double";

   private MyDataType() {
      super(NAME, Double.class);
   }

   @Override
   public Double getDefaultValue() {
      return 0.0;
   }

}

将类构造函数设置为私密,以确保仅存在数据类型的单个实例。

为了定义复杂的数据类型,该类必须扩展“ComplexDataType”类,并覆盖“fromMap()”和“getDefaultValue()”方法。 我们将以MyPoint2D类为例,以了解复杂数据类型类的外观。

public final class PointDataType extends ComplexDataType<MyPoint2D> {

   private static final String NAME = "MyPoint2D";
   public static final PointDataType Instance = new PointDataType();

   private PointDataType() {
      super(NAME, MyPoint2D.class);
   }

   @Override
   public Function<Map<String, Object>, MyPoint2D> fromMap() {
      return map -> {
         return new MyPoint2D((double) map.getOrDefault("x", 0.0), (double) map.getOrDefault("y", 0.0));
      };
   }

   @Override
   public MyPoint2D getDefaultValue() {
      // use default values of 0 for X and Y coordinates
      return new MyPoint2D(0, 0);
   }

}

上面的以下代码按规定工作:

fromMap() 方法使用它绑定到的 NetworkTables 条目中的值创建一个新的 MyPoint2D。如果无法获取条目值,getOrDefault 方法将返回 0.0。如果不存在源,getDefaultValue 将返回一个新的``MyPoint2D`` 对象。

将数据类型导出到插件

为了让Shuffleboard能够识别数据类型,插件必须通过覆盖“getDataTypes”的方法来导出它们。 例如,

public class MyPlugin extends Plugin {

   @Override
   public List<DataType> getDataTypes() {
      return List.of(PointDataType.Instance);
   }

}