Nice
widget
Tutorial Details:
Solve the date-selection problem once and for all
Solve the date-selection problem once and for all
By: By Allen Holub
Implement a date-selection widget using the Decorator pattern
ate selection is a problem that pops up every few months when you build client-side graphical user interfaces (GUIs). Unfortunately, Java doesn't provide anything like a DateChooser class, and the date-selection widgets I found in a recent Web search were too heavyweight for my purposes. I wanted something clean, unobtrusive, and flexible. Figure 1 shows a few variants of this article's class, so you can see what I mean by "clean" at the display level.
Figure 1. Various ways to present a Date_selector object
The free off-the-Web solutions were great examples of the you-get-what-you-pay-for principle: amateurish code that must be completely rewritten to be useful. This article's example, in fact, started out as an off-the-Web control, but by the time I finished fixing it, not a single line of the original code remained, and the architecture had completely changed (or, I should say, I added an architecture to an amorphous Java mass). So much for "free."
My widget also provides a good Decorator design pattern demonstration and a good look at Java's Calendar class, and it shows how to implement your own title bars and frames on a Swing JDialog .
Decorators
As is the case with any complex problem, the solution is greatly simplified by breaking the big problem up into smaller problems, each of which can be easily implemented (and tested). The Decorator pattern is great for this approach.
You've seen decorators if you've used Java's input/output (I/O) classes. The complex problem is efficiently reading a compressed stream of bytes, for example. You can do this with one massive class, but it's easier to break the problem up into three distinct subproblems:
Read bytes
Make reads more efficient with buffering
Decompress a stream of bytes
Java solves the first problem with a FileInputStream , instantiated like this:
try
{ InputStream in = new FileInputStream( "file.name" );
}
catch( IOException e )
{ System.err.println( "Couldn't open file.name" );
e.printStackTrace();
}
You then add buffering with a decoration (or "wrapping") strategy. You wrap the InputStream object with another InputStream implementor that buffers bytes. You ask the wrapper for a byte; it asks the wrapped stream for many bytes and returns the first one. The decorator wrapping goes like this:
try
{ InputStream in = new FileInputStream( "file.name" );
in = new BufferedInputStream( in );
}
catch( IOException e )
{ System.err.println( "Couldn't open file.name" );
e.printStackTrace();
}
Add decompression with another decorator:
try
{ InputStream in = new FileInputStream( "file.name" );
in = new BufferedInputStream( in );
in = new GZipInputStream( in );
}
catch( IOException e )
{ System.err.println( "Couldn't open file.name" );
e.printStackTrace();
}
You can increase filtering by adding more decorators.
This solution is very flexible. You can mix and max the decorators to get the feature mix you need. More importantly, each decorator is relatively simple because it solves only one problem. Consequently, the decorators are easy to write, debug, and modify without affecting the rest of the system. I can change the buffering algorithm by rewriting BufferedInputStream , for example, and not touch any other decorators (or any code that uses them). I can also add new filter functionality simply by implementing a new decorator. (Classes like CipherInputStream were added to Java this way.)
Date selection from the center out
I apply the Decorator principle to the date-selection problem. The core problem is displaying a calendar for a single month, so I start by implementing a class that does only that. Figure 2 shows the Date_selector_panel user interface. It's just a calendar, but it's easy to create because I don't have to clutter the code with unnecessary details. "Today" is highlighted. Select a date by clicking on it. ( ActionListener objects registered with the widget are notified when you select a date.) The background is transparent by default?it appears gray here because the underlying window is gray.
Figure 2. A raw Date_selector_panel, created with the no-arg constructor
This raw date selector can be "decorated" in several ways to make it more useful. First, you can add a navigation bar to the bottom (shown in Figure 3) to move the calendar one month (single arrow) or one year (double arrow) forward (right-pointing arrow) or backward (left-pointing arrow).
Figure 3. Add navigability
You can add navigation bars with a decorator object that wraps the raw Date_selector_panel . Both the wrapper and the underlying panel implement the Date_selector interface, so you can use them interchangeably. The following code creates the decorated date selector in Figure 3:
Date_selector selector = new Date_selector_panel();
selector = new Navigable_date_selector( selector );
The same effect is accomplished with a convenience constructor that creates the wrapped Date_selector_panel for you:
Date_selector selector = new Navigable_date_selector();
The other augmentation I've supported is a title that shows the month name and year that displays on the calendar (see Figure 4).
Figure 4. Add a title
I use the same decoration strategy as before to add the title:
Date_selector selector = new Date_selector_panel();
selector = new Navigable_date_selector( selector );
selector = new Titled_date_selector ( selector );
Leave out the navigation bar by omitting the second line in the above code. It doesn't matter which order you mix in the title and navigation bars if you need both. Again, a convenience constructor creates a titled date selector (without the navigation bar) as follows:
Date_selector selector = new Titled_date_selector();
The final variant is Figure 5's lightweight pop-up dialog. It can be dragged by the title bar (though dragging can be disabled) and closed by clicking on the close icon in the upper right corner.
Figure 5. A date-selection dialog
As before, use a decorator to manufacture a dialog:
Date_selector selector = new Date_selector_panel();
selector = new Navigable_date_selector( selector ); // Add navigation
Date_selector_dialog popup = new Date_selector_dialog( selector );
//...
Date = popup.select(); // Returns the user-selected date, or null if the
// dialog was closed without selecting anything.
// Or you can do this:
popup.setVisible( true ); // Pop it up. Block until dismissal.
Date = popup.get_selected_date(); // Get the selected date.
Note that you don't need to mix in a title here because you use the dialog-box title bar for that purpose. As before, the Date_selector_dialog defines a convenience constructor to create a navigable dialog box like the one in Figure 5:
Date_selector = new Date_selector_dialog();
All the earlier examples create a calendar for the current month. Several methods can programmatically change the date. For the most part, they work like the java.util.Calendar class's similar methods.
Implement Date_selector
I implement the core Date_selector_panel as an interface to make the Decorator pattern viable. (In the I/O example, all the decorators are InputStream objects, so they can be treated interchangeably. The constructor arguments to all the decorators are all InputStream references. You can wrap any decorator with another decorator without the latter knowing what it's wrapping.)
The core interface looks like this (I left out the Javadoc and other extraneous code in the interest of clarity. See Resources for the complete code):
public interface Date_selector
{
public static final int CHANGE_ACTION = 0;
public static final int SELECT_ACTION = 1;
public void addActionListener(ActionListener l);
public void removeActionListener(ActionListener l);
public Date get_selected_date();
public Date get_current_date();
/** Must work just like {@link Calendar#roll(int,boolean)} */
public void roll(int flag, boolean up);
/** Must work just like {@link Calendar#get(int)} */
public int get(int flag);
}
The interface defines two constant values, CHANGE_ACTION and SELECT_ACTION , used in event processing (more in a moment). The interface provides ways to add and remove ActionListener objects that are notified when a date is selected. Finally, it provides an interface that mimics the java.util.Calendar() methods to advance the calendar by some increment (a month, typically) and get an attribute's value (such as the month or year).
Let's return to the action listeners: add listeners to your date selector in the same way you add a listener to a button:
Date_selector selector = new Date_selector_panel();
selector.addActionListener
( new ActionListener()
{ public void actionPerformed( ActionEvent e )
{ // Do whatever you'd do to process an event
}
}
);
The listener strategy is a realization of the Observer design pattern.
Listeners are notified ( actionPerformed(...) is called) in two situations, which can be distinguished from one another by sending the ActionEvent object passed to actionPerformed a getID() message. The table below lists the details.
Action events
getID() returns
Description
CHANGE_ACTION
This event is sent when the calendar panel changes the displayed month or year (typically because some sort of navigator bar asked it to). Call event.getActionCommand getActionCommand() to get a string holding the current (after the scroll) month and year. You can also call get_current_date() to get the date the user selected.
SELECT_ACTION
Sent every time the user clicks on a date. Call event.getActionCommand getActionCommand() to get a string representing the selected date. (This string takes the same form as the one returned by toString .) You can also call get_selected_date() to get the date the user selected.
The following code demonstrates the two event types
Read
Tutorial at: Click here to view the tutorial
Rate Tutorial: Nice
widget
View Tutorial: Nice
widget
Related
Tutorials:
Use JNDI to
share objects between different virtual machines - JavaWorld July
1999
Use JNDI to
share objects between different virtual machines - JavaWorld July
1999 |
Embed Java code into your
native apps -
JavaWorld May 2001
Embed Java code into your
native apps -
JavaWorld May 2001 |
Will Big Blue
eclipse the Java
tools market?
Will Big Blue
eclipse the Java
tools market? |
Eclipse casts shadows
Eclipse casts shadows |
Got
resources?
Got
resources? |
TimCam
TimCam is an easy-to-use webcam program written in (pure) Java. It was designed to mimic such fantastic projects as ConquerCam, but with an added bonus: TimCam is in the public domain. |
Nice
widget
Nice
widget |
Very
interesting
Very
interesting |
Writing Ant Tasks
Writing Ant Tasks
A nice feature of Ant is that it is designed to allow you to add your own tasks and use them in an build. This article shows you the basics of writing an Ant task and how to get a task to work. |
Java 2D imaging for the Standard Widget Toolkit
Java 2D imaging for the Standard Widget Toolkit
Bring the power of 2D imaging to your Eclipse plug-ins
In this article, however, you'll learn how to have the best of both worlds. I'll demonstrate a simple technique that will allow you to paint Java |
Wi.Ser (WidgetServer) unified rich client framework
Wi.Ser is a Java/XML server-side GUI-framework which enables an application to run as either a monolithic Swing application, a thin-client/server Swing application, or as a Web application without any change!
|
Develop Your Own Plugins for Eclipse, Part 1
This article series is intended provide you the basic information necessary to quickly code your first plugin. The resources section will point to all of the necessary introductory materials. |
When tears bring you back your beloved method...
Accessing platform-specific information hasn't always been easy. While you could certainly create processes with Runtime.exec(), dealing with differences across platforms to build parameter sets often led to headaches. In addition, the getenv() method of |
Use SWT Listener Classes Effectively for Responsive Java UIs
Use SWT Listener Classes Effectively for Responsive Java UIs
Understanding the SWT listener classes and their usage is essential to building complex, highly responsive user interfaces for Java applications. The listener classes in SWT are classified into |
Professional Java Server Programming.
An overview of the new server-side Java platform - Java 2 Enterprise Edition - as it relates to building n-tier web applications. |
Java Resources
There are all Java freebies. Some of these are old, and not under maintenance. Download and use them at your risk. In case of queries, mail subrahmanyam_avb@technologist.com or varalakshmi_a@techie.com. |
Web Hosting Guide. What is Web Hosting Plan?
Web Hosting Guide. What is Web Hosting Plan?
What is Web Hosting Plan?
Web hosting plan is the different plans provided by Hosting Companies for hosting your web site. Web hosting plans include the storage limit, bandwidth, access to server |
Sanssouci is a Java framework for autogenerating fancy Swing-GUIs via introspection.
Sanssouci is a Java framework for autogenerating fancy Swing-GUIs via introspection which display objects directly to the user |
one-jar
One-JAR is a simple solution to a vexing problem in Java: how to distribute an application as a single jar-file, when it depends on multiple other jar-files. One-JAR uses a custom classloader to discover library jar files inside the main jar. |
A Practical Roadmap for Deploying Enterprise Web Applications: Taking the First Step
This article covers important decision points around the availability, scalability, and security that are needed for enterprise web applications. |
|
|
|