Steve On Java

Hacking JavaFX and Java with Agility
  • rss
  • Home
  • About
  • Contact
  • SvJugFX

WidgetFX Calendar Tutorial

steveonjava | January 27, 2009

Update 1: This sample is now Java 1.5 compatible.

Update 2: The Calendar Tutorial has been updated for the WidgetFX 1.2 beta!  Updates are highlighted in red.

WidgetFX makes it simple to deploy JavaFX widgets to the desktop.  This tutorial that Keith Combs and I developed will show you how to create simple Calendar Widget that shows the current year, month, and day.  For some visual splash, we will also make the widget appear like a stack of calendar pages complete with a spiral binding.

Calendar Widget

Calendar Widget

The first step is to download the latest SDK from the WidgetFX site.  You can download the SDK from the following link: http://code.google.com/p/widgetfx/downloads/list

The SDK includes javadoc, samples (including this one), and the required jars.  The only files you need to complete this tutorial are widgetfx-api.jar and JFXtras-0.5.jar which are located in the lib directory.  Make sure to add these to your application classpath when building this sample.

The main widget file always needs to return an object of type Widget.  The following code sample creates a new widget that has an initial width and height of 180 and 200, respectively. It is constrained to keep the same aspect ratio when resizing, and uses config and group variables that you will define later:

[sourcecode language='java']
def defaultWidth = 180.0;
def defaultHeight = 200.0;

def widget:Widget = Widget {
width: defaultWidth
height: defaultHeight
aspectRatio: defaultWidth / defaultHeight
configuration: config
content: group
}
return widget;
[/sourcecode]

Next you need to create the content group.  In this case you can use a Group that scales to fit the window and has a sequence of content to generate the pages, spiral, and calendar text.

[sourcecode language='java']
def group:Group = Group {
def arcHeight = defaultHeight / 20;
def offset = defaultWidth / 25;

    transforms: bind Transform.scale(
        widget.width / defaultWidth,
        widget.height / defaultHeight);
    // scale down by 1% to leave room for stroke width
scaleX: .99
scaleY: .99
content: [
for (i in reverse [0..3]) {
createPage(offset*i/3, offset*i/3 + arcHeight,
defaultWidth – offset,
defaultHeight – offset – arcHeight)
},
createSpiral(defaultWidth – offset, arcHeight),
createPageContents(0, arcHeight * 2,
defaultWidth – offset,
defaultHeight-offset-arcHeight*2)
]
}
[/sourcecode]

The pages are created using a simple for loop that iterates over a fixed sequence of 4 elements.  Each page is created by passing in different offsets to a common createPage function.

To build the createPage function you can return a sequence of 3 Rectangle objects layered on top of each other for the fill, footer, and border of the page.

[sourcecode language='java']
function createPage(x:Number, y:Number,
width:Number, height:Number) {
[
Rectangle { // Fill
translateX: x
translateY: y
width: width
height: height
fill: Color.WHITE
},
Rectangle { // Footer
translateX: x
translateY: y + height * 6/7
width: width
height: height / 7
fill: Color.MIDNIGHTBLUE
},
Rectangle { // Border
translateX: x
translateY: y
width: width
height: height
fill: null
stroke: Color.BLACK
}
]
}
[/sourcecode]

Because Widget extends Panel, you can run your application by simply passing your CalendarWidget class as the main class to the javafx command.  Running the program so far produces the following stacked deck of pages:

Calendar Widget Page Deck

Calendar Widget Page Deck

Next you need to implement the createSpiral method to add in the spiral binding, which can be created with a sequence of Arc objects.  The following code sample shows how to create 20 arcs that are evenly spaced out across the top of the page using another for loop:

