Java Project - CalendarComboBox




CalendarComboBox.java


As a Notes developer, I've gotten used to having a date input box with a perpetual calendar. I thought it would be nice to have one for my Java projects. It turned out to be less difficult to create than I'd originally imagined.

The one truly nice thing about Java is the richness of it's API. I was able to create the CalendarComboBox by simply arranging a number of existing components: JFormattedTextField, BasicArrowButton, JTable, and Popup. Of course, code always looks simple once it's finished. Originally I didn't know the BasicArrowButton and Popup classes even existed. It took some poking around in the API and Java source code related to JComboBox before I tracked them down.

I also needed to figure out how to build an array to hold the days in a month and leverage the various date related classes: Calendar, GregorianCalendar, DateFormat, and DateFormatSymbols. Mr. Dunn's book, Java Rules was particularly useful in helping me understand how these classes worked.

And last, but not least, were the layout experiments. I got stuck for a few hours on the calendar display; the buttons in the navigation panel kept changing size, it was very distracting. Finally realized that part of the problem was the JLabel component I was using to display the month and year name and the fact that I was using a BoxLayout. Once I changed the label to a JTextField and the calendar panel layout to BorderLayout, with the navigation portion placed in BorderLayout.NORTH and the table in BorderLayout.CENTER the display started to behave itself.

I ran across a few other snags, they are hightlighted in the code comments. Below are my reasons for designing the class as I did.

Design Decisions

  • Class fields

    The values represented by these fields are common to the system the class is running on. The data is based on the system Locale which is not likely to change; at least, not during the active life of a running application.

  • Field access modifiers

    All fields (except popup ) are declared private and final. This is good coding practice.

    The private keyword helps to enforce encapsulation and forces you to think about your classes public interface. In this case, only one field, current needed to be publicly exposed; a gettor method, public Calendar getDate() was provided to return current as it's reasonable to assume an external class would need access to the currently selected date.

    The keyword final emphasizes that the fields are required and that references cannot be accidently modifed during the life of an object. It also notifies the compiler that the code relating to these values can be safely optimized. Another advantage is that it helps ensure that everything the object requires to work correctly will be available once it is created; if you fail to initialize a final variable during object creation the compiler complains.

  • Why popup isn't final

    The API recommends using PopupFactory to create Popup objects. PopupFactory caches popup objects, managing their reuse and disposal. As the programmer's at Sun have been kind enough to supply me with a class that can manage popup's it seemed sensible to use it rather than create a final popup reference and attempt to manage it myself.

  • Listeners as inner classes

    There are three basic ways to implement listeners: as external classes, as inner classes or as anonymous classes. The only reason to implement one as an external class is if it could possibly be used by another class; yet listeners are generally very specific in nature and certainly are specific in this case so there was nothing to be gained by implementing them as external classes.

    Anonymous listener classes are generally used if they are required by only one element in the class and if they can be written in nine or ten lines of code. When I started writing the class I had no idea how long a particular listeners code would be and I did know that one listener, ButtonListener, would be required by three elements, not one. So again, there was little to be gained by implementing the listeners as anonymous classes. Add to that the difficulty of maintaining code that is peppered with anonymous classes and the choice of using inner classes became even more attractive.

  • The registerListeners() method

    For the most part, this is simply a personal preference. I find it easier to keep track of listeners when they are all located in one spot. Having a separate method to handle them just makes life easier for me.

Summary

If you've avoided creating custom components, thinking they're to much trouble or that you need to be an expert programmer to create them, here's the proof that it just ain't so! They can be alot easier to create than you realize.

If you end up using the class in one of your applications please let me know how it fares<g>

Enhancements

David Underhill used the code in a class project, adding some nice features:

  • added a constructor which allows the user to specify their own date format if they prefer
  • added the option for the user to have the popup collapse automatically when the user selects a date (however, it is smart enough to not collapse when the user is just browsing months)
  • added the ability for the class to track listeners and notify them when a change is made to the selection. This listener could be expanded further to listen for more specific of events, but this makes it easy to do that
  • made the input field uneditable. This is just the preference for our project, but it seems to make sense that if you have the box normally you would prefer the user to not manually enter the date.

David has kindly offered to share his code.

CalendarComboBox.java
CalendarComboBoxListener.java

Home | Projects