Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/349.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何沿贝塞尔曲线书写文本?_Java_Javafx 2_Javafx 8 - Fatal编程技术网

Java 如何沿贝塞尔曲线书写文本?

Java 如何沿贝塞尔曲线书写文本?,java,javafx-2,javafx-8,Java,Javafx 2,Javafx 8,我希望在JavaFX2.2或至少在JavaFX8中做类似的事情。我浏览了网页,没有结果 可以通过在图形中显示和svg来实现此效果。但是我的应用程序必须显示大量具有这种效果的文本。WebView组件太重,无法绘制具有此效果的文本 我在上问了同样的问题。您可以使用WebView和一些html来显示svg。以下是一个例子: import javafx.application.Application; import javafx.scene.Scene; import javafx.scene.lay

我希望在JavaFX2.2或至少在JavaFX8中做类似的事情。我浏览了网页,没有结果

可以通过在图形中显示和svg来实现此效果。但是我的应用程序必须显示大量具有这种效果的文本。WebView组件太重,无法绘制具有此效果的文本


我在上问了同样的问题。

您可以使用WebView和一些html来显示svg。以下是一个例子:

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.scene.web.WebView;
import javafx.stage.Stage;

public class CurvedText extends Application {

  public static void main(String[] args) {
    launch(args);
  }

  @Override
  public void start(Stage primaryStage) throws Exception {
    StackPane root = new StackPane();
    WebView view = new WebView();
    view.getEngine().loadContent("<!DOCTYPE html>\n" +
            "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n" +
            "  <body>\n" +
            "<embed width=\"100\" height=\"100\" type=\"image/svg+xml\" src=\"path.svg\">\n" +
            "  <svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">" +
            "<defs>\n" +
            "  <path id=\"textPath\" d=\"M10 50 C10 0 90 0 90 50\"/>\n" +
            "</defs>\n"+
            "<text fill=\"red\">\n" +
            "  <textPath xlink:href=\"#textPath\">Text on a Path</textPath>\n" +
            "</text>" +
            "</svg>\n" +
            "</embed>" +
            "  </body>\n" +
            "</html>");
    root.getChildren().add(view);
    Scene scene = new Scene(root, 500, 500);
    primaryStage.setScene(scene);
    primaryStage.show();
  }
}
导入javafx.application.application;
导入javafx.scene.scene;
导入javafx.scene.layout.StackPane;
导入javafx.scene.web.WebView;
导入javafx.stage.stage;
公共类CurvedText扩展了应用程序{
公共静态void main(字符串[]args){
发射(args);
}
@凌驾
public void start(Stage primaryStage)引发异常{
StackPane root=新的StackPane();
WebView视图=新建WebView();
view.getEngine().loadContent(“\n”+
“\n”+
“\n”+
“\n”+
"  " +
“\n”+
“\n”+
“\n”+
“\n”+
“路径上的文本\n”+
"" +
“\n”+
"" +
“\n”+
"");
root.getChildren().add(视图);
场景=新场景(根,500500);
初级阶段。场景(场景);
primaryStage.show();
}
}
结果:

这不是最佳的解决方案,因为根据我的经验,当JavaFXWebView的行为应该像一个标签时,它的行为有点敏感,但这是一个开始

编辑

因为您不想直接使用WebView,所以可以使用WebView的单个实例来使用html渲染场景,然后对其进行快照以生成ImageView。请参见此示例:

import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.Worker;
import javafx.scene.Scene;
import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage;
import javafx.scene.layout.HBox;
import javafx.scene.web.WebView;
import javafx.stage.Stage;

public class CurvedText extends Application {

  public static void main(String[] args) {
    launch(args);
  }

