Samstag, 21. Januar 2012

JavaFX Calendar Control

I've had much fun with JavaFX 2.0 recently and decided to develop a DatePicker / Calendar control, because it doesn't exist yet, and it would be a funny little project which would made me learn a lot about JavaFX.

So here it is (here are the sources):


The control consists of three views: A month view (which shows the current month), a year view (which shows the current year with its months) and a decades view (which shows two decades):


The behavior and navigation is similar to the JavaScript MooTools Calendar.

Features:
  • Localization
  • Easy navigation through months, years and decades.
  • CSS Styling
  • Disable certain week days or dates
  • Show/hide the "Today" Button
  • Show/hide the week numbers
  • Set custom date format (by default it is taken from the locale)
  • Set custom prompt text (by default it is taken from the date format pattern)
  • Auto-parsing the text field, when focus is lost and while typing (invalid input results in a red-bordered text field)
  • Cool animations :)
Usage:

You can just instantiate the Date Picker in a usual way and treat it as a normal control.

DatePicker datePicker = new DatePicker();

There are some properties directly on the date picker control, and some more on the calendar view. E.g. if you want to enable the today button, you have to do it on the calendar view:

datePicker.getCalendarView().setShowTodayButton(true);



Setting the locale:

You can either pass a locale in the constructor or you can use the locale property to change the locale later.

The locale is directly used to determine the calendar, e.g. whether the first day of the week is Sunday or Monday, or if the Gregorian calendar or the Buddhist calendar should be used. (Java only knows these two).


Setting the calendar:

