需要帮助创建自定义UI并将其添加到Scene Builder

时间:2015-10-15 09:50:56

标签: javafx javafx-8 scenebuilder

我是Netbeans,JavaFX和Scene Builder的新手。我使用最新版本,意思是8.x.我有一个要求,从几年开始捕捉。年份长度为4位,应为数字。

我找到了一个解决方案,并将其作为独立演示进行了测试。所以我创建了以下FXML和一个JAVA来创建一个JAR,我可以在Scene Builder中导入它。

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

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

    <fx:root id="AnchorPane" prefHeight="30.0" prefWidth="150.0"       type="AnchorPane" xmlns="http://javafx.com/javafx/8.0.40" xmlns:fx="http://javafx.com/fxml/1" fx:controller="numbertextfield.NumberTextField">
    <children>
          <TextField layoutX="14.0" layoutY="14.0" prefHeight="30.0"  prefWidth="150.0" promptText="Enter only numbers " AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
       </children>
    </fx:root>

控制器代码是

package numbertextfield;

import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.control.TextField;

/**
 *
 * @author Hornigold Arthur
 */
public class NumberTextField extends TextField {

    private final IntegerProperty maxLength = new SimpleIntegerProperty(this, "maxLength", -1);
    private final StringProperty restrict = new SimpleStringProperty(this, "restrict");

    @FXML
    private TextField numberTextField;

    public void NumberTextFieldController() {
        // TODO
        System.out.println(" Inside NumberTextField Controller");

        numberTextField.textProperty().addListener(new ChangeListener<String>() {
            private boolean ignore;

            @Override
            public void changed(ObservableValue<? extends String> observableValue, String s, String s1) {

                if (ignore || s1 == null) {
                    return;
                }
                if (maxLength.get() > -1 && s1.length() > maxLength.get()) {
                    ignore = true;
                    numberTextField.setText(s1.substring(0, maxLength.get()));
                    ignore = false;
                }

                if (restrict.get() != null && !restrict.get().equals("") && !s1.matches(restrict.get() + "*")) {
                    ignore = true;
                    numberTextField.setText(s);
                    ignore = false;
                }
            }
        });
//
       FXMLLoader fxmlLoader = new FXMLLoader(
                getClass().getResource("/NumberTextField.fxml"));      

        fxmlLoader.setRoot(this);
        fxmlLoader.setController(this);

        try {
            fxmlLoader.load();
        } catch (IOException exception) {
            throw new RuntimeException(exception);
        }
//       
    }

    /**
     *      * The max length property.      *      * @return The max le
     * @return ngth
     * property.      
     */
    public IntegerProperty maxLengthProperty() {
        return maxLength;
    }

    /**
     *      * Gets the max length of the text field.      *      * @return The
     * max length.      
     * @return 
     */
    public int getMaxLength() {
        return maxLength.get();
    }

    /**
     *      * Sets the max length of the text field.      *      * @param
     * maxLength The max length.
     * @param maxLength
     */
    public void setMaxLength(int maxLength) {
        this.maxLength.set(maxLength);
    }

    /**
     *      * The restrict property.      *      * @return The restrict
     * property.
     * @return 
     */
    public StringProperty restrictProperty() {
        return restrict;
    }

    /**
     *      * Gets a regular expression character class which restricts the user
     * input.        *      * @return The regular expression.      * @see
     * #getRestrict()
     
     * @return 
     */
    public String getRestrict() {
        return restrict.get();
    }

    /**
     *      * Sets a regular expression character class which restricts the user
     * input.        * E.g. [0-9] only allows numeric values.      *      
     *
     *
     * @param restrict The regular expression.      
     */
    public void setRestrict(String restrict) {
        this.restrict.set(restrict);
    }
}

我在Scene Builder中将jar文件导入为自定义类并构建了一个  FXML用于独立模块。

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

    <?import numbertextfield.*?>
    <?import java.lang.*?>
    <?import java.util.*?>
    <?import javafx.scene.*?>
    <?import javafx.scene.control.*?>
    <?import javafx.scene.layout.*?>

    <AnchorPane id="AnchorPane" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.40" xmlns:fx="http://javafx.com/fxml/1">
       <children>
          <NumberTextField fx:id="testNumber" layoutX="226.0" layoutY="125.0" maxLength="4" restrict="&quot;[0-9]&quot;" />
       </children>
    </AnchorPane>

