【问题标题】:Generate a custom object and apply custom fxml file in JavaFX生成自定义对象并在 JavaFX 中应用自定义 fxml 文件
【发布时间】:2017-01-19 10:11:14
【问题描述】:

我想编写一个“简单的 UML 编辑器”

用例

单击 UML 画布,并生成 UML 形状。 生成后,光标位于 UML 形状的左上角。作为this image


这里是示例代码。

Main.java

package application;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;


public class Main extends Application {
    @Override
    public void start(Stage primaryStage) {
        try {
            Parent root = FXMLLoader.load(getClass().getResource("mainView.fxml"));
            Scene scene = new Scene(root);
            primaryStage.setScene(scene);
            primaryStage.show();
        } catch(Exception e) {
            e.printStackTrace();
        }
    }

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

mainView.fxml

<?xml version="1.0" encoding="UTF-8"?>

<?import java.lang.*?>
<?import javafx.scene.layout.*?>


<Pane fx:id="canvas" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" onMouseClicked="#onMouseClicked" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.MainViewController" />

MainViewController.java

package application;

import javafx.fxml.FXML;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Pane;

public class MainViewController {

    @FXML Pane canvas;

    @FXML private void onMouseClicked(MouseEvent event) {
        myCircle c = new myCircle();

        c.setLayoutX(event.getX());
        c.setLayoutY(event.getY());
        canvas.getChildren().add(c);
    }
}

myCircle.fxml

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.shape.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.Scene?>

<Pane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="40.0" prefWidth="40.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
   <children>
      <Circle fx:id="circle" fill="DODGERBLUE" layoutX="20.0" layoutY="20.0" radius="20.0" stroke="BLACK" strokeType="INSIDE" />
   </children>
</Pane>

myCircle.java

package application;

import java.io.IOException;

import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.layout.Parent;
import javafx.scene.shape.Circle;

public class myCircle extends Parent {

    @FXML Circle circle;

    public myCircle() {
        // TODO Auto-generated constructor stub
        FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("myCircle.fxml"));
        //fxmlLoader.setRoot(this);
        fxmlLoader.setController(this);
        try {
            fxmlLoader.load();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        this.getChildren().add(circle);

        System.out.println("generate myCircle");
    }
}

问题

  1. 在文件中:myCircle.java。我无法添加代码fxmlLoader.setRoot(this);,否则会显示错误消息:“已指定根值。” 根节点是动态加载的吗? (我没用&lt;fx:root&gt;setRoot())如果是动态加载,我当前的根节点是哪一个?

  2. 在文件中:myCircle.java。我必须添加行this.getChildren().add(circle);,否则没有圈子生成。为什么?我觉得有些重要的细节我不知道……

  3. 我需要centerXProperty() 来实现绑定线相关功能,但是有一些问题。我的自定义 UML 形状应用并加载自定义 fxml 文件,我无法获得真正的 centerXProperty。我打印 centerXProperty 消息:DoubleProperty [bean: Circle[id=circle, centerX=0.0, centerY=0.0, radius=20.0, fill=0x1e90ffff, stroke=0x000000ff, strokeWidth=1.0], name: centerX, value: 0.0]。无论如何,该值始终为 0.0。我该怎么办?

我不想输入意大利面条代码。

【问题讨论】:

    标签: javafx javafx-8 fxml


    【解决方案1】:
    1. FXML 文件的根元素是&lt;Pane&gt; 元素,它基本上是对FXMLLoader 创建Pane 实例的指令,该实例成为根。因此,当您尝试调用 fxmlLoader.setRoot(...) 时,它会抱怨,因为 FXML 文件中已经指定了一个根。要解决此问题,您需要使用 &lt;fx:root...&gt; 作为根元素:

      <?xml version="1.0" encoding="UTF-8"?>
      
      <?import javafx.scene.shape.*?>
      <?import java.lang.*?>
      <?import javafx.scene.layout.*?>
      <?import javafx.scene.Scene?>
      
      <fx:root type="Pane" maxHeight="-Infinity" maxWidth="-Infinity" 
          minHeight="-Infinity" minWidth="-Infinity" 
          prefHeight="40.0" prefWidth="40.0" 
          xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
         <children>
            <Circle fx:id="circle" fill="DODGERBLUE" layoutX="20.0" layoutY="20.0" radius="20.0" stroke="BLACK" strokeType="INSIDE" />
         </children>
      </fx:root>
      

