首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何将JavaFX javafx.scene.shape.Path的实例保存到文件

如何将JavaFX javafx.scene.shape.Path的实例保存到文件
EN

Stack Overflow用户
提问于 2018-08-18 23:32:21
回答 1查看 408关注 0票数 0

我正在尝试将javafx.scene.shape.Path保存到文件(至少是它的元素)中,然而,由于Path是不可序列化的,而且它的PathElement也是不可序列化的,所以它被证明是非常困难的。

有人能告诉我有什么方法可以将对象转换为字符串(首选)、JSON或其他格式吗?

下面是我尝试过的所有保存对象的方法:

代码语言:javascript
复制
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import javafx.scene.shape.Path;
import javafx.scene.shape.Polygon;
import javafx.scene.shape.Rectangle;
import javafx.scene.shape.Shape;

class Test {

  public static void main(String[] args) {

    GsonBuilder builder = new GsonBuilder();
    Path path;
    Gson gson = builder.create();

    {
      Rectangle rectangle = new Rectangle(100, 100);
      Polygon polygon = new Polygon(0, 0, 50, 50, 0, 50);
      path = (Path) Shape.subtract(rectangle, polygon);
    }

    try {
      String completePathObject = gson.toJson(path);
      System.out.println(completePathObject);
    } catch (IllegalArgumentException e) {
      e.printStackTrace();
      // java.lang.IllegalArgumentException: class com.sun.javafx.util.WeakReferenceQueue$ListEntry declares multiple JSON fields named next
    }

    try {
      String pathObjectElements = gson.toJson(path.getElements());
      System.out.println(pathObjectElements);
    } catch (IllegalArgumentException e) {
      e.printStackTrace();
      // java.lang.IllegalArgumentException: class com.sun.javafx.util.WeakReferenceQueue$ListEntry declares multiple JSON fields named next
    }

    try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("test.set"))) {
      objectOutputStream.writeObject(path);
    } catch (IOException e) {
      e.printStackTrace();
//      java.io.NotSerializableException: javafx.scene.shape.Path
    }

    try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("test.set"))) {
      objectOutputStream.writeObject(path.getElements());
    } catch (IOException e) {
      e.printStackTrace();
//      java.io.NotSerializableException: javafx.scene.shape.Path$2
    }
  }
}
EN

回答 1

Stack Overflow用户

发布于 2018-08-20 18:31:03

Node包含许多属性,您需要将其转换为可写入文件的形式。

由于最后一次尝试表明您对将路径元素写入文件感到满意,因此可以将PathElement转换为SVG路径的一部分,还可以实现用于从svg路径字符串解析元素PathElement的逻辑。

下面不接受所有可能的SVG路径,可能会接受一些无效路径:

代码语言:javascript
复制
public class SVGConverter {

    private enum PathElementType {

        ARC('a', ArcTo.class, ArcTo::new,
                ArcTo::radiusXProperty,
                ArcTo::radiusYProperty,
                ArcTo::XAxisRotationProperty,
                ArcTo::largeArcFlagProperty,
                ArcTo::sweepFlagProperty,
                ArcTo::xProperty,
                ArcTo::yProperty),
        CLOSE_PATH('z', ClosePath.class, ClosePath::new),
        CUBIC_CURVE('c', CubicCurveTo.class, CubicCurveTo::new,
                CubicCurveTo::controlX1Property,
                CubicCurveTo::controlY1Property,
                CubicCurveTo::controlX2Property,
                CubicCurveTo::controlY2Property,
                CubicCurveTo::xProperty,
                CubicCurveTo::yProperty),
        H_LINE_TO('h', HLineTo.class, HLineTo::new,
                HLineTo::xProperty),
        LINE_TO('l', LineTo.class, LineTo::new,
                LineTo::xProperty, LineTo::yProperty),
        MOVE_TO('m', MoveTo.class, MoveTo::new,
                MoveTo::xProperty, MoveTo::yProperty),
        QUAD_CURVE_TO('q', QuadCurveTo.class, QuadCurveTo::new,
                QuadCurveTo::controlXProperty, QuadCurveTo::controlYProperty,
                QuadCurveTo::xProperty, QuadCurveTo::yProperty),
        V_LINE_TO('v', VLineTo.class, VLineTo::new,
                VLineTo::yProperty);

        private final char letter;
        private final String typeName;
        private final Supplier<? extends PathElement> factory;
        private final Function[] propertyGetters;