以下Java代码应该加载此FXML(它正确地执行并显示NumberTextField。但它允许任何长度的非数字字符。

    package anothertest;

    import java.io.IOException;
    import javafx.application.Application;
    import static javafx.application.ConditionalFeature.FXML;
    import javafx.event.ActionEvent;
    import javafx.event.EventHandler;
    import javafx.fxml.FXML;
    import javafx.fxml.FXMLLoader;
    import javafx.scene.Scene;
    import javafx.scene.control.Button;
    import javafx.scene.layout.AnchorPane;
    import javafx.scene.layout.StackPane;
    import javafx.stage.Stage;
    import numbertextfield.NumberTextField;

    /**
     *
     * @author Hornigold Arthur
     */
    public class AnotherTest extends Application {

        @FXML
        NumberTextField testNumber = new NumberTextField();

        @Override
        public void start(Stage mainStage) throws Exception {

            try {
                FXMLLoader loader = new FXMLLoader();
                loader.setLocation(AnotherTest.class.getResource("AnotherTest.fxml"));
                AnchorPane rootLayout = (AnchorPane) loader.load();
                testNumber.setMaxLength(4);
                testNumber.setRestrict("[0-9");

                // Show the scene containing the root layout.
                Scene scene = new Scene(rootLayout);
                mainStage.setScene(scene);
                mainStage.show();

            } catch (IOException e) {
                e.printStackTrace();
            }

        }

        /**
         * @param args the command line arguments
         */
        public static void main(String[] args) {
            launch(args);
        }

    }

但是下面的代码完全可以从Internet样本中获取。

package testnumberinput;

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.control.TextField;

/**
 *
 * @author Hornigold Arthur
 */
public class TestNumberInput extends Application {

    @Override
    public void start(Stage primaryStage) {
        RestrictiveTextField textInput = new RestrictiveTextField();
        textInput.setMaxLength(4);
        textInput.setRestrict("[0-9]");
        Label label1 = new Label("Enter a number  : ");
        textInput.setOnAction(new EventHandler<ActionEvent>() {

            @Override
            public void handle(ActionEvent event) {
                System.out.println("Hello World!");
            }
        });

        HBox hBox = new HBox();
        hBox.getChildren().addAll(label1, textInput);
        StackPane root = new StackPane();
        root.getChildren().add(hBox);

        Scene scene = new Scene(root, 300, 250);

        primaryStage.setTitle("This is a test ..... !");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        launch(args);
    }

}

/**
 *  * A text field, which restricts the user's input.  
 * <p>
 *  * The restriction can either be a maximal number of characters which the
 * user is allowed to input  * or a regular expression class, which contains
 * allowed characters.  * </p>
 *  
 * <p/>
 *  * <b>Sample, which restricts the input to maximal 10 numeric characters</b>:
 *  
 * <pre>
 *  * {@code
 *  * RestrictiveTextField textField = new RestrictiveTextField();
 *  * textField.setMaxLength(10);
 *  * textField.setRestrict("[0-9]");
 *  * }
 *  * </pre>  *  * @author Christian Schudt  
 */
class RestrictiveTextField extends TextField {

    private IntegerProperty maxLength = new SimpleIntegerProperty(this, "maxLength", -1);
    private StringProperty restrict = new SimpleStringProperty(this, "restrict");

    public RestrictiveTextField() {
        textProperty().addListener(new ChangeListener<String>() {
            private boolean ignore;

            @Override
            public void changed(ObservableValue<? extends String> observableValue, String s, String s1) {
                if (ignore || s1 == null) {
                    return;
                }
                if (maxLength.get() > -1 && s1.length() > maxLength.get()) {
                    ignore = true;
                    setText(s1.substring(0, maxLength.get()));
                    ignore = false;
                }

                if (restrict.get() != null && !restrict.get().equals("") && !s1.matches(restrict.get() + "*")) {
                    ignore = true;
                    setText(s);
                    ignore = false;
                }
            }
        });
    }

    /**
     *      * The max length property.      *      * @return The max length
     * property.      
     */
    public IntegerProperty maxLengthProperty() {
        return maxLength;
    }

    /**
     *      * Gets the max length of the text field.      *      * @return The
     * max length.      
     */
    public int getMaxLength() {
        return maxLength.get();
    }

    /**
     *      * Sets the max length of the text field.      *      * @param
     * maxLength The max length.
     */
    public void setMaxLength(int maxLength) {
        this.maxLength.set(maxLength);
    }

    /**
    *      * The restrict property.      
    *      * @return The restrict property.
    */

    public StringProperty restrictProperty() {
        return restrict;
    }

    /**
     *      * Gets a regular expression character class which restricts the user
     * input.        *      * @return The regular expression.      * @see
     * #getRestrict()
     
     */
    public String getRestrict() {
        return restrict.get();
    }

    /**
     *      * Sets a regular expression character class which restricts the user
     * input.        * E.g. [0-9] only allows numeric values.      *      
     *
     *
     * @param restrict The regular expression.      
     */
    public void setRestrict(String restrict) {
        this.restrict.set(restrict);
    }
    }

有人可以告诉我我在哪里弄错了吗?非常感谢。

我修改了整个过程并将它们放在一个单一的NETBEANS项目中以获得便利,看看它是否有效。告诉我,以下的部分是否正确。它仍然不起作用。现场“periodFrom”允许我输入所有内容。

这是fxml-1。 (EditedNumber.fxml)

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

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


<fx:root fx:id="numberField" promptText="Enter Number" type="TextField" xmlns="http://javafx.com/javafx/8.0.40" xmlns:fx="http://javafx.com/fxml/1" />

这是fxml-1的控制器。 (EditedNumber.java)

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package InputNumber;

import java.io.IOException;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.TextField;

/**
 *
 * @author Hornigold Arthur
 */
public class EditedNumber extends TextField{

/**
 *
 * @author Hornigold Arthur
 */
    private final IntegerProperty maxLength = new SimpleIntegerProperty(this, "maxLength", -1);
    private final StringProperty restrict = new SimpleStringProperty(this, "restrict");

    @FXML
    private TextField numberField;


    public void EditedNumber() {
        // TODO
        System.out.println(" Inside NumberTextField Controller");

        numberField = new TextField();

        numberField.textProperty().addListener(new ChangeListener<String>() {
            private boolean ignore;

            @Override
            public void changed(ObservableValue<? extends String> observableValue, String s, String s1) {

                if (ignore || s1 == null) {
                    return;
                }
                if (maxLength.get() > -1 && s1.length() > maxLength.get()) {
                    ignore = true;
                    numberField.setText(s1.substring(0, maxLength.get()));
                    ignore = false;
                }

                if (restrict.get() != null && !restrict.get().equals("") && !s1.matches(restrict.get() + "*")) {
                    ignore = true;
                    numberField.setText(s);
                    ignore = false;
                }
            }
        });
//
        FXMLLoader fxmlLoader = new FXMLLoader(
                getClass().getResource("Editor.fxml"));

        fxmlLoader.setRoot(this);
        fxmlLoader.setController(this);

        try {
            fxmlLoader.load();
        } catch (IOException exception) {
            throw new RuntimeException(exception);
        }
    }
//       
    /**
     *      * The max length property.      *      * @return The max le
     *
     * @return      
     */
    public IntegerProperty maxLengthProperty() {
        return maxLength;
    }

    /**
     *      * Gets the max length of the text field.      *      * @return The
     * max length.      
     *
     * @return
     */
    public int getMaxLength() {
        return maxLength.get();
    }

    /**
     *      * Sets the max length of the text field.      *      * @param
     * maxLength The max length.
     *
     * @param maxLength
     */
    public void setMaxLength(int maxLength) {
        this.maxLength.set(maxLength);
    }

    /**
     *      * The restrict property.      *      * @return The restrict
     * property.
     *
     * @return
     */
    public StringProperty restrictProperty() {
        return restrict;
    }

    /**
     *      * Gets a regular expression character class which restricts the user
     * input.        *      * @return The regular expression.      * @see
     * #getRestrict()      
     *
     * @return
     */
    public String getRestrict() {
        return restrict.get();
    }

    /**
     *      * Sets a regular expression character class which restricts the user
     * input.        * E.g. [0-9] only allows numeric values.      *      
     *
     *
     * @param restrict The regular expression.      
     */
    public void setRestrict(String restrict) {
        this.restrict.set(restrict);
    }

}

我的假设是 - 他们应该在一个新的UI类型的团队中工作。

这是fxml-2。它使用EditedNumber UI类型。 (mainFXML.fxml)

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

<?import javafx.scene.text.*?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import InputNumber.EditedNumber?>


<AnchorPane id="AnchorPane" prefHeight="400.0" prefWidth="600.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8.0.40">
   <children>
      <Label layoutX="128.0" layoutY="104.0" text="Period From : " textAlignment="RIGHT">
         <font>
            <Font name="Bookman Old Style" size="18.0" />
         </font>
      </Label>
      <EditedNumber fx:id="periodFrom" layoutX="255.0" layoutY="98.0" style="-fx-background-color: lightblue; -fx-border-color: red; -fx-border-width: 2;">
         <font>
            <Font name="Bookman Old Style" size="18.0" />
         </font>
      </EditedNumber>
   </children>
</AnchorPane>

这是控制器(或主程序)(InputNumber.java)

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package InputNumber;

import java.io.IOException;
import javafx.application.Application;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.AnchorPane;
import javafx.stage.Stage;

/**
 *
 * @author Hornigold Arthur
 */
public class InputNumber extends Application {

    @FXML
    EditedNumber periodFrom;

    @Override
    public void start(Stage mainStage) {
        periodFrom = new EditedNumber();
        periodFrom.setMaxLength(4);
        periodFrom.setRestrict("[0-9]");

        try {
            FXMLLoader loader = new FXMLLoader();
            loader.setLocation(InputNumber.class.getResource("mainFXML.fxml"));
            AnchorPane rootLayout = (AnchorPane) loader.load();

            Scene scene = new Scene(rootLayout);
            mainStage.setScene(scene);
            mainStage.show();


        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        launch(args);
    }

}

没有编译错误。如果这样可以正常工作,那么我可以将EDITED NUMBER类移动到Scene Builder并查看它是否正常工作。

提前感谢您的指导。

1 个答案:

答案 0 :(得分:0)

你这里有点乱......

让我们从您的Main类开始。 testNumber.setRestrict("[0-9"); 无法工作,您需要关闭括号:("[0-9]")

然后在您的NumberTextField FXML中 您定义fx:root id=AnchorPane,但在您的班级中,您会延长TextField。决定你想扩展哪一个!我建议扩展TextField,但是你的类中不需要额外的私有Field TextField,因为那样你就有两个TextField。

作为控制器,您编写了controller="numbertextfield.NumberTextField",但这不是特定的类名。在您的班级中,您再次定义控制器。你不能设置两次!请再次决定将这些行放在哪里。

对于TextField,您没有定义fx:id,但在您的班级中,您希望通过@FXML代码访问它。也不可能。

然后在NumberField类中,你有一个名为NumberTextFieldController的方法,它永远不会被调用。里面的代码必须在NumberTextField的构造函数中,而不是一个额外的方法。 然后,您必须首先加载FXML,然后才能访问TextField的textproperty。请使用FXMLLoader向上移动这些行。

请做一些清理,然后再试一次!

编辑:

仍有很多错误!也许你应该reed this文档。

EditedNumber类:我猜你实例化了numberField,因为你在下一行有一个NPE?删除该行并将fxmlLoader.load()向上移动到构造函数的第一行,这样就可以加载fxml文件,并且实例化该字段,但您甚至不需要字段numberField,因为您的类是TextField。删除它并更改呼叫,例如从numberField.textProperty()this.textProperty()

你仍然没有构造函数。删除void此处

public void EditedNumber() {...}

为什么要加载此资源?您说该名称为EditedNumber.fxml而不是Editor.fxml。您需要在第一个char中添加/才能找到fxml。

final FXMLLoader fxmlLoader = new FXMLLoader(this.getClass().getResource("Editor.fxml"));

做了所有这些改变,在我的例子中它起作用了!!