      为了使fxmlLoader.setRoot(this) 工作,this 必须是&lt;fx:root&gt;type 属性指定的类的实例,即您必须使myCircle 成为Pane 的子类:

      package application;
      
      import java.io.IOException;
      
      import javafx.fxml.FXML;
      import javafx.fxml.FXMLLoader;
      import javafx.scene.layout.Pane;
      import javafx.scene.shape.Circle;
      
      public class myCircle extends Pane {
      
          @FXML Circle circle;
      
          public myCircle() {
              // TODO Auto-generated constructor stub
              FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("myCircle.fxml"));
              fxmlLoader.setRoot(this);
              fxmlLoader.setController(this);
              try {
                  fxmlLoader.load();
              } catch (IOException e) {
                  // TODO Auto-generated catch block
                  e.printStackTrace();
              }
      
              // circle is now added to this by the FXML. 
              // So next line is no longer needed:
              // this.getChildren().add(circle);
      
              System.out.println("generate myCircle");
          }
      }
      
    2. 通过修复fxmlLoader.setRoot(this) 来修复。圆圈是Pane 的子代,它是FMXL 文件的根。以前,除非您明确这样做,否则它不会添加到 myCircle 实例中。

    3. 您永远不会更改 centerXcenterY 属性,因此它们将始终为 0。您的意思是在 FXML 中使用 centerX="20" 而不是 layoutX="20" 吗?如果您想公开它们以进行绑定/设置/等,您可以在 myCircle 类中这样做:

      package application;
      
      import java.io.IOException;
      
      import javafx.beans.property.DoubleProperty ;
      import javafx.fxml.FXML;
      import javafx.fxml.FXMLLoader;
      import javafx.scene.layout.Pane;
      import javafx.scene.shape.Circle;
      
      public class myCircle extends Pane {
      
          @FXML Circle circle;
      
          public myCircle() {
              // TODO Auto-generated constructor stub
              FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("myCircle.fxml"));
              fxmlLoader.setRoot(this);
              fxmlLoader.setController(this);
              try {
                  fxmlLoader.load();
              } catch (IOException e) {
                  // TODO Auto-generated catch block
                  e.printStackTrace();
              }
      
              // circle is now added to this by the FXML. 
              // So next line is no longer needed:
              // this.getChildren().add(circle);
      
              System.out.println("generate myCircle");
          }
      
          public DoubleProperty centerXProperty() {
              return circle.centerXProperty();
          }
      
          public final double getCenterX() {
              return centerXProperty().get();
          }
      
          public final void setCenterX(double centerX) {
              centerXProperty().set(centerX);
          }
      
          // same for centerY...
      }
      

      您也可以考虑将MyCircle 设为Circle 的子类,这样您就可以简单地继承centerXcenterY 属性。即

      package application;
      
      import java.io.IOException;
      
      import javafx.fxml.FXML;
      import javafx.fxml.FXMLLoader;
      import javafx.scene.shape.Circle;
      
      public class myCircle extends Circle {
      
          public myCircle() {
              // TODO Auto-generated constructor stub
              FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("myCircle.fxml"));
              fxmlLoader.setRoot(this);
              fxmlLoader.setController(this);
              try {
                  fxmlLoader.load();
              } catch (IOException e) {
                  // TODO Auto-generated catch block
                  e.printStackTrace();
              }
      
              System.out.println("generate myCircle");
          }
      }
      

      然后

      <?xml version="1.0" encoding="UTF-8"?>
      
      <?import javafx.scene.shape.*?>
      <?import java.lang.*?>
      <?import javafx.scene.layout.*?>
      <?import javafx.scene.Scene?>
      
      <fx:root type="Circle" fill="DODGERBLUE" layoutX="20.0" layoutY="20.0" 
          radius="20.0" stroke="BLACK" strokeType="INSIDE"
          xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
      </fx:root>
      

      虽然我不确定这是否仍能为您提供所需的所有功能。

    【讨论】:

      猜你喜欢
      • 2020-07-24
      • 1970-01-01
      • 1970-01-01
      • 2013-11-04
      • 1970-01-01
      • 2017-07-15
      • 2014-10-10
      • 2015-01-14
      • 1970-01-01
      相关资源
      最近更新 更多