Tuesday, February 15, 2011

Learning the JavaFX Script Programming Language -- Learning the JavaFX Script Programming Language -- Writing Scripts

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

- Declaring Script Variables
- Defining and Invoking Script Functions
- Passing Arguments to Script Functions
- Returning Values from Script Functions
- Accessing Command-Line Arguments
- Testing for Read-Only Variables

Declaring Script Variables

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.
Defining and Invoking Script Functions

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.
Passing Arguments to Script Functions

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 that the function 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.
Returning Values from Script Functions

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);



The return type of a function is determined by the type of the last expression in the function. If the function is empty, or if the last expression in the function is Void (for example, a call to println()) then the return type is Void.

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.
Accessing Command-Line Arguments

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:

javafx calculator 100 50



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.

Testing for Read-Only Variables

You can test for read-only variables by invoking the built-in isReadOnly function. This function accepts a single argument which must be a variable defined with a var (as opposed to an expression, or a variable defined with a def.)

isReadOnly(xx) returns true if xx cannot be modified, else it returns false. The only vars that are read-only are those defined with a bind. For example:

var y;
var x = bind y;
println("is x bound ? {isReadOnly(x)}");
println("is y bound ? {isReadOnly(y)}");



This code will print:

is x bound ? true
is y bound ? false


SOURCE:http://download.oracle.com/javafx/1.3/tutorials/core/writingScripts/index.html

0 comments: