如何创建自定义节点 class?

How to create a custom Node class?

我是 java 和 javafx 的新手。我尝试创建一个自定义 class 来显示时间选择器,但它不会在视觉上呈现节点。

下面的问题是什么class?

package customcombobox;

import javafx.event.EventHandler;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.control.Spinner;
import javafx.scene.control.TextField;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;

public class TLTimePicker extends GridPane{
private int hr = 1;
private int min;
private int sec;
private String meas = "AM";
private String value = hr+":"+ min +":"+ sec +" "+meas;    
private final VBox timePicker = new VBox(5);       

public TLTimePicker(){
    this.render();
}

public TLTimePicker(int hour, int minute, int second, String measure){
    this.hr = hour;
    this.min = minute;
    this.sec = second;
    this.meas = measure;
    this.value = hr+":"+ min +":"+ sec +" "+meas;  
    this.render();
}

public GridPane render(){
    HBox contnr = new HBox();
    TextField txtfld = new TextField();
    txtfld.setEditable(false);
    Button open = new Button();
    contnr.getChildren().addAll(txtfld, open);
    ImageView arrow = new ImageView(new Image(getClass().getResourceAsStream("down.png")));
    open.setGraphic(arrow);        
    arrow.setFitWidth(12);
    arrow.setFitHeight(12);
    Label hrLbl = new Label("Hour");
    Spinner hour = new Spinner(1, 13, 1);
    Label mntLbl = new Label("minute");
    Spinner minute = new Spinner(0, 61, 0);
    Label scnLbl = new Label("second");
    Spinner second = new Spinner(0, 61, 0);
    ComboBox<String> ampm = new ComboBox<String>();
    ampm.getItems().addAll("AM", "PM");
    ampm.getSelectionModel().selectFirst();

    hour.setPrefWidth(52);
    minute.setPrefWidth(52);
    second.setPrefWidth(52);
    ampm.setPrefWidth(64);
    hour.setEditable(true);
    minute.setEditable(true);
    second.setEditable(true);    

    txtfld.setText(value);

    hour.valueProperty().addListener((ob, ov, nv) -> {
        hr = (int)nv;
        if(ov.equals(12)) {
            hour.getValueFactory().setValue(1);
            hr = 1;
        }          
        String value = hr+":"+ min +":"+ sec +" "+meas;
        txtfld.setText(value);
    });

    minute.valueProperty().addListener((ob, ov, nv) -> {
        min = (int)nv;
        if(ov.equals(60)) {
            minute.getValueFactory().setValue(0);
            min = 0;
        }

        String value = hr+":"+ min +":"+ sec +" "+meas;
        txtfld.setText(value);
    });

    second.valueProperty().addListener((ob, ov, nv) -> {
        sec = (int)nv;
        if(ov.equals(60)) {
            second.getValueFactory().setValue(0);
            sec = 0;
        }
        String value = hr+":"+ min +":"+ sec +" "+meas;
        txtfld.setText(value);
    });        

    ampm.setOnAction((event) -> {
        meas = ampm.getValue();
        String value = hr+":"+ min +":"+ sec +" "+meas;
        txtfld.setText(value);
    });       

    GridPane grid = new GridPane();
    grid.add(hrLbl, 0, 0);
    grid.add(hour, 1, 0);
    grid.add(mntLbl, 0, 1);
    grid.add(minute, 1, 1);
    grid.add(scnLbl, 0, 2);
    grid.add(second, 1, 2);
    grid.setHgap(5);
    grid.setVgap(5);        

    timePicker.getChildren().addAll(grid, ampm);
    timePicker.setStyle("-fx-background-color:"
            + "#ededed; -fx-border-color: "
            + "#dddddd; -fx-border-size:1;"
            + "-fx-padding:5 25;");
    hidetimePicker();        
    arrow.setRotate(0);

    EventHandler showHide = (event) -> {
        Object[] obj = {hour, minute, second};
        String[] arr = txtfld.getText().split("[\s:]+");
        for(int i=0; i<arr.length;i++ ){
            if(arr[i].matches("^(\d+)$")) {
                ((Spinner)obj[i]).getValueFactory().setValue(Integer.parseInt(arr[i]));
            } else {
                ampm.setValue(arr[i].toUpperCase());
            }
        }       
        if(timePicker.visibleProperty().getValue()) {
            hidetimePicker();
            arrow.setRotate(0);
        } else {
            timePicker.setVisible(true);
            timePicker.setManaged(true);
            arrow.setRotate(180);
        }
    };

    open.setOnAction(showHide);        
    txtfld.setOnMousePressed(showHide);

    GridPane group = new GridPane();
    group.add(contnr, 0, 0);
    group.add(timePicker, 0, 1);
    timePicker.toFront();

    Scene scene = group.getScene();
//        scene.setOnMousePressed((event) -> {
//            hidetimePicker();
//            arrow.setRotate(0);
//        }); 



    return group;
}  

private void hidetimePicker(){
    timePicker.setVisible(false);
    timePicker.setManaged(false);        
}    

}

调用它 用这个调用后显示空白window。

package customcombobox;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;

public class demo extends Application {

    @Override
    public void start(final Stage primaryStage) {
        TLTimePicker timer = new TLTimePicker(5,27,0,"PM");
        HBox box = new HBox();
        box.getChildren().add(timer);
        Scene scene = new Scene(box, 350, 250);

        primaryStage.setScene(scene);
        primaryStage.setTitle("TimePicker");
        primaryStage.show();
    }

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

稍微改变一下您的 render()。 首先,使方法 void:

public void render() {
    // most part of your code just stays as it is
    ...

其次,更改最后几行(注释掉的是你的行,其余行使其有效):

    ...
    // GridPane group = new GridPane(); ---> you don't need a new one
    // group.add(contnr, 0, 0);
    // group.add(timePicker, 0, 1);
    this.add(contnr, 0, 0);
    this.add(timePicker, 0, 1);
    timePicker.toFront();

    // Scene scene = group.getScene();
    // scene.setOnMousePressed((event) -> {
    // hidetimePicker();
    // arrow.setRotate(0);
    // });

    // return group;
}

您也可以在 demo 中调用 GridPane timer = new TLTimePicker(5,27,0,"PM").render() 而不是 TLTimePicker timer = new TLTimePicker(5,27,0,"PM") 并且不更改任何其他内容以使其工作,这将使扩展 GridPane 以某种方式过时......