生成自定义对象并在JavaFX中应用自定义fxml文件

时间:2017-01-19 10:11:15

标签: javafx javafx-8 fxml

我想编写一个“简单的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);,或者它将显示错误消息:“已指定根值”。 根节点是否动态加载? (我没有使用<fx:root>setRoot())如果是动态加载,哪一个是我当前的根节点?

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

  3. 我需要centerXProperty()来实现绑定行相对功能,但是存在一些问题。我的自定义UML形状应用并加载自定义fxml文件,我无法获得真正的centerXProperty。我打印centerXProperty messege: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。我该怎么办?
  4. 我不想输入意大利面条代码。

1 个答案:

答案 0 :(得分:0)

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

    <?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必须是type属性<fx:root>指定的类的实例,即您必须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>
    

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