If you want to use your custom calendar (must be derived from java.util.Calendar or treat language and calendar independently, you can do it by setting the calendar explicitly like:

datePicker.setLocale(Locale.GERMAN);
datePicker.getCalendarView().setCalendar(new BuddhistCalendar());


Which would look like:


How do I get the selected date?

Probably the most important part. There's are property selectedDate, which you can use. If the field is left without a valid date it becomes null otherwise it gives you the date.

Styling

The control uses only JavaFX css properties for styles. That means you can easily change the -fx-base to some other color and you get the following result:


Download

Kommentare:

  1. This is great! JavaFX needs a date picker and this satisfies that nicely.

    There is no license though, whats your thought on others using you work?

    AntwortenLöschen
  2. You can use or modify the code as you like.

    AntwortenLöschen
    Antworten
    1. Thank you for this nice work, Christian.

      I've made some little modifications and provide a jar on my blog. I hope this is ok.

      You can find it here: http://edu.makery.ch/blog/2013/01/07/javafx-date-picker/

      Löschen
  3. The link to the source code is not working is there another place where I can get it?

    AntwortenLöschen
  4. For me it works. Sorry, there is no other place.

    AntwortenLöschen
  5. Hi, I'm not sure that my comments are being posted, so I'll give it another shot.

    Is there a way to limit a range of selectable dates? For example, let user select only dates between 01 Jan 1970 and today? Thanks!

    AntwortenLöschen
  6. No sorry, I haven't implemented that. You can only disable certain week days or single dates. But feel free to implement that yourself.
    Add a min and max date property. Then modify the updateContent method in MonthView, DecadesView, YearView classes by setting the buttons disabled if the date is not in range. You get the currently displayed date from calendarView.getCalendar().getTime().

    AntwortenLöschen
    Antworten
    1. OK, I did this. Thanks for the instructions. Cheers! :)

      Löschen
  7. Hi Christian.

    Nice work Christian. I use your component to create DatePickerColumn. It is part of my work to create Table control designed for java POJO. The Java Web Start and the source code is available here http://panemu.com/articles/?p=73&lang=en

    AntwortenLöschen
  8. Hi Christian. This is really nice, but how can i integrate it in a fxml?

    AntwortenLöschen
  9. Hi.
    Your DatePicker doesn't work with Polish language. Unfortunately polish abbreviation of Sunday is just N. It cause Exception at MonthView.java:256.

    AntwortenLöschen
  10. Dieser Kommentar wurde vom Autor entfernt.

    AntwortenLöschen
  11. Good work! I would ask you how to add EventHandler to this datePicker, so when we choose date, they will call some functions.. Thank you!! Sorry for my bad english...:)

    AntwortenLöschen
    Antworten
    1. I already figured it out. With method addEventFilter(...). Thank you!

      Löschen
  12. Hello Christian.
    I am playing around with this control. Well done! And thanks for sharing it!! I changed it so i can use it in any other control and not as a popup. I could change it that the height is resizing according the parent-control-height but i didn't find out what s needed to also have resizing it in width... :-( Could you provide me with a little help. Thanks again. Regards, T.

    AntwortenLöschen
  13. Maybe to be more precise. Resizing is done with not using buttons anymore. I instead use a customcontrol which just extends HBox. This controls are rezising verticaly when i change the parent controlsize. But only verticaly rezising is done. Horizontaly the controls are resizing but just until a certain with. So my guess is that the stackpanes are somehow only growing to a certain with... but its just a guess and i am lost here. Thx, T.

    AntwortenLöschen
    Antworten
    1. I guess you have to use something like HBox.setHGrow(calendarControl, Priority.ALWAYS) in your new parent control to allow the child to grow in width.
      However, it is a general layout problem which is not related to my control.

      Löschen
    2. This looks excellent! Could you please tell me how to use these sources in an existing project? I am used to getting .jar files and simply adding them to my classpath.

      Löschen
    3. Well. Just add them to your own sources then. Or make a new project and compile them as *.jar and then add it. I use Maven for compiling them, but an IDE should work as well.

      Löschen
  14. Hello, i have a question. How exactly can i change the calendar to decade view? And is it posible to change the names of days? From (Mo, Tu, We...) to (Po, Ut, St)? Thanks in advance.

    AntwortenLöschen
    Antworten
    1. The calendar is changed to decade view by clicking the name in the top navigation bar. It works the same way as the Windows 7 calendar.
      The names of the days are set by Java directly. Just try to the Locale to yours.

      Löschen
  15. Hi Christian,
    I've memory leaks using your Calendar View. After some reloads of the view in which there is the widget I see that istances of buttons becames thousands!!!

    I see that you never remove listeners that you use.

    Can you give me some feedback?

    Thanks!

    AntwortenLöschen
    Antworten
    1. Thanks for your hint! I don't want to deny that ;-). This control was one of my first steps with JavaFX. Sorry for any mistakes. If my time permits, I will check the source. But I think it won't be necessary, as JavaFX 8 will contain its own DatePicker control.

      Löschen
    2. I've tested a few hours and analyzed it in VisualVM but I couldn't find any leaks (I created 10000 DatePickers).
      Either I have another source now, or you are mistaken.
      It's true, that I don't remove listeners, but as far as I understand there is no need to, because the objects have no further references.

      Löschen
  16. Hi Christian, just added the calendar to my project and I wanted to disable certain dates, can you tell me how its done ?Would really apreciate the help.

    Awesome work by the way.

    AntwortenLöschen
    Antworten
    1. Hi, in this version it's probably not implemented. You would have to do it in the MonthView class, where the buttons are updated.

      Löschen
  17. Can i use your calendar as based class for building my custom datepicker?

    Great job by the way.

    AntwortenLöschen
    Antworten
    1. Sure. Use and modify it as you like.

      Löschen
    2. Nice thanks, do you have any license agreement so that I can refer to?

      Löschen
  18. Hi Christian, good work,I'm still new to javafx and I want to recover the year, month and day I select, can you tell me how its done?

    AntwortenLöschen
    Antworten
    1. Not sure what you exactly mean. Year, month and day are all buttons. So you probably will just need to add a different style in the style class!?

      Löschen
  19. Hi. Any way I can change the today date. It's now getting current localsytem, but my application uses a specific clock supported by JodaTime. Any way I can assum today for a different date based on that DateTime from JodaTime ??

    Thanks.

    AntwortenLöschen
    Antworten
    1. Hi. Sorry, my original code ie really old and I don't have it anymore. Please refer to the new code on Bitbucket (see my latest post). However, there is no today button anymore, since I felt it would blow up the API too much and it wasn't really that useful.
      If you want to use the old code, it must be somewhere in the Skin implementation for the Calendar ("todayButton")

      Löschen
  20. Hi Christian, I use this component on Webstart application and it works, but when i deploy it to Web Application on Tomcat Server, its doesn't show anything, thanks for advance

    AntwortenLöschen
    Antworten
    1. Hi. Sorry, I have no experience with running JavaFX on the web. And without error message I really have no clue what might be wrong.

      Löschen
  21. Hi Christian, thank you very much for the time you spent on creating this useful control!

    AntwortenLöschen
  22. Thank you for this helpful DatePicker! I have a request and a question:
    1) Could you please also implement a method that returns java.util.Calendar? With java.util.Date, timezone problems are possible. E.g. you select November 26, but the DatePicker returns November 25 23:00.
    2) Please describe what kind of EventType should I pass to addEventHandler to intercept date selection event?

    AntwortenLöschen
    Antworten
    1. Hi Vadim,

      ad 1): There's already a getCalendar() method on the DatePicker class.
      ad 2): I haven't created an extra EventType for that. Just use the valueProperty(). It changes as soon as a date is selected.

      Löschen
  23. Hi Christian!

    Is there possibility to open calendar popup from some external button. I would like to add calendar icon at next to date textfield and popup should be opened also by pressing the icon. I didn't found method for that. Is that possible?

    AntwortenLöschen
    Antworten
    1. Hi,
      try calling the show() method on the DatePicker instance. Alternatively you could also write/derive a new skin, which adds the icon directly to your skin. There's a showPopup method in the DatePickerSkin, which is private, but which should be invoked by calling show().

      Löschen
  24. Hey Christian,
    Is there any way by which you can apply style to the TextField? For e.g - If user has input a wrong date, upon form submission, I need to change the background color of the text field to red.

    AntwortenLöschen
    Antworten
    1. Hi,
      Try the following:

      1.) add a second style class to your datepicker instance, e.g. "error".
      2.) add your own style sheet to the scene, which contains a style selector for your datepicker:
      .date-picker.error .text-field
      {
      -fx-background-color: red;
      }
      It basically means "select node which have class date-picker AND error, then select subnode, which have class text-field".
      3.) remove the style class again, when it is no longer needed.

      Haven't tested it though.

      Löschen
  25. Hi, Great component - thanks for the work. I have a question though... I don't see the selectedDate property anymore, and haven't figured out how to tell if the user has actually selected something. What am I missing?

    Thanks

    AntwortenLöschen
  26. OK, nevermind... I was trying to use the calendar property itself. Just using getValue() works as desired. Sorry!
    Thanks again for a great component.

    AntwortenLöschen
  27. Hi Christian, Great control !!! I am trying to use the DatePicker as custom cell factory in TableCell. I am not able to do a commitEdit() while trying to enter date manually instead of selecting from popup. Here is my implementation.

    datePicker.setOnKeyPressed(new EventHandler() {
    @Override
    public void handle(KeyEvent t) {
    if (t.getCode() == KeyCode.ENTER) {
    if(getItem() == null) {
    commitEdit(null);
    } else {
    commitEdit(datepicker.getValue());
    }
    } else if (t.getCode() == KeyCode.ESCAPE) {
    cancelEdit();
    }
    }
    });

    This works if i select a date from from the Calendar popup.

    AntwortenLöschen
  28. Dieser Kommentar wurde vom Autor entfernt.

    AntwortenLöschen
  29. amazing! i will be using this for in a project of mine for date selection.

    AntwortenLöschen
  30. Hi, Would you happen to have a time picker to go with this?

    AntwortenLöschen
  31. Hi Christian, I want to make some dates red as per my input. for eg, if I pass a date to function it should be reflected as red. Can you please guide how it can be done?

    AntwortenLöschen