|
This lesson provides a hands-on introduction to the JavaFX Script
programming language. In it you will learn the basics of variables and functions,
by writing a simple calculator that runs from the command line.
Each section will introduce one new core concept, discuss it, and provide sample code that you can
compile and run. The discussions also contain "real world"
code excerpts showing how a particular construct is used in an actual SDK demo. Following the link for
each demo will take you to the javafx.com website, where you can obtain the full code listing,
plus additional notes from the developer.
|
Contents
The previous lesson walked you through setting up a development environment; here we will
take a closer look at the Calculator.fx source code.
The code in red below
declares the program's script variables.
Script variables are declared using the var or def keywords. The difference between the two is that var variables may be assigned new values throughout the life of the script, whereas def1 variables remain constant at their first assigned value. Here we have assigned some values to numOne and numTwo, but have left result uninitialized because this variable will hold the result of our future calculations:
def numOne = 100;
def numTwo = 2;
var result;
add();
subtract();
multiply();
divide();
function add() {
result = numOne + numTwo;
println("{numOne} + {numTwo} = {result}");
}
function subtract() {
result = numOne - numTwo;
println("{numOne} - {numTwo} = {result}");
}
function multiply() {
result = numOne * numTwo;
println("{numOne} * {numTwo} = {result}");
}
function divide() {
result = numOne / numTwo;
println("{numOne} / {numTwo} = {result}");
}
|
You may have noticed that we did not need to explicitly specify these variables as
holding numerical data (as opposed to character strings or any other kind of data). The compiler is smart enough to figure out your intent based on the context in which the variable is used. This is known as type inference. Type inference makes your job as a script programmer a little easier because it frees you from the burden of declaring the data types that your variable is compatible with.
Real-World Example: Effects Playground
The screenshot above shows the "Effects Playground" demo application. The code excerpt to the right
shows a few of its script variables.
You won't understand this entire listing — yet — but the highlighted portions
should make sense based on what you've just learned.
Keep in mind that
while this tutorial is focused on non-graphical, core constructs only,
you will eventually put this knowledge to use in
your own GUI-based applications.
For a lower-level discussion of variables, see
Chapter 3: Variables of the
JavaFX Script Programming Language Reference.
Our calculator example also
defines some script functions that add, subtract, multiply, and divide the two numbers.
A function is an executable block of code that performs
a specific task. The red code below defines four functions; each performs a simple
mathematical calculation and then prints out the result. Organizing code into
functions is a common practice that makes your programs easier to read, easier to use, and easier to debug.
The body of a function will typically be indented for readability.
def numOne = 100;
def numTwo = 2;
var result;
add();
subtract();
multiply();
divide();
function add() {
result = numOne + numTwo;
println("{numOne} + {numTwo} = {result}");
}
function subtract() {
result = numOne - numTwo;
println("{numOne} - {numTwo} = {result}");
}
function multiply() {
result = numOne * numTwo;
println("{numOne} * {numTwo} = {result}");
}
function divide() {
result = numOne / numTwo;
println("{numOne} / {numTwo} = {result}");
}
|
You should also know that function code does not execute until it is explicitly invoked. This makes it possible to run a function from any location within your script. It does not matter if the function invocation is placed before or after the function definition (in our example we invoke the functions earlier in the source file than where they are actually defined):
def numOne = 100;
def numTwo = 2;
var result;
add();
subtract();
multiply();
divide();
function add() {
result = numOne + numTwo;
println("{numOne} + {numTwo} = {result}");
}
function subtract() {
result = numOne - numTwo;
println("{numOne} - {numTwo} = {result}");
}
function multiply() {
result = numOne * numTwo;
println("{numOne} * {numTwo} = {result}");
}
function divide() {
result = numOne / numTwo;
println("{numOne} / {numTwo} = {result}");
}
|
Real-World Example: Draggable MP3 Player
In the "Draggable MP3 Player" demo,
the programmer has defined functions to stop or play the current song. Although we are looking at this
code completely out of context, the naming choice for these functions (stopCurrentSong and playCurrentSong) makes the code
self-documenting, and therefore much
easier to analyze.
When naming
your variables and functions, try to always use meaningful words like this.
The convention is to spell the first word in all lowercase letters, then capitalize the first
letter of each subsequent word in the name.
Script functions may also be defined to accept arguments. Arguments are specific values
that you pass in while invoking a function. With this approach we can make the
calculator application perform computations on any two numbers,
not just the values that were hard-coded into the numOne and numTwo variables.
In fact, in this version, we have removed numOne and numTwo entirely, leaving
result as the only remaining script variable:
var result;
add(100,10);
subtract(50,5);
multiply(25,4);
divide(500,2);
function add(argOne: Integer, argTwo: Integer) {
result = argOne + argTwo;
println("{argOne} + {argTwo} = {result}");
}
function subtract(argOne: Integer, argTwo: Integer) {
result = argOne - argTwo;
println("{argOne} - {argTwo} = {result}");
}
function multiply(argOne: Integer, argTwo: Integer) {
result = argOne * argTwo;
println("{argOne} * {argTwo} = {result}");
}
function divide(argOne: Integer, argTwo: Integer) {
result = argOne / argTwo;
println("{argOne} / {argTwo} = {result}");
}
|
The output of this script is now:
100 + 10 = 110
50 - 5 = 45
25 * 4 = 100
500 / 2 = 250
|
Real-World Example: Interesting Photos
In this code excerpt from the "Interesting Photos" demo,
we see a script
function named loadImage that accepts a list of arguments.
Again, the choice of function and argument names makes the code
easier to understand.
Understanding the full implementation of this function is not
important at this time. What is important, however, is recognizing
the function that accepts two arguments.
As you start writing your own applications, you will probably rely on sample code such as this for examples of the correct syntax.
A function may also return a value to the code that invokes it. For example, we could
change the calculator's add function
so that it returns the result of each calculation:
function add(argOne: Integer, argTwo: Integer) : Integer {
result = argOne + argTwo;
println("{argOne} + {argTwo} = {result}");
return result;
}
|
The first code in red specifies that the function returns an Integer; the second is the code that actually returns the value.
The add function can now be invoked like this:
var total;
total = add(1,300) + add(23,52);
|
If no return value is specified, a function returns Void by default.
Real-World Example:
Animating Photos from Flickr
In this code excerpt from the "Animating Photos from Flickr" demo,
we see return values at work in three different functions. The returned values
are slightly more complex than what you've seen so far, but the core concept is the same: each
function performs some specific calculation, then returns a result. The first two functions subsequently
invoke a Math function (to calculate a square root) and return its result. The third function
returns a new Vector2D object. There isn't enough information in this listing alone to know exactly what
that means, but with the complete source code, it would make sense (that is,
providing that you've taken the time to first learn the language!)
For a lower-level discussion of functions, see
Chapter 4: Functions of the
JavaFX Script Programming Language Reference.
Finally, scripts can also accept command-line arguments. In our calculator example, this will enable end users to specify the numbers to be calculated at runtime.
var result;
function run(args : String[]) {
// Convert Strings to Integers
def numOne = java.lang.Integer.parseInt(args[0]);
def numTwo = java.lang.Integer.parseInt(args[1]);
// Invoke Functions
add(numOne,numTwo);
subtract(numOne,numTwo);
multiply(numOne,numTwo);
divide(numOne,numTwo);
}
function add(argOne: Integer, argTwo: Integer) {
result = argOne + argTwo;
println("{argOne} + {argTwo} = {result}");
}
function subtract(argOne: Integer, argTwo: Integer) {
result = argOne - argTwo;
println("{argOne} - {argTwo} = {result}");
}
function multiply(argOne: Integer, argTwo: Integer) {
result = argOne * argTwo;
println("{argOne} * {argTwo} = {result}");
}
function divide(argOne: Integer, argTwo: Integer) {
result = argOne / argTwo;
println("{argOne} / {argTwo} = {result}");
}
|
This change introduces the run function, which is where the command-line arguments
are received by the script. Unlike the other functions that you've seen, run is a special function
that serves as the script's main entry point. The run function stores all
command-line arguments in args, which is a sequence of String objects.
(Sequences are ordered lists of objects, similar to arrays in other programming languages; they are
explained in detail in Lesson 5: Sequences.)
To run this script, the user now must specify the first and second numbers at runtime:
The output is now:
100 + 50 = 150
100 - 50 = 50
100 * 50 = 5000
100 / 50 = 2
|
Note that in all previous versions of the calculator script, we did not explicitly provide a run function. We just typed the code to be executed at the script level and it ran as expected. In such cases, the compiler silently generates a no-arg run function and places the code to be executed inside of it. When specifying your own run function, the name args can be anything you want; we use "args" but you will probably see programmers use other variations of it, such as "arg", "ARGS", "__ARGS__", "argv" etc.
Also note that in this version we have brought back the numOne and numTwo variables, which are now defined inside the run function instead of at the script level. (When a variable is defined inside a function, it is technically known as a local variable, because it is only visible to other code within that same function.) Our calculator functions expect numbers, but the command-line arguments are character strings; we therefore must convert each command-line argument from String to Integer before we can pass them along to the functions:
// Convert Strings to Integers
def numOne = java.lang.Integer.parseInt(args[0]);
def numTwo = java.lang.Integer.parseInt(args[1]);
|
To do this we have enlisted the help of the Java programming language to perform the actual type conversion. Tapping into the existing Java ecosystem as needed brings tremendous power to this otherwise simple scripting language.
Real-World Example: Brick Breaker
This excerpt from the "Brick Breaker" demo shows the run function serving as the game's main entry point. While this particular example does not actually use its command-line arguments, we can see that the run function initializes the main frame of the application, setting its title, width, height, etc.
1. Unless the def is involved in a bind. Binding will be covered in Lesson 8.
Do you have comments about this article? We welcome your participation in our community. Please keep your comments civil and on point. You may optionally provide your email address to be notified of replies - your information is not used for any other purpose. By submitting a comment, you agree to these Terms of Use.
|
|