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(); | |
} | |
} |
mmdemirbas
commented
Apr 5, 2016
This looks ideal for my JavaFX app. I changed the package and the class names. Unfortunately when I tried to use it, I hit a problem with JFXPanel.
Please can you help?
"C:\Program Files\Java\jdk-15.0.2\bin\java.exe" --module-path "C:\Program Files\Java\javafx-sdk-16\lib" --add-modules javafx.controls,javafx.fxml --add-exports javafx.graphics/com.sun.javafx.sg.prism=ALL-UNNAMED "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2020.3.2\lib\idea_rt.jar=50564:C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2020.3.2\bin" -Dfile.encoding=UTF-8 -classpath "C:\Users\Ted\IdeaProjects\PerfectWindows\out\production\Fixtures;C:\Program Files\Java\javafx-sdk-16\lib\src.zip;C:\Program Files\Java\javafx-sdk-16\lib\javafx-swt.jar;C:\Program Files\Java\javafx-sdk-16\lib\javafx.web.jar;C:\Program Files\Java\javafx-sdk-16\lib\javafx.base.jar;C:\Program Files\Java\javafx-sdk-16\lib\javafx.fxml.jar;C:\Program Files\Java\javafx-sdk-16\lib\javafx.media.jar;C:\Program Files\Java\javafx-sdk-16\lib\javafx.swing.jar;C:\Program Files\Java\javafx-sdk-16\lib\javafx.controls.jar;C:\Program Files\Java\javafx-sdk-16\lib\javafx.graphics.jar" fixturesPkg.Main
Exception in thread "AWT-EventQueue-0" java.lang.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 @0x676e7187
at javafx.embed.swing.JFXPanel.(JFXPanel.java:136)
at fixturesPkg.Main.lambda$launchSwing$1(Main.java:38)
at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:316)
at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:770)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:715)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:391)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:740)
at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
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