Getting Weather Forecast from Yahoo!
This simple JavaFX application displays weather forecasts retrieved from Yahoo! Weather RSS feed. Any location can be requested by its Location ID. For example, ENXX0004 for Tallinn (Estonia), RSXX0091 for St. Petersburg (Russia), EZXX0012 for Prague (Czech Republic), USCA0693 for Menlo Park, and USCA1018 for Santa Clara.
Understanding the Code
This example shows how to parse XML in the JavaFX programming language.
Information about weather forecasts is obtained by performing an HTTP GET request by using the JavaFX asynchronous HTTP API, as shown in Figure 1. Note that the input stream should be closed even if an error occurs.
HttpRequest {
location: url
onDone: function() {
// check for errors after parsing
if (forecast.isEmpty())
location = "Loading error"
}
onInput: function(input) {
try {
// parse input stream
// see Figure 2
} finally {
input.close()
}
}
}.enqueue()
Figure 1: Requesting a Weather Forecast
The response document is parsed by using the JavaFX XML pull parser to extract information about the location and the forecast for that location. The sample code is shown in Figure 2.
PullParser {
var wind: Wind;
var temp: String;
var speed: String;
input: input
onEvent: function(event) {
if ((event.type == PullParser.START_ELEMENT) and (event.qname.prefix == "yweather")) {
if (event.qname.name == "location") {
location = event.getAttributeValue(QName{name:"city"});
def region = event.getAttributeValue(QName{name:"region"});
if (0 < region.length()) {
location = "{location}, {region}"
}
}
else if (event.qname.name == "units") {
temp = event.getAttributeValue(QName{name:"temperature"});
speed = event.getAttributeValue(QName{name:"speed"})
}
else if (event.qname.name == "wind") {
wind = Wind {
angle: event.getAttributeValue(QName{name:"direction"})
speed: event.getAttributeValue(QName{name:"speed"})
unit: speed
}
}
else if (event.qname.name == "condition") {
insert Forecast {
day: "Now"
high: event.getAttributeValue(QName{name:"temp"})
text: event.getAttributeValue(QName{name:"text"})
code: event.getAttributeValue(QName{name:"code"})
unit: temp
wind: wind
} into forecast
}
else if (event.qname.name == "forecast") {
insert Forecast {
day: event.getAttributeValue(QName{name:"day"})
low: event.getAttributeValue(QName{name:"low"})
high: event.getAttributeValue(QName{name:"high"})
text: event.getAttributeValue(QName{name:"text"})
code: event.getAttributeValue(QName{name:"code"})
unit: temp
} into forecast
}
}
}
}.parse()
Figure 2: Parsing the Server Response
Customizing the Code
The Config class contains the following variables that affect the appearance of the weather widget.
- WIDTH
- Preferred width of the widget, but actual width depends on scene width
- HEIGHT
- Height of the widget
- SPACE
- Default spacing between components
- SMALL_FONT
- Font used for small text: forecast name, temperature, and wind speed
- LARGE_FONT
- Font used for large text: location and short description
- (it is calculated automatically)
- ROUND
- Diameter of the arc at the four corners of the rectangles
- FONT_COLOR
- Foreground color used for all text
- DARK_COLOR
- Main background color
- LIGHT_COLOR
- Lighter background color for creating the gradient filling
public def WIDTH = 320; public def HEIGHT = 170; public def SPACE = 2; public def SPACE_DOUBLE = 2 * SPACE; public def SMALL_FONT = Font { size: 12 } public def LARGE_FONT = Font { size: SPACE + 2 * SMALL_FONT.size } public def ROUND = SMALL_FONT.size; public def OFFSET = HEIGHT - 6 * SPACE - 2 * LARGE_FONT.size; public def FONT_COLOR = Color.WHITE; public def DARK_COLOR = Color.DARKBLUE; public def LIGHT_COLOR = Color.LIGHTBLUE;
Figure 3: Variables to Change
Sergey Malenkov