[sourcecode language='java']
function createSpiral(width:Number, arcHeight:Number) {
def numArcs = 20;
for (i in [1..numArcs]) {
var arcSpacing = width / (numArcs + 2);
Arc {
centerX: arcSpacing * (i + 1)
centerY: arcHeight
radiusX: arcHeight * 2 / 3
radiusY: arcHeight
startAngle: 0
length: 230
stroke: Color.BLACK
fill: null
}
}
}
[/sourcecode]

Adding the spiral to the page stack produces the following output:

Calendar Widget with Spiral

Calendar Widget with Spiral

Now it is time to add in the calendar contents.  To get the current year, month, and day you can call the java.util.Calendar class from JavaFX Script.  Rendering the text is simply a matter of binding Text instances to the corners and center of the page as shown in the following example:

[sourcecode language='java']
var locale = Locale.getDefault();
function createPageContents(x:Number, y: Number,
width:Number, height:Number) {
def calendar = Calendar.getInstance();
def fontHeight = 20;
def offset = 5;
def dateSymbols = bind new DateFormatSymbols(locale);
def date:Text = Text {
translateX: bind (width-date.layoutBounds.width)/2
translateY: bind (height-date.layoutBounds.height)/2
content: “{calendar.get(Calendar.DAY_OF_MONTH)}”
font: Font.font(“Impact”, height * 2 / 3)
textOrigin: TextOrigin.TOP
}
def year:Text = Text {
translateX: offset
translateY: offset + fontHeight
font: Font.font(null, fontHeight)
content: “{calendar.get(Calendar.YEAR)}”
}
def month:Text = Text {
translateX: bind width – month.layoutBounds.width -
offset
translateY: offset + fontHeight
font: Font.font(null, fontHeight)
content: bind Arrays.asList(dateSymbols.getMonths())
.get(calendar.get(Calendar.MONTH))
    }
    def dayOfWeek:Text = Text {
        translateX:
            bind (width – dayOfWeek.layoutBounds.width) / 2
        translateY: height – offset * 1.5
        font: Font.font(null, fontHeight)
content: bind Arrays.asList(dateSymbols.getWeekdays())
.get(calendar.get(Calendar.DAY_OF_WEEK))
fill: Color.WHITESMOKE
}
Group {
translateX: x
translateY: y
content: [date, year, month, dayOfWeek]
}
}
[/sourcecode]

The example uses a platform specific font for Windows, which will automatically map to a similar Font on other platforms, but you may want to change it based on your platform.

To run your application as a real Widget complete with transparency, resizing, and a toolbar, you can use the Widget Runner.  The Widget Runner is automatically invoked whenever you run a Widget class via Web Start.  Try using the javafxpackager tool to create a Web Start distribution for your widget, which will produce the following results when you launch your JNLP file:

Calendar Widget in Widget Runner

Calendar Widget in Widget Runner

Rather than simply hard coding the locale, you can make this dynamic by creating a Configuration object for the widget.  Configuration consists of properties that get saved to disk or loaded on startup and a Scene that defines the configuration dialog that pops up when you click on the wrench icon in the toolbar.  The following example persists the language, country, and variant as Strings, and pops up a dialog using the JFXtras Grid to align the Text and SwingComboBox.

[sourcecode language='java']
var language:String = Locale.getDefault().getLanguage();
var country:String = Locale.getDefault().getCountry();
var variant:String = Locale.getDefault().getVariant();
var locale = bind new Locale(language, country, variant);

def config = Configuration {
properties: [
StringProperty {
name: "language"
value: bind language with inverse
},
StringProperty {
name: "country"
value: bind country with inverse
},
StringProperty {
name: "variant"
value: bind variant with inverse
}
]
var locales = Locale.getAvailableLocales();
var localePicker = SwingComboBox {
items: for (l in locales) {
SwingComboBoxItem {
selected: l == locale
text: l.getDisplayName()
value: l
}
}
}
scene: Scene {
content: Grid {
rows: row([
Text {content: "Locale:"},
localePicker
])
}
}
onSave: function() {
var l = localePicker.selectedItem.value as Locale;
language = l.getLanguage();
country = l.getCountry();
variant = l.getVariant();
}
    onLoad: function() {
        localePicker.selectedIndex =
            Sequences.indexOf(locales, locale);
    }
}
[/sourcecode]

