luckyguy73
luckyguy73

Reputation: 1939

How do I initialize the DatePicker in a Java FXML app?

When clicking the Add Appointment button the new form pops up, but the DatePicker is blank (should have LocalDate.now() populated), and none of the Saturday/Sunday dates are disabled. Tried calling the setup method in both Initialize and the method launching the new scene. Whether I put it in one or the other or both it never works. Please advise what I am doing wrong. Thank you.

Image showing DatePicker value blank and no disabled dates in Calendar. enter image description here

package gci.controllers.dialogs;

import gci.App;
import gci.models.Appointment;
import gci.utilities.CustomerDAO;
import java.io.IOException;
import java.net.URL;
import java.sql.SQLException;
import java.time.*;
import java.util.*;
import java.util.logging.*;
import java.util.stream.*;
import javafx.collections.*;
import javafx.event.ActionEvent;
import javafx.fxml.*;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.stage.*;
import javafx.util.*;

public class AddAppointmentController implements Initializable {

    @FXML private ChoiceBox<String> nameChoiceBox;
    @FXML private ChoiceBox<String> typeChoiceBox;
    @FXML private ChoiceBox<String> timeChoiceBox;
    @FXML private Label titleLabel;
    @FXML private Label copyrightLabel;
    @FXML private Button saveButton;
    @FXML private Button cancelButton;
    @FXML private DatePicker datePicker;

    private final CustomerDAO dao = new CustomerDAO();
    private Stage stage;
    private static final Region modal = new Region();

    @Override
    public void initialize(URL url, ResourceBundle rb) {
        initApptChoiceBoxes();
        setDatePicker();
        setCopyright();
        modal.setStyle("-fx-background-color: #00000099;");
    }

    private void initApptChoiceBoxes() {
        try {
            nameChoiceBox.setItems(dao.retrieveAll().stream().map(m -> m.getName())
                .collect(Collectors.toCollection(FXCollections::observableArrayList)));
        } catch (SQLException ex) {
            Logger.getLogger(AddAppointmentController.class.getName()).log(Level.SEVERE, null, ex);
        }

        typeChoiceBox.setItems(FXCollections.observableArrayList("In-Person", "Phone", "WebMeeting"));
    }

    public void loadAddModifyAppointmentScene(Stage stage, Appointment appt) throws IOException {
        Stage addAppointmentForm = new Stage();
        FXMLLoader loader = new FXMLLoader();
        loader.setLocation(App.class.getResource("views/dialogs/add_appointment.fxml"));
        Parent root = loader.load();
        Parent parent = stage.getScene().getRoot();
        StackPane stack = new StackPane(parent, modal);
        modal.setVisible(true);
        stage.setScene(new Scene(stack));
        addAppointmentForm.setScene(new Scene(root));
        addAppointmentForm.initModality(Modality.WINDOW_MODAL);
        addAppointmentForm.initOwner(stage);
        addAppointmentForm.initStyle(StageStyle.UNDECORATED);
        AddAppointmentController controller = loader.getController();
        controller.setStage(addAppointmentForm);
        controller.setAppointment(appt);
        controller.setDatePicker();
        addAppointmentForm.show();
        addAppointmentForm.centerOnScreen();
    }

    private void setStage(Stage stage) {
        this.stage = stage;
    }

    private void setAppointment(Appointment appt) {
    }

    @FXML
    private void handleCancelButton(ActionEvent event) {
        this.stage.close();
        modalOff();
    }

    @FXML
    private void handleSaveButton(ActionEvent event) {

    }

    private void setCopyright() {
        int year = LocalDate.now().getYear();
        copyrightLabel.setText("Copyright © " + year + " Global Consulting Institution");
    }

    public void modalOff() {
        modal.setVisible(false);
    }

    private void setDatePicker() {
        datePicker = new DatePicker(LocalDate.now());
        StringConverter<LocalDate> converter = datePicker.getConverter();
        datePicker.setConverter(new StringConverter<LocalDate>() {
            @Override
            public String toString(LocalDate object) {
                return converter.toString(object);
            }

            @Override
            public LocalDate fromString(String string) {
                LocalDate date = converter.fromString(string);
                if (date.getDayOfWeek() == DayOfWeek.SATURDAY
                    || date.getDayOfWeek() == DayOfWeek.SUNDAY) {
                    return datePicker.getValue();
                } else {
                    return date;
                }
            }
        });

        datePicker.setDayCellFactory(d -> new DateCell() {
            @Override
            public void updateItem(LocalDate date, boolean empty) {
                super.updateItem(date, empty);
                setDisable(empty || date.getDayOfWeek() == DayOfWeek.SATURDAY
                    || date.getDayOfWeek() == DayOfWeek.SUNDAY);
            }
        });

        datePicker.valueProperty().addListener((obs, ov, nv) -> {
            if (nv.getDayOfWeek() == DayOfWeek.SATURDAY || nv.getDayOfWeek() == DayOfWeek.SUNDAY) {
                Alert alert = new Alert(Alert.AlertType.WARNING);
                alert.setTitle("Select Appointment");
                alert.setHeaderText(null);
                alert.setContentText("Business Hours are Mon - Fri, 8am - 5pm");
                alert.showAndWait();
            }
        });
    }

}

Upvotes: 1

Views: 1663

Answers (1)

fabian
fabian

Reputation: 82461

The DatePicker instance you create in setDatePicker() is never added to the scene. It overwrites the DatePicker object injected by FXMLLoader when loading the fxml (unless you didn't properly add the fx:id). All other modifications done in this method are done on this instance too.

You need to replace the line

datePicker = new DatePicker(LocalDate.now());

with

datePicker.setValue(LocalDate.now());

In general you shouldn't assing values to @FXML annotated fields. If this is needed to "fix" a NullPointerException or something similar, you just fix the symptoms instead of fixing the actual issue. There may be exceptions to this rule, but you need to be aware of the fact that you need to make sure that the node is added to the scene yourself.

Upvotes: 2

Related Questions