Swing Worldclock

Februar 18th, 2010 by Gerrit Diesen Artikel diskutieren »

During my trip to JFokus conference last month i was waiting for the train on a german trainstation.
Because i started working on a little swing tool (i will blog about it later) for our usergroup i was in the need for a analog clock.
So the german railway company „Deutsche Bahn“ has a famous analog clock on nearly every german trainstation which looks like this:

DB_Clock.jpg

I thought this would be a nice clock to adopt in Swing and started coding. To my surprise that was an easy job and did not took much time to complete. I started with a dark version of this clock because my usergroup swing component was designed in a dark color scheme.

Some days later i remembered that on the iPhone there’s a worldclock application which also contains analog clocks.
Because the clock was finished already i thought i could not be too hard to implement this kind of worldclock in Java.
So i started this little worldclock project i would like to tell you about here.

Step #1
Creating two versions of the analog clock component.

ishot-3.png

The nice thing in NetBeans (and also other gui editors) is that once you generated a swing component you could easily drag’n drop the component to a JPanel or JFrame etc. like on the following movie (quicktime mov format).

NetBeans_Swing.mov

So you will be able to easily create new components by drag stuff together.

Step #2

Creating a JPanel which contains the clock and the name of the related city. So we need a class that contains cities with their international timezones. Here is a small fraction of my class.

public enum City
{
    // -12
    Wellington("Wellington", -43200000),
    Fidschi("Fidschi", -43200000),
    Kamtschatka("Kamtschatka", -43200000),
    // -11
    Magadan("Magadan", -39600000),
    Sachalin("Sachalin", -39600000),
    Salomoninseln("Salmoninseln", -39600000),
    Malekula("Malekula", -39600000),
    // -10
    Wladiwostok("Wladiwostok", -36000000),
    Guam("Guam", -36000000),
    Sydney("Sydney", -36000000),
    Brisbane("Brisbane", -36000000),
    Melbourne("Melbourne", -36000000),
    // -9.5
    Darwin("Darwin", -34200000),
    Adelaide("Adelaide", -34200000),
    // -9
    ...
}

So if you won’t find your city in the list…feel free to add it with it’s timezone offset.

Additional to that we should show the current time of the day because if it’s 5:50 AM and 6:10 PM we will get a dark clock in both cases but one is at morning and the other at evening. For this reason i added a JPanel where i draw one out of four different states like follows:

  • Sunrise    ishot-8.png
  • Day         ishot-5.png
  • Sunset     ishot-6.png
  • Night       ishot-7.png

Furthermore we need a indication for the current day because it might happen, that a timezone is still on the time yesterday or on the time tomorrow. For this i add a little JLabel that indicates these states with

  • yesterday
  • today
  • tomorrow

Long story short…this is the JPanel i’m talking about

ishot-9.png

Step #3

Now i created a neat background panel that will take all the different city panels and give them a nice background.
Looks like this

ishot-10.png

Step #4

Create a JFrame in NetBeans and drag’n drop the background panel on to it.
Now you drag’n drop as many clock panels on the background panel as you would like to see in your worldtime clock and select the city for each panel…bam…that’s it.

ishot-13.png

Step #5

R E V I E W . . .

As i used the clock on my desktop i thought it would be nice if the clock itself could show the time of the day like some watches do.

And so i started to create another version of the AnalogClock component…

Therefor i needed a circular shape which represents the day-night cycle. Here is my Fireworks prototype

ishot-14.png

Unfortunately there is no out of the box ConicalGradientPaint available in Java2D and so i had to create my own version. I did this by rotating a Line2D around the center of the clock with changing color in dependence on the rotation angle.

This worked out fine and did the job but looked ugly in the code and i thought about creating my own ConicalGradientPaint class.

This was a challange to me because i had no idea about WritableRaster, PaintContext etc. and it took me some time to understand the underlying concept.

Now i have a gradient paint (and you will have it too if you take a look at the source) that i can use in the same way as e.g. LinearGradientPaint or RadialGradientPaint, here a short example

// Define the center of the cone
final java.awt.geom.Point2D CENTER = new java.awt.geom.Point2D.Double(IMAGE.getWidth() / 2, IMAGE.getHeight() / 2);

// Define the fractions for the colors
final float[] FRACTIONS =
{
    0.0f,
    0.10f,
    0.14f,
    0.18f,
    0.32f,
    0.68f,
    0.82f,
    0.86f,
    0.90f,
    1.0f
};

// Define the colors for the fractions
final java.awt.Color[] COLORS =
{
    new java.awt.Color(0x000000),
    new java.awt.Color(0x000000),
    new java.awt.Color(0x332200),
    new java.awt.Color(0x664411),
    new java.awt.Color(0x85A4C3),
    new java.awt.Color(0x85A4C3),
    new java.awt.Color(0x004466),
    new java.awt.Color(0x002233),
    new java.awt.Color(0x000000),
    new java.awt.Color(0x000000)
};

// Define the ConicalGradientPaint with the given parameters
final ConicalGradientPaint CONICAL_GRADIENT_PAINT = new ConicalGradientPaint(CENTER, FRACTIONS, COLORS);

// Set the paint
g2.setPaint(CONICAL_GRADIENT_PAINT);

// Fill a ellipse with the gradient
g2.fill(new java.awt.geom.Ellipse2D.Double(0, 0, IMAGE.getWidth(), IMAGE.getHeight()));

This piece of code leads to something like that

ishot-15.png

which is exactly the result i needed.
There’s one thing which i was not able to fix right now and that is transformation. Because i rotate the image in dependency of the current time i just calculate the angle from the time and say g2.rotate(nightDayAngle)…

Unfortunately this doesn’t work with my homebrewed ConicalGradientPaint because it does not take the transformation into account.
My idea was to create the night-day image as a bufferedimage and rotate it every minute about the time dependend angle. Because i could not rotate the gradient i now create the night-day image and rotate it everytime the seconds pointer will move forward.

That means if i could rotate the gradient it would give me a better performance but unfortunately i did not found the time to implement it right now.

Again long story short…here is the result of the AnalogClock component with it’s ability to show the current time of the day as graphic.

I created a special version of the clock with semitransparent images to show you were the night-day image is placed behind the clock-background. Here you see both versions…

ishot-16.png
ishot-17.png

With this AnalogClock i also created a worldclock that now looks like this

ishot-18.png

Well that’s it so far, i hope this will be usefull for at least some of you…

Of course you will get the source as always here…WorldClock.zip

In the netbeans project you will find two main classes, Main.class will start the worldclock without the night-day display and Main2.class will start it with the night-day display. Default is the Main.class.

Follow me on twitter if you like…

 

6 Antworten Verfasse eine Antwort

  1. Lucio Biondi sagt:

    Wow, very impressive !!

  2. John Wheeler sagt:

    FUCK FUCK FUCK AWESOME!!!

  3. niks sagt:

    I have seen some similar clock with css3 check out here

  4. Wow, this is one of the best I’ve seen so far. I can’t believe it’s not Flash 🙂

  5. Dirk Lemmermann sagt:

    This looks very nice. Another example that you can do pretty much anything in Swing and Java2D, you only need the know-how. Writing blogs like this one will help to spread the word.

  6. Neon sagt:

    I really like it.