1

I'm using JFXtras CalendarPicker to get dates for multiple days in the calendar. My project is a JavaFX project and I'm using an FXML, in that the CalendarPicker is linked to my Controller class. In details, this is my FXML:

<CalendarPicker fx:id="calendarpicker" mode="MULTIPLE" />

In my controller class, I'm using a EventHandler inside the initialize() method:

public void initialize() {

        this.dateFormat = new SimpleDateFormat("yyyy-mm-dd");
        calendarpicker.addEventFilter(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent event) {

                if (event.getButton().equals(MouseButton.PRIMARY)) {

                    Calendar cal = calendarpicker.getCalendar();
                    if(cal != null){
                        String formattedDate = dateFormat.format(cal.getTime());
                        ObservableList<String> items = listview.getItems();
                        if (!items.contains(formattedDate)) {
                            items.add(formattedDate);

                        } else {
                            items.remove(formattedDate);
                        }
                        listview.setItems(items);
                    }
                }
            }
        });
}

So in JFXtras the CalendarPicker dates inside the calendar looks like buttons, on one click (you press down the button), but when you release it it doesn't come up. If you click again on the pressed down button it will come up. I have a ListView (named as "listview") what I want to populate with the dates when I click on the calendar day it should add the date to the list. If the date is NOT on the list I want to add it. If it is already on the list (so the button is already pressed down), and I click on it again, it should remove that date from the list.

The problem is that my code doesn't behave as expected, probably because this two stage action (pressing down and pressing again to come up). I have no clue how to fix it, so I kindly ask for help.

Thend
  • 95
  • 7
  • Why don't you just use a `ListView` and set the items to `calendarPicker.getCalendars()`? Then it should just automatically update, instead of writing all this code to reinvent the wheel. – James_D Mar 27 '23 at 19:07
  • @James_D Unfortunately, that doesn't work. When I un-press an actual day in the calendar it doesnt remove the Calendar from the listview. May I kindly ask you to try it? – Thend Mar 27 '23 at 19:19
  • Works fine for me. Maybe I misunderstood what you're trying to do. – James_D Mar 27 '23 at 19:29
  • @James_D works perfectly, I overcomplicated it unfortunately. Appreciate the help! Thx! :) – Thend Mar 27 '23 at 19:34

1 Answers1

4

There is no need to implement all this yourself. The calendarPicker exposes an ObservableList<Calendar> representing all the selected Calendar instances. Simply use this list as the backing list for your ListView:

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import jfxtras.scene.control.CalendarPicker;

import java.io.IOException;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.util.Calendar;

public class HelloApplication extends Application {
    @Override
    public void start(Stage stage) throws IOException {
        CalendarPicker calendarPicker = new CalendarPicker();
        calendarPicker.setMode(CalendarPicker.Mode.MULTIPLE);
        ListView<Calendar> dates = new ListView<>();
        dates.setItems(calendarPicker.calendars());
        dates.setCellFactory(lv -> new ListCell<>(){
            private DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM);
            @Override
            protected void updateItem(Calendar item, boolean empty) {
                super.updateItem(item, empty);
                if (empty || item == null) {
                    setText("");
                } else {
                    setText(formatter.format(LocalDate.ofInstant(item.toInstant(), ZoneId.systemDefault())));
                }
            }
        });
        BorderPane root = new BorderPane(dates);
        root.setTop(calendarPicker);
        Scene scene = new Scene(root);
        stage.setScene(scene);
        stage.show();
    }

    public static void main(String[] args) {
        launch();
    }
}
James_D
  • 201,275
  • 16
  • 291
  • 322
  • Thanks for answering the question, James! Always interesting to see what complex solutions people come up with, when in fact I tried to make usage as easy as possible. – tbeernot Mar 27 '23 at 20:16