        <T extends PathElement> PathElementType(char letter, Class<T> type, Supplier<T> factory, Function<T, ? extends Property<?>>... propertyGetters) {
            this.letter = letter;
            this.typeName = type.getName();
            this.factory = factory;
            this.propertyGetters = propertyGetters;
        }
    }

    private final Map<String, PathElementType> ELEMENT_TYPES_BY_TYPE;
    private final Map<Character, PathElementType> ELEMENT_TYPES_BY_LETTER;

    public SVGConverter() {
        ELEMENT_TYPES_BY_LETTER = new HashMap<>();
        ELEMENT_TYPES_BY_TYPE = new HashMap<>();

        for (PathElementType et : PathElementType.values()) {
            ELEMENT_TYPES_BY_LETTER.put(et.letter, et);
            ELEMENT_TYPES_BY_TYPE.put(et.typeName, et);
        }
    }

    public String pathToSvg(Path path) {
        StringBuilder sb = new StringBuilder();

        for (PathElement element : path.getElements()) {
            PathElementType elementType = ELEMENT_TYPES_BY_TYPE.get(element.getClass().getName());
            if (elementType == null) {
                throw new IllegalArgumentException("Unknown PathElement type: " + element.getClass().getName());
            }

            // specify path element type
            char c = elementType.letter;
            if (element.isAbsolute()) {
                c = Character.toUpperCase(c);
            }
            sb.append(c);

            // write property values
            for (Function f : elementType.propertyGetters) {
                Property property = (Property) f.apply(element);
                sb.append((property instanceof BooleanProperty)
                        // special treatment for booleans to convert true/false to 1/0
                        ? (((BooleanProperty) property).get() ? "1" : "0")
                        : property.getValue().toString()).append(' ');
            }
        }

        // trim, if necessary
        int lastIndex = sb.length() - 1;
        if (lastIndex >= 0 && sb.charAt(lastIndex) == ' ') {
            sb.deleteCharAt(lastIndex);
        }
        return sb.toString();
    }

    private static final String NUMBER_PATTERN_STRING = "[+-]?\\d*\\.\\d*(?:[eE][+-]?\\d+)?";
    private static final Pattern NUMBER_PATTERN = Pattern.compile("(?<![\\d.+-])(" + NUMBER_PATTERN_STRING + ')');
    private static final Pattern SVG_PATTERN = Pattern.compile("([aAcChHlLvmMqQVzZ])((?:\\s*" + NUMBER_PATTERN_STRING + "(?:[\\s,]+" + NUMBER_PATTERN_STRING + ")*)?)");

    // parses doubles from number sequence
    private static double[] getNumberMatches(Matcher m, int count) {
        double[] result = new double[count];
        for (int i = 0; i < count; i++) {
            if (!m.find()) {
                throw new IllegalArgumentException("missing numbers");
            }
            result[i] = Double.parseDouble(m.group(1));
        }
        if (m.find()) {
            throw new IllegalArgumentException("too many numbers");
        }
        return result;
    }

    public Path svgToPath(String svg) {
        Path path = new Path();
        Matcher matcher = SVG_PATTERN.matcher(svg);
        while (matcher.find()) {
            // find out path element type
            char c = matcher.group(1).charAt(0);
            PathElementType elementType = ELEMENT_TYPES_BY_LETTER.get(Character.toLowerCase(c));
            if (elementType == null) {
                throw new IllegalArgumentException("Unknown path type " + c);
            }

            PathElement element = (PathElement) elementType.factory.get();
            element.setAbsolute(Character.isUpperCase(c));

            // retrieve parameters
            if (elementType.propertyGetters.length > 0) {
                Matcher numberMatcher = NUMBER_PATTERN.matcher(matcher.group(2));
                double[] numbers = getNumberMatches(numberMatcher, elementType.propertyGetters.length);
                for (int i = 0; i < elementType.propertyGetters.length; i++) {
                    Property property = (Property) elementType.propertyGetters[i].apply(element);
                    property.setValue((property instanceof BooleanProperty)
                            ? (numbers[i] == 1) // convert to boolean (true iff 1.0)
                            : numbers[i]);
                }
            }
            path.getElements().add(element);
        }
        return path;
    }
}

注意:这不会恢复任何类型的绑定,这些绑定可能在转换为字符串之前就已经存在了。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51910131

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档