如何扩展 JavaFX Shape 类以实现自定义形状

Posted

技术标签:

【中文标题】如何扩展 JavaFX Shape 类以实现自定义形状【英文标题】:How to extend the JavaFX Shape class to implement custom shapes 【发布时间】:2016-07-05 06:35:24 【问题描述】:

我正在开发一个应用程序来为某些特定问题的二维几何建模。当然,我想在屏幕上绘制那个几何图形,让用户真正看到它。

JavaFX 有一些 2D 形状,如矩形、椭圆等。它也有三次和四次曲线,实现为贝塞尔曲线。搜索自定义形状并没有帮助,因为我发现的只是一些示例,例如获取一些形状元素(例如路径)并将它们组合在一起以绘制自定义形状,例如心形或钻石。搜索有关如何通过扩展 Shape 类来实现新形状的信息就更没用了。

我要绘制的是任意顺序和长度的 B 样条曲线。我知道如何计算和实现样条线本身,但我不知道如何将它们实现为新形状或形状包装器。

我查看了JavaFX的源代码和纪录片。似乎这些形状本身就是某种包装类。例如。 Ellipse 类包含一个椭圆作为成员,它是几何包的一部分。这个递归走得很远。

现在JavaFX必须使用某种方法来实际绘制曲线,但我找不到。

那么我如何扩展 JavaFX 形状以创建例如样条类? Java绘制它的关键是什么方法/类?

我希望有人可以帮助我。

您真诚的托尔斯滕

【问题讨论】:

你能更详细地解释一下为什么Path(它扩展了Shape)还不够吗? 我不认为你将能够直接扩展 Shape 并在不依赖标记的 API 的情况下渲染扩展的形状:“@deprecated 这是一个不打算使用的内部 API,将在下一个版本中删除”。 @VGR 使用路径我只需将不同的形状组合成一个。这将我限制在标准形状类中。所以,例如,我只能画到四度的曲线。对于没有预构建类的所有内容,我必须使用预构建形状类创建该曲线,并将曲线和线段放在一起以创建和近似。 【参考方案1】:

我会看看JSilhoutte 是如何实现它们的形状的。

例如,Cross 不会扩展 Shape,但它通过创建两个矩形并使用 Shape.union 组合它们来生成一个代表十字的 Shape。下面是相关方法:

@Override
protected void calculateShape() 
        double cx = getCenterX();
        double cy = getCenterY();
        double r = getRadius();
        double n = validateRoundness(getRoundness());
        double w = validateWidth(getWidth(), r);

        double arcWH = w * n;
        Rectangle beam1 = new Rectangle(cx - r, cy - (w / 2), r * 2, w);
        Rectangle beam2 = new Rectangle(cx - (w / 2), cy - r, w, r * 2);
        beam1.setArcWidth(arcWH);
        beam1.setArcHeight(arcWH);
        beam2.setArcWidth(arcWH);
        beam2.setArcHeight(arcWH);
        Shape shape = Shape.union(beam1, beam2);

        shape.getStyleClass().addAll("silhouette", "silhoutte-cross");

        setShape(shape);

因此,您可以使用 Shape.union 将多个 CubicCurve/QuadCurve 形状组合在一起,以创建任意顺序和长度的 B 样条曲线。

【讨论】:

【参考方案2】:

我试图做类似的事情,但我没有尝试扩展 Shape,而是尝试扩展 PathElement。我这样做是为了实现一个 nurbsTo 方法,该方法允许我绘制 NURBS 或 B 样条曲线。 PathElement 是一个希望你重写的抽象类:

void addTo(NGPath)

它不是公开的,所以如果你想这样做,你的新类必须在 javafx/scene/shape 包中。所以基本上,你不能那样做。看到这篇文章,我快速查看了编写一个扩展形状的调用是否可行,正如 Thorsten 正确指出的那样,这看起来像是一条艰难的尝试下去的道路,所以我没有追求它。

我采用的方法是让我的 NURBS 类生成一组 MoveTo 命令。我以足够的增量值迭代 U(t) 以获得足够的点,使曲线看起来平滑。这可能是满足 Thorsen 发布需求的最合理方式。如果您查看类似 Circle 的 javafx 实现,那么它在内部也在做同样的事情。默认情况下,Circle 类在圆形上计算 64 个点并绘制线条。对于大多数 NURBS 和 B-Spline 曲线,我发现 100 个点看起来既漂亮又平滑,但这当然取决于所使用的度数、控制点和节点。

【讨论】:

最后,所有非平凡的弯曲几何图形在渲染之前都会被展平为线性线段。 参见:“com.sun.javafx.geom.FlateningPathIterator”。 是的,当然,您在渲染之前将不平凡的曲线变平。这就是您必须做的事情,因为 JavaFX 图形功能使得几乎不可能扩展 PathElement 或开发新的自定义形状。发布的问题是“你如何扩展 Shape?”,我建议不要这样做并采用扁平曲线方法。 FlattenPathIterator 没有用,因为您无法制作自定义 PathElement。

以上是关于如何扩展 JavaFX Shape 类以实现自定义形状的主要内容,如果未能解决你的问题,请参考以下文章

JavaFX:自定义控件

如何使用自定义对象在 JavaFX 中填充 ListView?

javafx datepicker如何自定义

如何在张量流的自定义损失中获取张量的形状

JavaFX自定义窗口标题栏

Android打造万能自定义阴影控件