Last active
May 31, 2022 22:27
-
-
Save mmdemirbas/07f7cb0840d68ef00e75cd60e9b97ce1 to your computer and use it in GitHub Desktop.
JavaFX Multiple Dates Picker
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.mmdemirbas.lab; | |
/** | |
* Created by md on 5.04.2016. | |
*/ | |
import javafx.application.Application; | |
import javafx.application.Platform; | |
import javafx.collections.FXCollections; | |
import javafx.collections.ObservableList; | |
import javafx.embed.swing.JFXPanel; | |
import javafx.geometry.Bounds; | |
import javafx.scene.Scene; | |
import javafx.scene.control.*; | |
import javafx.scene.input.KeyCode; | |
import javafx.scene.layout.HBox; | |
import javafx.scene.layout.VBox; | |
import javafx.stage.Popup; | |
import javafx.stage.Stage; | |
import javafx.stage.Window; | |
import javafx.util.Callback; | |
import javafx.util.StringConverter; | |
import javax.swing.*; | |
import java.time.LocalDate; | |
import java.time.format.DateTimeFormatter; | |
public class MultiDatePicker extends Application { | |
public static void main(String[] args) { | |
// launch(args); | |
launchSwing(); | |
} | |
private static void launchSwing() { | |
SwingUtilities.invokeLater(() -> { | |
JFrame frame = new JFrame("Swing and JavaFX"); | |
final JFXPanel fxPanel = new JFXPanel(); | |
frame.add(fxPanel); | |
frame.setVisible(true); | |
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); | |
Platform.runLater(() -> fxPanel.setScene(createScene())); | |
}); | |
} | |
private static Scene createScene() { | |
Button addButton = new Button("+"); | |
Button removeButton = new Button("-"); | |
ObservableList<LocalDate> selectedDates = FXCollections.observableArrayList(); | |
ListView<LocalDate> dateList = new ListView<>(selectedDates); | |
String pattern = "yyyy-MM-dd"; | |
DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern(pattern); | |
DatePicker datePicker = new DatePicker(); | |
datePicker.setShowWeekNumbers(true); | |
datePicker.setOnAction(event -> System.out.println("Selected date: " + datePicker.getValue())); | |
datePicker.setPromptText(pattern); | |
datePicker.setConverter(new StringConverter<LocalDate>() { | |
@Override | |
public String toString(LocalDate date) { | |
return (date == null) ? "" : dateFormatter.format(date); | |
} | |
@Override | |
public LocalDate fromString(String string) { | |
return ((string == null) || string.isEmpty()) ? null : LocalDate.parse(string, dateFormatter); | |
} | |
}); | |
datePicker.setOnAction(event -> selectedDates.add(datePicker.getValue())); | |
datePicker.setDayCellFactory(new Callback<DatePicker, DateCell>() { | |
@Override | |
public DateCell call(DatePicker param) { | |
return new DateCell() { | |
@Override | |
public void updateItem(LocalDate item, boolean empty) { | |
super.updateItem(item, empty); | |
boolean alreadySelected = selectedDates.contains(item); | |
setDisable(alreadySelected); | |
setStyle(alreadySelected ? "-fx-background-color: #09a30f;" : ""); | |
} | |
}; | |
} | |
}); | |
// TODO: Hide text field of the date picker combo. Show dropdown directly on clicking "+" button. | |
// TODO: Keep dropdown of the date picker combo open until intentionally clicking some other where. | |
dateList.setOnKeyPressed(event -> { | |
if (event.getCode() == KeyCode.DELETE) { | |
removeSelectedDates(selectedDates, dateList); | |
} | |
}); | |
dateList.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE); | |
removeButton.disableProperty().bind(dateList.getSelectionModel().selectedItemProperty().isNull()); | |
addButton.setOnAction(event -> { | |
Popup popup = new Popup(); | |
popup.getContent().add(datePicker); | |
popup.setAutoHide(true); | |
Window window = addButton.getScene().getWindow(); | |
Bounds bounds = addButton.localToScene(addButton.getBoundsInLocal()); | |
double x = window.getX() + bounds.getMinX(); | |
double y = window.getY() + bounds.getMinY() + bounds.getHeight() + 5; | |
popup.show(addButton, x, y); | |
datePicker.show(); | |
}); | |
removeButton.setOnAction(event -> removeSelectedDates(selectedDates, dateList)); | |
HBox buttons = new HBox(addButton, removeButton); | |
return new Scene(new VBox(buttons, dateList)); | |
} | |
private static boolean removeSelectedDates(ObservableList<LocalDate> selectedDates, ListView<LocalDate> dateList) { | |
return selectedDates.removeAll(dateList.getSelectionModel().getSelectedItems()); | |
} | |
@Override | |
public void start(Stage primaryStage) { | |
primaryStage.setScene(createScene()); | |
primaryStage.show(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I was using JDK 8 when I wrote this piece of code. I can see from the output that you are using JDK 15. The error seems related to the Java module system which is introduced on JDK 9 as I remember. I'm afraid I don't know much about the module system. But I can say that your problem is unrelated to the
MultiDatePicker
code itself. I believe you can find some related material when you search for the error on the Internet. For example, I found the following quick results when I searched this phrase:IllegalAccessError: class javafx.embed.swing.JFXPanel (in unnamed module @0x676e7187) cannot access class com.sun.javafx.logging.PlatformLogger (in module javafx.base) because module javafx.base does not export com.sun.javafx.logging to unnamed module
I hope it helps.