Variables
JavaFX supports two kinds of variables: instance and script. Script variables hold state for the entire script, whereas instance variables hold state for specific instantiations of a class declared within the script file.
There are basically two flavors of variables: unassignable and changeable. Unassignable variables are declared using the def keyword and must be assigned a default value that never changes.
public def PI = 3.14;
These variables cannot be assigned to, overridden, or initialized in object literals. In a sense, these can be viewed as constants; however, they are not “pure” constants and can participate in binding. (For more information on binding, see Chapter 4, Synchronize Data Models—Binding and Triggers.)
Consider the following example of defining an unassignable variable that contains an object. The object instance cannot change, but that does not mean the state of that instance will not.
def centerPoint = Point{x: 100, y:100}; centerPoint.x = 500;
The actual Point object assigned to centerPoint remains unchanged, but the state of that object instance, the actual x and y values, may change. When used in binding though, centerPoint is constant; if the state of centerPoint changes, the bound context will be notified of the change.
Changeable instance variables are declared using the var keyword with an optional default value. If the default value is omitted, a reasonable default is used; basically, Numbers default to zero, Boolean defaults to false, Strings default to the empty string, Sequences default to the Empty Sequence, and everything else defaults to null.
Script variables are declared outside of any class declaration, whereas instance variables are declared within a class declaration. If a script variable is declared with one of the access modifiers—public, protected, or package—it may be used from outside of the script file, by referring to its fully qualified name. This fully qualified name is the combination of package name, script name, and the variable name. The following is the fully qualified name to a public script variable from the javafx.scene.Cursor class for the crosshair cursor.
javafx.scene.Cursor.CROSSHAIR;
Instance variables are declared within a class declaration and come into being when the object is created. Listing 3.5 illustrates several examples of script and instance variables.
Listing 3.5. Script and Instance Variables
import javafx.scene.Cursor; import javafx.scene.paint.Color; // import of script variable from javafx.scene.Cursor import javafx.scene.Cursor.CROSSHAIR; // Unchangeable script variable def defaultText = "Replace ME"; // Script accessible only // Changeable script variable public var instanceCount: Integer; // Public accessible public class Title { // Unchangeable instance variables def defStroke = Color.NAVY; // class only access, //resolves to javafx.scene.paint.Color.NAVY // Changeable instance variables // defaults to the empty String "" public var text:String; public var width: Number; // defaults to zero (0.0) public var height = 100; // Infers Integer type public var stroke: Color = defaultStroke; public var strokeWidth = 1.0; // Infers Number type public var cursor = CROSSHAIR; //resolves to javafx.scene.Cursor.CROSSHAIR ... }
You may have noticed that some of the declarations contain a type and some don’t. When a type is not declared, the type is inferred from the first assigned value. String, Number, Integer, and Boolean are built-in types, everything else is either a JavaFX or a Java class. (There is a special syntax for easily declaring Duration and KeyFrame class instances that will be discussed in Chapter 7, Add Motion with JavaFX Animation.)
Table 3.1 lists the access modifiers for variables and their meaning and restrictions. You will notice reference to initialization, which refers to object literal declarations. Also, you will notice variables being bound. This is a key feature of JavaFX and is discussed in depth in Chapter 4.
Table 3.1. Access Modifiers
Access Modifier |
Meaning |
var |
The default access permission is script access, so without access modifiers, a variable can be initialized, overridden, read, assigned, or bound from within the script only. |
def |
The default access permission is script access; a definition can be read from or bound to within the script only. |
public var |
Read and writable by anyone. Also, it can be initialized, overridden, read, assigned, or bound from anywhere. |
public def |
This definition can be read anywhere. A definition cannot be assigned, initialized (in an object literal), or overridden no matter what the access permissions. It may be bound from anywhere. |
public-read var |
Readable by anyone, but only writable within the script. |
public-init var |
Can be initialized in object literals, but can only be updated by the owning script. Only allowed for instance variables. |
package var |
A variable accessible from the package. This variable can be initialized, overridden, read, assigned, or bound only from a class within the same package. |
package def |
Define a variable that is readable or bound only from classes within the same package. |
protected var |
A variable accessible from the package or subclasses. This variable can be initialized, overridden, read, assigned, or bound from only a subclass or a class within the same package. |
protected def |
Define a variable that is readable or bound only from classes within the same package or subclasses. |
public-read protected var |
Readable and bound by anyone, but this variable can only be initialized, overridden, or assigned from only a subclass or a class within the same package. |
public-init protected var |
Can be initialized in object literals, read and bound by anyone, but can only be overridden or assigned, from only a subclass or a class within the same package. Only allowed for instance variables. |
You can also declare change triggers on a variable. Change triggers are blocks of JavaFX script that are called whenever the value of a variable changes. To declare a change trigger, use the on replace syntax:
public var x:Number = 100 on replace { println("New value is {x}"); }; public var width: Number on replace (old) { println("Old value is {old}, New value is {x}"); }
Change triggers are discussed in more depth in Chapter 4.