Now when you run the example in the Widget Runner and click on the wrench icon in the toolbar you will get the following dialog:

Locale Configuration Dialog

Locale Configuration Dialog

Note: Due to a defect in the JavaFX 1.2 release the combo box dropdown will not extend below the bottom of the window, so you will have to use keyboard navigation to change the locale.  A JavaFX native combo box is targeted for the next major JavaFX release, which should solve this problem.

Changing the locale and closing the dialog will allow you to see the dates in your language of choice, and will also be saved between sessions.  The following example shows the finished Calendar Widget configured for the Greek locale:

Finished Calendar Widget in Greek

Finished Calendar Widget in Greek

Deploying your fnished WidgetFX application on the web is as simple as creating a Web Start link to the WidgetFX application that references your widget’s jnlp file using the following format:

http://widgetfx.org/dock/launch.jnlp?arg=<widgetUrl>

Note: Until the official WidgetFX 1.2 release, you will have to replace “dock” with “beta” in all your URLs (e.g. http://widgetfx.org/beta/launch.jnlp)

This will automatically install or launch WidgetFX and add your Widget to the dock.  Please feel free to use the following graphic when creating links to widgets so your users know that it runs in WidgetFX:

WidgetFX Launch Icon
WidgetFX Launch Icon

Your completed HTML link would look something like the following:

[sourcecode language="html"]


[/sourcecode]

Click to launch the finished demo:

Congratulations!

You have finished your first WidgetFX widget complete with dynamic resizing, configuration, and web deployment.  The sky is the limit in creating JavaFX widgets, so give your own widget ideas a try and upload them to the new Widget Library.

 
Categories
Uncategorized
Comments rss
Comments rss
Trackback
Trackback

« JFXtras 0.2 Release – Shapes, Shapes, and More! Migrating to the JavaFX 1.1 Release »

5 Responses to “WidgetFX Calendar Tutorial”

  1. Swing links of the week, February 2nd | Jonathan Giles says:
    February 1, 2009 at 12:09 pm

    [...] Chin posts in his blog a tutorial on using the Calendar widget (which comes as part of [...]

    Reply
  2. JavaFX Links (3) « Java and more … says:
    February 20, 2009 at 11:17 am

    [...] Calendar [...]

    Reply
  3. World feelings WidgetFX « TareitasFX says:
    February 24, 2009 at 3:58 pm

    [...] If you want to learn how to build a widget for widgetfx platform here is a basic tutorial calendar tutorial [...]

    Reply
  4. WidgetFX 1.2 Beta Announcement « Steve on Java says:
    June 18, 2009 at 5:40 am

    [...] http://steveonjava.com/2009/01/27/widgetfx-calendar-tutorial/ [...]

    Reply
  5. WidgetFX 1.2 Release Announcement « Steve on Java says:
    June 30, 2009 at 5:19 am

    [...] (from left-to-right: Clock, WebFeed, Weather, SlideShow, Pac-Man, World Clock, Calendar) [...]

    Reply

Leave a Reply

Click here to cancel reply.

Publications

The most comprehensive book on the JavaFX Platform! Also covers JFXtras and WidgetFX in depth.

Download my free Refcard covering JavaFX 1.2 from DZone.

Affiliations

Awards

2009 JavaOne Rock Star!

Categories

  • Announcements (11)
  • contest (3)
  • Events (11)
  • JavaFX (26)
  • jfxtras (8)
  • Liferay (2)
  • presentation (4)
  • pro javafx (2)
  • SvJugFx (3)
  • Uncategorized (22)
  • widgetfx (9)
rss Comments rss valid xhtml 1.1 design by jide powered by Wordpress get firefox