  @Override
  public void start(Stage primaryStage) throws Exception {
    final HBox root = new HBox();
    final WebView view = new WebView();
    view.getEngine().loadContent("<!DOCTYPE html>\n" +
            "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n" +
            "  <body>\n" +
            "<embed width=\"100\" height=\"100\" type=\"image/svg+xml\" src=\"path.svg\">\n" +
            "  <svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">" +
            "<defs>\n" +
            "  <path id=\"textPath\" d=\"M10 50 C10 0 90 0 90 50\"/>\n" +
            "</defs>\n"+
            "<text fill=\"red\">\n" +
            "  <textPath xlink:href=\"#textPath\">Text on a Path</textPath>\n" +
            "</text>" +
            "</svg>\n" +
            "</embed>" +
            "  </body>\n" +
            "</html>");
    root.getChildren().add(view);
    view.getEngine().getLoadWorker().stateProperty().addListener(new ChangeListener<Worker.State>() {
      @Override
      public void changed(ObservableValue<? extends Worker.State> arg0, Worker.State oldState, Worker.State newState) {
        if (newState == Worker.State.SUCCEEDED) {
          // workaround for https://javafx-jira.kenai.com/browse/RT-23265
          AnimationTimer waitForViewToBeRendered = new AnimationTimer(){
            private int frames = 0;
            @Override
            public void handle(long now) {
              if (frames++ > 3){
                WritableImage snapshot = view.snapshot(null, null);
                ImageView imageView = new ImageView(snapshot);
                root.getChildren().add(imageView);
                this.stop();
              }
            }
          };
          waitForViewToBeRendered.start();
        }
      }
    });
    Scene scene = new Scene(root, 500, 500);
    primaryStage.setScene(scene);
    primaryStage.show();
  }
}
导入javafx.animation.AnimationTimer;
导入javafx.application.application;
导入javafx.beans.value.ChangeListener;
导入javafx.beans.value.observeValue;
导入javafx.concurrent.Worker;
导入javafx.scene.scene;
导入javafx.scene.image.ImageView;
导入javafx.scene.image.WritableImage;
导入javafx.scene.layout.HBox;
导入javafx.scene.web.WebView;
导入javafx.stage.stage;
公共类CurvedText扩展了应用程序{
公共静态void main(字符串[]args){
发射(args);
}
@凌驾
public void start(Stage primaryStage)引发异常{
最终HBox根=新HBox();
最终网络视图=新网络视图();
view.getEngine().loadContent(“\n”+
“\n”+
“\n”+
“\n”+
"  " +
“\n”+
“\n”+
“\n”+
“\n”+
“路径上的文本\n”+
"" +
“\n”+
"" +
“\n”+
"");
root.getChildren().add(视图);
view.getEngine().getLoadWorker().stateProperty().addListener(新的ChangeListener()){
@凌驾
公共空间改变了(observeValue这里有一种滥用,将文本绘制在一条直线上

该程序允许您拖动控制点来定义曲线,然后沿该曲线绘制文本。文本中的字符间距相等,因此,如果曲线的总长度与文本宽度非常接近,且具有“正常”间距,则效果最佳,并且不会对诸如紧排之类的内容进行调整

以下示例显示:

  • 有效果的曲线文本
  • 一些弯曲的文本没有应用任何效果
  • 用于定义无效果文本沿的曲线路径的控制操纵点
  • 解决方案是基于StackOverflow问题的答案进行的快速破解:。我相信,通过更多的努力、时间和技能,可以找到更好的解决方案

    因为这个程序是基于转换的,所以很容易采用它,这样文本就可以按照曲线进行动画处理,在溢出时从右到左进行换行(就像你在或股票行情中看到的那样)

    任何标准的JavaFX效果(如光晕、阴影等)和字体更改都可以应用于从您的问题中的paintshop pro文本中获得阴影效果。光晕效果是一种很好的应用效果,因为它可以微妙地软化旋转字符周围的锯齿状边缘

    此外,此解决方案所基于的路径转换可以采用任意形状作为路径输入,因此文本可以遵循其他类型的路径,而不仅仅是三次曲线

    import javafx.animation.*;
    import javafx.application.Application;
    import javafx.beans.property.DoubleProperty;
    import javafx.collections.*;
    import javafx.event.*;
    import javafx.scene.*;
    import javafx.scene.control.ToggleButton;
    import javafx.scene.effect.Glow;
    import javafx.scene.input.MouseEvent;
    import javafx.scene.paint.Color;
    import javafx.scene.shape.*;
    import javafx.scene.text.Text;
    import javafx.stage.Stage;
    import javafx.util.Duration;
    
    /**
     * Example of drawing text along a cubic curve.
     * Drag the anchors around to change the curve.
     */
    public class BezierTextPlotter extends Application {
        private static final String CURVED_TEXT = "Bézier Curve";
    
        public static void main(String[] args) throws Exception {
            launch(args);
        }
    
        @Override
        public void start(final Stage stage) throws Exception {
            final CubicCurve curve = createStartingCurve();
    
            Line controlLine1 = new BoundLine(curve.controlX1Property(), curve.controlY1Property(), curve.startXProperty(), curve.startYProperty());
            Line controlLine2 = new BoundLine(curve.controlX2Property(), curve.controlY2Property(), curve.endXProperty(), curve.endYProperty());
    
            Anchor start = new Anchor(Color.PALEGREEN, curve.startXProperty(), curve.startYProperty());
            Anchor control1 = new Anchor(Color.GOLD, curve.controlX1Property(), curve.controlY1Property());
            Anchor control2 = new Anchor(Color.GOLDENROD, curve.controlX2Property(), curve.controlY2Property());
            Anchor end = new Anchor(Color.TOMATO, curve.endXProperty(), curve.endYProperty());
    
            final Text text = new Text(CURVED_TEXT);
            text.setStyle("-fx-font-size: 40px");
            text.setEffect(new Glow());
            final ObservableList<Text> parts = FXCollections.observableArrayList();
            final ObservableList<PathTransition> transitions = FXCollections.observableArrayList();
            for (char character : text.textProperty().get().toCharArray()) {
                Text part = new Text(character + "");
                part.setEffect(text.getEffect());
                part.setStyle(text.getStyle());
                parts.add(part);
                part.setVisible(false);
    
                transitions.add(createPathTransition(curve, part));
            }
    
            final ObservableList<Node> controls = FXCollections.observableArrayList();
            controls.setAll(controlLine1, controlLine2, curve, start, control1, control2, end);
    
            final ToggleButton plot = new ToggleButton("Plot Text");
            plot.setOnAction(new PlotHandler(plot, parts, transitions, controls));
    
            Group content = new Group(controlLine1, controlLine2, curve, start, control1, control2, end, plot);
            content.getChildren().addAll(parts);
    
            stage.setTitle("Cubic Curve Manipulation Sample");
            stage.setScene(new Scene(content, 400, 400, Color.ALICEBLUE));
            stage.show();
        }
    
        private PathTransition createPathTransition(CubicCurve curve, Text text) {
            final PathTransition transition = new PathTransition(Duration.seconds(10), curve, text);
    
            transition.setAutoReverse(false);
            transition.setCycleCount(PathTransition.INDEFINITE);
            transition.setOrientation(PathTransition.OrientationType.ORTHOGONAL_TO_TANGENT);
            transition.setInterpolator(Interpolator.LINEAR);
    
            return transition;
        }
    
        private CubicCurve createStartingCurve() {
            CubicCurve curve = new CubicCurve();
            curve.setStartX(50);
            curve.setStartY(200);
            curve.setControlX1(150);
            curve.setControlY1(300);
            curve.setControlX2(250);
            curve.setControlY2(50);
            curve.setEndX(350);
            curve.setEndY(150);
            curve.setStroke(Color.FORESTGREEN);
            curve.setStrokeWidth(4);
            curve.setStrokeLineCap(StrokeLineCap.ROUND);
            curve.setFill(Color.CORNSILK.deriveColor(0, 1.2, 1, 0.6));
            return curve;
        }
    
        class BoundLine extends Line {
            BoundLine(DoubleProperty startX, DoubleProperty startY, DoubleProperty endX, DoubleProperty endY) {
                startXProperty().bind(startX);
                startYProperty().bind(startY);
                endXProperty().bind(endX);
                endYProperty().bind(endY);
                setStrokeWidth(2);
                setStroke(Color.GRAY.deriveColor(0, 1, 1, 0.5));
                setStrokeLineCap(StrokeLineCap.BUTT);
                getStrokeDashArray().setAll(10.0, 5.0);
            }
        }
    
        // a draggable anchor displayed around a point.
        class Anchor extends Circle {
            Anchor(Color color, DoubleProperty x, DoubleProperty y) {
                super(x.get(), y.get(), 10);
                setFill(color.deriveColor(1, 1, 1, 0.5));
                setStroke(color);
                setStrokeWidth(2);
                setStrokeType(StrokeType.OUTSIDE);
    
                x.bind(centerXProperty());
                y.bind(centerYProperty());
                enableDrag();
            }
    
            // make a node movable by dragging it around with the mouse.
            private void enableDrag() {
                final Delta dragDelta = new Delta();
                setOnMousePressed(new EventHandler<MouseEvent>() {
                    @Override
                    public void handle(MouseEvent mouseEvent) {
                        // record a delta distance for the drag and drop operation.
                        dragDelta.x = getCenterX() - mouseEvent.getX();
                        dragDelta.y = getCenterY() - mouseEvent.getY();
                        getScene().setCursor(Cursor.MOVE);
                    }
                });
                setOnMouseReleased(new EventHandler<MouseEvent>() {
                    @Override
                    public void handle(MouseEvent mouseEvent) {
                        getScene().setCursor(Cursor.HAND);
                    }
                });
                setOnMouseDragged(new EventHandler<MouseEvent>() {
                    @Override
                    public void handle(MouseEvent mouseEvent) {
                        double newX = mouseEvent.getX() + dragDelta.x;
                        if (newX > 0 && newX < getScene().getWidth()) {
                            setCenterX(newX);
                        }
                        double newY = mouseEvent.getY() + dragDelta.y;
                        if (newY > 0 && newY < getScene().getHeight()) {
                            setCenterY(newY);
                        }
                    }
                });
                setOnMouseEntered(new EventHandler<MouseEvent>() {
                    @Override
                    public void handle(MouseEvent mouseEvent) {
                        if (!mouseEvent.isPrimaryButtonDown()) {
                            getScene().setCursor(Cursor.HAND);
                        }
                    }
                });
                setOnMouseExited(new EventHandler<MouseEvent>() {
                    @Override
                    public void handle(MouseEvent mouseEvent) {
                        if (!mouseEvent.isPrimaryButtonDown()) {
                            getScene().setCursor(Cursor.DEFAULT);
                        }
                    }
                });
            }
    
            // records relative x and y co-ordinates.
            private class Delta {
                double x, y;
            }
        }
    
        // plots text along a path defined by provided bezier control points.
        private static class PlotHandler implements EventHandler<ActionEvent> {
            private final ToggleButton plot;
            private final ObservableList<Text> parts;
            private final ObservableList<PathTransition> transitions;
            private final ObservableList<Node> controls;
    
            public PlotHandler(ToggleButton plot, ObservableList<Text> parts, ObservableList<PathTransition> transitions, ObservableList<Node> controls) {
                this.plot = plot;
                this.parts = parts;
                this.transitions = transitions;
                this.controls = controls;
            }
    
            @Override
            public void handle(ActionEvent actionEvent) {
                if (plot.isSelected()) {
                    for (int i = 0; i < parts.size(); i++) {
                        parts.get(i).setVisible(true);
                        final Transition transition = transitions.get(i);
                        transition.stop();
                        transition.jumpTo(Duration.seconds(10).multiply((i + 0.5) * 1.0 / parts.size()));
                        // just play a single animation frame to display the curved text, then stop
                        AnimationTimer timer = new AnimationTimer() {
                            int frameCounter = 0;
    
                            @Override
                            public void handle(long l) {
                                frameCounter++;
                                if (frameCounter == 1) {
                                    transition.stop();
                                    stop();
                                }
                            }
                        };
                        timer.start();
                        transition.play();
                    }
                    plot.setText("Show Controls");
                } else {
                    plot.setText("Plot Text");
                }
    
                for (Node control : controls) {
                    control.setVisible(!plot.isSelected());
                }
    
                for (Node part : parts) {
                    part.setVisible(plot.isSelected());
                }
            }
        }
    }
    
    导入javafx.animation.*;
    导入javafx.application.application;
    导入javafx.beans.property.DoubleProperty;
    导入javafx.collections.*;
    导入javafx.event.*;
    导入javafx.scene.*;
    导入javafx.scene.control.ToggleButton;
    导入javafx.scene.effect.Glow;
    导入javafx.scene.input.MouseEvent;
    导入javafx.scene.paint.Color;
    导入javafx.scene.shape.*;
    导入javafx.scene.text.text;
    导入javafx.stage.stage;
    导入javafx.util.Duration;
    /**
    *沿三次曲线绘制文本的示例。
    *拖动定位点以更改曲线。
    */
    公共类BezierTextPlotter扩展应用程序{
    私有静态最终字符串弯曲_TEXT=“Bézier曲线”;
    公共静态void main(字符串[]args)引发异常{
    发射(args);
    }
    @凌驾
    public void start(final Stage)引发异常{
    最终立方体曲线=createStartingCurve();
    Line controlLine1=新边界线(curve.controlX1Property()、curve.controlY1Property()、curve.startXProperty()、curve.StartProperty());
    Line controlLine2=新边界线(curve.controlX2Property()、curve.controlY2Property()、curve.endXProperty()、curve.endYProperty());
    锚点开始=新锚点(Color.PALEGREEN,curve.startXProperty(),curve.startYProperty());
    Anchor control1=新锚(Color.GOLD、curve.controlX1Property()、curve.ControlyProperty());
    锚点控制2=新锚点(Color.GOLDENROD,curve.controlX2Property(),curve.controlY2Property());
    锚定端=新