JavaFX
Регистрация
Advertisement

Главная | Описание языка | FXD | API | Примеры | Инструменты Разработки | Новости | Ресурсы | Форум


Документация[]

На Английском

На Русском

Полезные советы[]

Установка языка JavaFX Script[]

Установка JavaFX SDK[]


В текстовом редакторе создайте файл HelloWorld.fx и скопируйте туда код примера:

import javafx.stage.*;

import javafx.scene.*;
import javafx.scene.text.*;
import javafx.scene.paint.*;
import javafx.scene.effect.*;


Stage {
    title: "Hello Frame"
    width: 250
    height: 80
    scene: Scene {
        content: Text {
            x: 10  y: 30
            font: Font { size: 24 }
            fill: Color.BLUE
            effect: DropShadow{ offsetX: 3 offsetY: 3}
            content: "Hello World!"
        }
    }
}


Чтобы скомпилировать и запустить пример, наберите в командной строке:

    > javafxc HelloWorld.fx
    > javafx  HelloWorld


На экране монитора у вас должно появится окошко с заголовком "Hello Frame" и надписью "Hello World!"

compiler_hello_world

Инструменты Разработки[]

Для программирования на языке JavaFX Script можно воспользоваться существующими средами разработки:

Краткое введение в язык JavaFX Script[]

Смотри краткое введение в язык JavaFX Script на примере компании Pond Inc

Особенности языка JavaFX Script[]

Декларативный синтаксис[]

В отличие от императивных языков, в которых описывается последовательность исполняемых действий, язык JavaFX Script позволяет описать структуру самой программы.


Создание программы на языке JavaFX Script можно разбить на 2 этапа

описание необходимых компонент (классов)
построение программы из готовых компонент

Сама программа строится по принципу:

пишем имя компонента
в фигурных скобках задаем атрибуты компонента
MyComponent{
   attribute1: value1
   attribute2: value2
   // ...
   attributeN: valueN

}


Атрибуты могут иметь простой тип (число, строка) или сложный.


MyComponent{
   attr1: SubComp1{
             subAttr1: value1
             // ...
          }
   // ...
   attrN: SubComp1{
             subAttr1: value1
             // ...
          }
}


Таким образом программа на JavaFX представляет из себя дерево вложенных друг в друга компонент.


Примеры:

2D графика

Пример использования Картинка
import javafx.stage.*;
import javafx.scene.*;
import javafx.scene.text.*;
import javafx.scene.shape.*;
import javafx.scene.paint.*;
import javafx.scene.effect.*;

Stage {
    title: "Shapes"
    scene: Scene {
        width: 330
        height: 280
        content: [
            Rectangle {
                x: 50, y: 50
                width: 220, height: 120
                strokeWidth: 2
                fill: Color.LIGHTGREEN
                stroke: Color.GREEN
            }
            Circle {
                centerX: 180, centerY: 150
                radius: 70
                fill: Color.LIGHTBLUE
                stroke: Color.BLUE
                strokeWidth: 2
            } Text {
                x: 70, y: 130
                font: Font { size: 30 }
                content: "Hello World!"
                fill: Color.ORANGE
                effect: DropShadow {}
            }
        ]
    }
}
Lang shapes


UI интерфейс

Пример использования Картинка
import javafx.stage.*;
import javafx.scene.*;
import javafx.scene.text.*;
import javafx.scene.paint.*;
import javafx.scene.control.*;


var name = "";

Stage {
    title : "Hello World!"
    scene: Scene {
        width: 330
        height: 170
        content: [
            Text {
                font: Font{ size: 24 }
                x: 10, y: 30
                fill: Color.BLUE
                content: "Enter Name:"
            }
            TextBox {
                columns: 12
                translateX: 150
                translateY: 10
                font: Font{ size: 16 }
                text: bind name with inverse
            }
            Text {
                font: Font{ size: 24 }
                x: 10, y: 70
                fill: Color.GREEN
                content: bind "Hello {name}!"
            }
        ]
    }
}
Lang ui


Структура данных


Язык JavaFX Script позволяет описывать данные аналогично тому, как это делается в XML

XML: contacts.xml JavaFX: Contacts.fx
<contact-list>
    <contact>
        <firstName> Mike </firstName>
        <lastName> Wazowski </lastName>
        <eMailAddress> 
              Mike.Wazowski@monster.com 
        </eMailAddress>
    </contact>
    <contact>
        <firstName> Sulley </firstName>
        <lastName> Monster </lastName>
        <eMailAddress> 
            Sulley.Monster@monster.com
        </eMailAddress>
    </contact>
</contact-list>
[ 
    Contact {
        firstName: "Mike"
        lastName: "Wazowski"
        eMailAddress: "Mike.Wazowski@monster.com"
    },
    Contact {
        firstName: "Sulley"
        lastName: "Monster"
        eMailAddress: "Sulley.Monster@monster.com"
    }
]





Описав класс Contact на языке JavaFX Script вы сможете скомпилировать файл Contacts.fx (компилятор проверит все ошибки), загрузить данные из этого файла в вашу программу и использовать их.

Пример:


class Contact{
    var firstName: String;
    var lastName: String;
    var eMailAddress: String;
}

var contacts = loadFXCode("Contacts");

for(contact in contacts){
    println("{contact.firstName} {contact.lastName} has {contact.eMailAddress} email address");
}

Результат исполнения программы:

 Mike Wazowski has Mike.Wazowski@monster.com email address
 Sulley Monster has Sulley.Monster@monster.com email address



Система, состоящая из компонент


Пример использования Картинка
ElectroScheme{
    var wire1 = Wire{}
    var wire2 = Wire{}
    var wire3 = Wire{}

    components:[
    Lamp{
        pos: XY{ x: 160  y: 25}
        pin1: wire1.pin2
        pin2: wire3.pin1
    },
    Battery{
        pos: XY{ x: 100  y: 120}
        pin1: wire2.pin2
        pin2: wire1.pin1
    },Switch{
        pos: XY{ x: 180  y: 105}
        pin1: wire3.pin2
        pin2: wire2.pin1

    },
  ]
}
Electronic simulator off

Связывание данных[]

Поскольку программа на JavaFX состоит из набора компонент, возникает необходимость связывать между собой атрибуты компонент в дереве программы.

Для этого используется оператор bind.

В примере ниже переменная R связывается:

с атрибутом value комонента Slider
с атрибутом radius комонента Circle
с атрибутом content комонента Text


Пример использования Картинка
import javafx.stage.*;
import javafx.scene.*;
import javafx.scene.text.*;
import javafx.scene.paint.*;
import javafx.scene.shape.*;
import javafx.scene.control.*;

def PI = 3.14;
var R = 50.0;

Stage {
    title: "Circle"
    scene: Scene {
        width: 300
        height: 300
        content: [
            Slider {
                min: 10, max: 70
                value: bind R with inverse
            }
            Circle {
                centerX: 150
                centerY: 150
                radius: bind R
                fill: Color.YELLOW
                stroke: Color.ORANGE
            }
            Text{
                x: 10, y: 250
                font: Font{  size: 18 }
                content: bind "Radius: { R }"
            }
            Text{
                x: 10, y: 270
                font: Font{  size: 18 }
                content: bind "Perimiter: { 2 * PI * R}"
            }
            Text{
                x: 10, y: 290
                font: Font{  size: 18 }
                content: bind "Area: { PI * R * R }"
            }

        ]
    }
}
Lang bind circle

Прямое использование классов языка Java[]

Программы на JavaFX Script и других языках[]

Hello World[]

JavaFX Script


Пример использования Картинка
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.Label;

import javafx.scene.layout.Flow;

Stage {
    title : "Hello World!"
    scene: Scene {
        width: 200
        height: 50
        content: Flow{
            content: Label {
                text: "Hello World!"
            }
        }
    }
}
Lang jfx helloworld


Java

Создание Hello World из готовых компонент:

Пример использования Картинка
import java.awt.*;
import javax.swing.*;

public class HelloWorld {

    public static void main(String[] args) {

        JFrame frame = new JFrame("Hello World!");
        frame.setSize(200, 70);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JPanel panel = new JPanel(new FlowLayout());
        panel.add(new JLabel("Hello World!"));

        frame.getContentPane().add(panel);
        frame.setVisible(true);
        
    }
}

Lang java helloworld

Расширение класса JFrame:

Пример использования Картинка
import java.awt.*;
import java.awt.event.*;

import javax.swing.*;

public class HelloFrame extends JFrame {

    public HelloFrame(){

        setTitle("Hello World!");
        setSize(200, 70);
        setDefaultCloseOperation(EXIT_ON_CLOSE);

        JPanel panel = new JPanel(new FlowLayout());
        panel.add(new JLabel("Hello World!"));

        getContentPane().add(panel);
    }

    public static void main(String[] args) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new HelloFrame().setVisible(true);
            }
        });
    }

}
Lang java helloworld


Обработка событий[]

JavaFX Script


Пример использования Картинка
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.layout.Flow;
import javafx.scene.control.Button;


Stage {
    title : "Button Example!"
    scene: Scene {
        width: 200
        height: 50
        content: Flow{
            content: Button {
                text: "Press Me!"
                action: function () {
                    println("Button Pressed!");
                }
            }
        }
    }
}
Lang jfx actionevent


Java

Пример использования Картинка
import java.awt.*;
import java.awt.event.*;

import javax.swing.*;

public class ButtonExample extends JFrame {

    public ButtonExample(){

        setTitle("Button Example!");
        setSize(250, 70);
        setDefaultCloseOperation(EXIT_ON_CLOSE);

        JPanel panel = new JPanel(new FlowLayout());
        JButton button = new JButton("Click Me!");

        button.addActionListener(new ActionListener(){
                public void actionPerformed(ActionEvent e) {
                    System.out.println("Button Pressed!");
                }
            }
        );

        panel.add(button);

        getContentPane().add(panel);
    }

    public static void main(String[] args) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new ButtonExample().setVisible(true);
            }
        });
    }

}
Lang java actionevent

Описание языка JavaFX Script[]

Смотри также документацию:


Main файл[]

 println("Hello World!");


import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.text.Text;
import javafx.scene.text.Font;


Stage {
    title: "Hello World!"
    scene: Scene {
        content: Text {
                x: 10, y: 30
                font : Font { size: 24 }
                content: "Hello World!"
            }
    }
}

Метод run[]

function run(){
    println("Hello world!");
}

Получение параметров[]

Получение параметров в методе run:

function run(args:String[]){
    for(arg in args){
        println("arg: {arg}");
    }
}

или получение переданных параметров по имени:

 println("Argument {FX.getArgument( "key" )}");

Передача параметров[]

JavaFX - Passing Arguments


Командная строка

 javafx -cp FXArguments.jar fxarguments.Main key="From Command Line"


Апплет

Форум

<script src="http://dl.javafx.com/1.2/dtfx.js"></script>
<script>
    javafx(
        {
              archive: "FXArguments.jar",
              draggable: true,
              width: 250,
              height: 80,
              code: "fxarguments.Main",
              name: "FXArguments",
        },
        {
              key: "from Applet"
        }
    );
</script> 


JNLP

<jnlp spec="1.0+" codebase="dist" href="FXArguments.jnlp">
    <application-desc main-class="com.sun.javafx.runtime.main.Main">
        <argument>MainJavaFXScript=fxarguments.Main</argument>
        <argument>key=from Java Web Start</argument>
    </application-desc>
</jnlp> 

Типы данных[]

Базовые типы[]

В языке JavaFX Script существуют следующие примитивные типы:

Логический тип

  • Boolean

Символьный тип

  • Character
  • String

Целые числа

  • Byte
  • Short
  • Integer
  • Long

Числа с плавающей точкой

  • Float (Number)
  • Double

Время

  • Duration


JavaFX тип Описание Пример
Boolean Логический тип true, false
Character Символ
String Строка "Hello World!"
Byte Байт 10
Short Короткое целое число 12
Integer Целое число 12
Long Длиное целое число 12
Float Вещественное число 5.0
Double Вещественное число с двойной точностью 10.0
Duration Время 12s // 12 секунд

Поэтому можно использовать все те методы, которые есть у этих типов в языке Java

Примеры использования:

   var s = "Hello";   // Создаем переменную типа String
   println(s.toUpperCase());  // распечатается строка: "HELLO"
   var b = true;    // Создаем переменную типа Boolean
   println(b.equals(true));  //распечатается строка: true
   println(b.equals(false)); //распечатается строка: false
   var n = 1.5;   // Создаем переменную типа Number
   println(n.intValue());  // распечатается строка: 1

Функции[]

Объявление функции:

function sqr(x:Number):Number { x * x };

println("sqr(3) = {sqr(3)}"); // output: sqr(3) = 9.0


Функции являются отдельным типом данных.

Например, переменной можно присвоить функцию:

var f = function(x:Number):Number {  x * x };

println("f(3) = {f(3)}"); // output: f(3) = 9.0

Класс может иметь атрибут типа функция:

class TaskManager{
    var task:function();
}


Функцию можно передавать в качестве аргумента другой функции

import java.lang.Math;

function f(x:Number):Number{ Math.cos(x) }

function integral( f: function(Number):Number, a:Number, b: Number, dx: Number):Number{
    var s = 0.0;
    for(x in [a..b step dx]){ 
        s += f(x) * dx;
    }
    s -= 0.5 * f(a) * dx + 0.5 * f(b) * dx;
    return s;
}

println( integral(f, -Math .PI / 2, Math.PI / 2, 0.01) );

Последовательности[]

Последовательность (Sequence) в языке JavaFX Script содержит в себе набор элементов одного и того же типа.

В языке JavaFX Script все последовательности одномерные.

Для того, чтобы задать последовательность, нужно перечислить ее элементы через запятую в квадратных скобках:

  var nums = [1,2,3,4,5];
  var strings = ["one", "two", "three"];

Квадратные скобки служат указанием, что объявляемый аттрибут является последовательностью:

class List{
    public var  items: String[];
}

var list = List{ items: ["item1", "item2", "item3"]  };


Последовательности можно вкладывать друг в друга, получая при этом один общую последовательность:

  var week_days = ["Mon","Tue","Wed","Thur","Fri"];
  var      days = [week_days, ["Sat","Sun"] ];

Результатом будет последовательность: ["Mon","Tue","Wed","Thur","Fri","Sat","Sun"];

Нумерация последовательностей производится от 0.

Получение элемента последовательности по индексу:

  var numbers = ["zero","one", "two", "three"];
  var n1 = numbers[1]; // n1 = "one"
  var n2 = numbers[2]; // n2 = "two"

Получение размера последовательности:

  var numbers = ["zero","one", "two", "three"];
  var size = sizeof numbers;  // size = 4


Выборка элементов последовательности:

var nums = [1,2,3,4,5];
println(nums[n|n > 2]); // [ 3, 4, 5 ]

Вставка и удаление элементов последовательности:

var seq = [1.0, 2.0, 3.0];

insert 1.5 after  seq[0];  // [1.0, 1.5, 2.0, 3.0]
insert 2.5 before seq[3];  // [1.0, 1.5, 2.0, 2.5, 3.0 ]

delete seq[4];

println(seq); // [ 1.0, 1.5, 2.0, 2.5 ]

Встроенные операции:

println( reverse nums ); // [ 5, 4, 3, 2, 1 ]

Итерация последовательности:

var seq = [1, 2, 3, 4, 5];


for(elem in seq){
    println(elem);
}


var sqrSeq = for(n in seq) { n * n };


Сортировка последовательности:

import javafx.util.Sequences;

var sequence = [ 5, 2, 3, 1, 4 ];

var sortedSequence = Sequences.sort(sequence) as Integer[];

println(sortedSequence); // [ 1, 2, 3, 4, 5 ]


Сортировка с помощью Comparator-а:

class Vector{
    public var x:Number;
    public var y:Number;

    public function length () {  Math.sqrt( x * x + y * y) }
    public override function toString ():String { "[ {x}, {y}]" }
}

var vectors = [ Vector{ x: 0 y: 2}, Vector{ x: 1 y: 0}, Vector{ x: 1 y: 1} ];


var sortedVectors = Sequences.sort(vectors, Comparator{
                public override function compare(obj1 : Object, obj2 : Object): Integer{
                    var v1 = (obj1 as Vector);
                    var v2 = (obj2 as Vector);
                    var delta = v2.length() - v1.length();
                    if (delta == 0 ) { 0 } else if ( delta < 0 ) { 1 } else { -1 } ;
                }
            }
        ) as Vector[];


println(sortedVectors); // [ [ 1.0, 0.0], [ 1.0, 1.0], [ 0.0, 2.0] ]

Описние устройства последовательностей:

http://per.bothner.com/blog/2009/JavaFX-sequence-basics
http://per.bothner.com/blog/2009/JavaFX-unboxed-sequences
http://per.bothner.com/blog/2009/JavaFX-sequence-updating
http://per.bothner.com/blog/2009/JavaFX-sequence-triggers


Перечисляемые типы[]

В языке JavaFX Script нет собственных перечислимых типов данных, но их можно использовать из Java.


Day.java

public enum Day {
    SUNDAY,
    MONDAY,
    // ...        
}


Использование перечислимого типа:

Main.fx

var day = Day.SUNDAY;

var days = Day.values();

for(d in days){
    println("day: {d}");
}

Операторы[]

Математические операции:

Оператор Описание Пример Использования
+ Сложить 2 + 3
- Вычесть 5 - 2
* Умножить 2 * 2
/ Разделить 10 / 5

Константы и переменные[]

Константы[]

Константы задаются с помощью ключевого слова def:

  def PI = 3.1415;


Переменные[]

Объявление переменной[]

Для объявления переменной используется синтаксис:

 var имя_переменной[:тип_переменной] [= значение]; 

Пример использования:

var radius = 10;
println("radius={radius}"); // результат: radius=10

var angle:Number = 45;
println("angle={angle}");  // результат: angle=45.0  // т.е angle имеет тип Number, а не Integer

Рекурсивное использование переменной[]

Иногда при создании объекта возникает необходимость тут же использовать его атрибуты или методы.


Например вы задаете окружность, а при нажатии мышкой на окружность нужно изменить ее цвет.

Чтобы код успешно скомпилировался в этом случае необходимо обязательно указывать тип определяемой переменной.

import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;

var circle:Circle = Circle{
    fill: Color.GREEN
    onMouseClicked: function (event){
        circle.fill = Color.BLUE;
    }
}

Использование переменной в дереве программы[]

Иногда небходимо обратится к объекту, который является частью дерева программы.

В этом случае можно определить переменную соответсвующего типа в начале программы а потом в дереве программе присвоить ей необходимый объект.

Пример того, как переменной присвоить компонент MediaPlayer, который задан в дереве программы:

var mediaPlayer: MediaPlayer;

MediaView {
    mediaPlayer: mediaPlayer = MediaPlayer { }
}


Подробный пример:

import javafx.scene.*;
import javafx.scene.media.*;
import javafx.scene.control.*;

var mediaPlayer: MediaPlayer;

Scene {
    content: [
        MediaView {
            mediaPlayer: mediaPlayer = MediaPlayer {
                media: Media {
                    source: "movie.avi"
                }
            }
        }
        Button {
            text: "Play"
            action: function () {
                mediaPlayer.play();
            }
        }
        Button {
            text: "Pause"
            action: function () {
                mediaPlayer.pause();
            }
        }
    ]
}

Классы[]

Объявление класса[]

public class Cat{
}

Объявление атрибутов и функций[]

public class Cat {
    var name:String;
    public function talk(): String { return "Meow!"; };
}


Статические атрибуты и функции объявляются вне класса:

public var quantity = 0;

public class Animal {
    init{ quantity++ }
}

Инициализация объекта[]

Инициализация атрибутов:

class Cat {
    var name:String = "Pushok";
}


Ининциализация объекта с помощью блока init:

class Cat {
    var name:String;

    init{
        name = "Pushok"
    }
}

var cat = Cat{ };
println("Cat name is {cat.name}"); // Cat name is Pushok

Ининциализация объекта с использованием триггеров:

class Cat{

    public var name: String on replace{
        if(name == null){ name = "unknown" }
    };

}

Cat{ };  // name: unknown

Абстрактные классы[]

Чтобы объявить абстрактный класс, нужно использовать ключевое слово abstract

например:

public abstract class Animal{
    public var name: String;
    public abstract function talk(): String;
}

Интерфейсы[]

В JavaFX нет интерфейсов как таковых, но зато позволяется расширять Java интерфейсы.

Наследование классов[]

Чтобы отнаследоваться от уже существующего класса, надо использовать ключевое слово extends

например:

public  class Dog extends Animal {
    override var name = "dog";
    public override function talk(): String { "Bark!"; };
}


Множественное наследование[]

В JavaFX можно создавать mixin классы. mixin классы, это абстрактные классы для которых разрешено множественное наследование.

например:

mixin class A{
}

Полный пример c использованием Классов[]

abstract class Animal{

    public var name: String = "unknown";

    public abstract function talk(): String;
    public override function toString () { name }

    init{
        println("[init] animal: {this}");
    }

}


class Cat extends Animal{
    override var name= "cat";
    override function talk(): String {  "Meow!"; };
}

class Dog extends Animal {
    override var  name = "dog";
    override function talk(): String {  "Bark!"; };
}


var cat = Cat {};  // output: [init]  animal: cat
var dog = Dog {};  // output: [init]  animal: dog



var mouse = Animal{
    name: "mouse"
    override function talk() {  return "Squeak!"; }
}
// output: [init]  animal: mouse


println("{cat}  : {cat.talk()}"  ); // output: cat  : Meow!
println("{dog}  : {dog.talk()}"  ); // output: dog  : Bark!
println("{mouse}: {mouse.talk()}"); // output: mouse: Squeak!

Функции[]

Объявление функции[]

Снтаксис объявления функции:

 function имя_фукции(список аргументов):тип_возвращаемого_значения { тело_фукции }


Функции в языке JavaFX Script позволяют как вычислить какое-нибудь значение, так и выполнить определенный набор действий.

Пример объявления функции:

  function square(x: Number):Number { x * x }
  function hello(name: String){
     System.out.println("Hello {name}!");
  }

Пример вызова функций:

  var a = square(2);
  println("square(3)={square(3)}"); // square(3)=9.0
  hello("Peter");  //  Hello Peter!

Рекурсивные функции[]

Так же можно определять рекурсивные функции:

 function factorial(n: Integer):Integer{
   return if ( n == 0 ) then { 1 } else { n * factorial(n - 1) }
 }
 println("factorial(5) = {factorial(5)}"); // factorial(5) = 120

Функция как самостоятельный тип данных[]

Функции в языке JavaFX Script являются отдельным типом данных. Их можно присваивать переменным:

var abs = function(x:Number):Number { if (x < 0 ) then -x else x }

println("abs( -3 ) = {abs( -3)}"); // abs( -3 ) = 3.0

Базовые конструкции[]

Оператор импорта import[]

import в JavaFX похож на import в Java, однако есть и сущесвенное отличие: import может встречатся в любом месте кода (не обязательно между package и class. В этом плане import напоминает required_once() из языка PHP.

  import javafx.scene.shape.Circle;

Кроме того, в интепретируемой версии языка JavaFX Script была интересная разновидность этого оператора, позволяющая импортировать класс и назначить ему синоним, под которым этот класс будет "виден":

  import java.awt.Color as AWTColor;
  import javafx.scene.paint.Color;

Таким образом в JavaFX решалась проблема использования классов с одинаковыми именами в Java (например, совместное использования java.util.Date и java.sql.Date). Такую же возможность планируется реализовать и в компилируемой версии языка JavaFX Script.

Block Expression[]

В фигурных скобках можно написать выражение, которое будет выполнено. Результат последнего выражения будет возвращен в качестве значения.

Например:

  println("2 * 3 = { 2 * 3 }");


Еще пример:

  var N = 5;
  var fact = {var n = 1; for(i in [1..N]){ n = i * n}  n };

Оператор связывания данных bind[]

В языке JavaFX определен оператор bind который позволяет связать переменную с определенным выражением. При этом изменение любой переменной из выражения также автоматически влечет изменение связанной с этим выражением переменной.

Синтаксис оператора:

 переменная = bind выражение 

Пример использования оператора bind:

function max(x:Number, y:Number):Number { if( x < y ) then y else x }

var a = 3;
var b = 4;
var maxAB = bind max(a,b);

println("max( {a}, {b} ) = {maxAB}"); // max( 3, 4 ) = 4.0

a = 5;

println("max( {a}, {b} ) = {maxAB}"); // max( 5, 4 ) = 5.0

b = 7;

println("max( {a}, {b} ) = {maxAB}"); // max( 5, 7 ) = 7.0

Как видно из примера, при изменении любой из переменных a или b автоматически изменяется и связанная с ними переменная maxAB

Триггеры[]

Триггеры (triggers) используются для того, чтобы по определенным событиям (например изменение переменной или атрибута класса) можно было исполнять необходимые пользователю действия.


Пример:

  var a = 10 on replace{ println("a: {a}"); } // output a: 10


Установка тригера для атрибута класса:

class A{
    var hello: String on replace{
        println("Hello {hello}!");
    }
}

var a = A{ hello: "World" }; //  Hello World!

Использование старого и нового значения атрибута:

class B{
    var num: Number on replace oldValue = newValue{
        println("old value {oldValue} has been changed to new value {newValue}");
    }
}


var b = B{ num: 10 }; // old value 0.0 has been changed to new value 10.0
b.num = 20;           // old value 10.0 has been changed to new value 20.0


Установка триггера для последовательности:

class C{
    var seq: Number[] on replace oldValue[a..b] = newValue{
        println("changed boundaries: [{a}..{b}]");
        println(oldValue);
        println(newValue);
    }
}


var c = C{ seq: [1, 2, 3] }; 
c.seq= [3, 2];   

Условная конструкция if[]

Формат конструкции:

  if (<условие>) then {
     выполняется последовательность действий, если условие верно
  } else 
    выполняется последовательность действий, если условие не верно
  }

Например фукция, которая вычисляет максимум двух чисел, может выглядеть следующим образом:

function max(x:Number, y:Number):Number{
    if( x < y ) then y else x
}

println (max(3,5));

Цикл for[]

Формат оператора:

for( <variable> in <sequence> ){
    // Тело цикла
}


Пример цикла, который повторяется 100 раз:

for (i in [1..100]){
   println("Iteration: {i}");
 }


Пример цикла, создающий 3 кнопки:

import javafx.scene.Group;
import javafx.scene.control.Button;

Group {
    content: for (text in ["Prevoius", "Home", "Next"]) Button { text: text }
}


Операция indexof позволяет определить индекс итерируемой переменной в теле цикла:

var animals = [ "cat", "dog", "mouse" ];

for(animal in animals){
    println("animals[{indexof animal}] = {animal}");
}

Результат исполнения программы:

animals[0] = cat
  animals[1] = dog
  animals[2] = mouse

Асинхронный вызов методов[]

Асинхронный вызов Java методов[]

http://blogs.sun.com/clarkeman/entry/javafx_async_task

MyRunnableFuture.java

import javafx.async.RunnableFuture;

public class MyRunnableFuture implements RunnableFuture{

    public void run() throws Exception {
        System.out.println("Call Java Methods!");
    }

}

Main.fx

import javafx.async.JavaTaskBase;
import javafx.async.RunnableFuture;


var task = JavaTaskBase{
    
    override function create():RunnableFuture{
        new MyRunnableFuture();
    }

}

task.start();

Асинхронный вызов JavaFX кода I[]

JavaRunnableFuture.java

import javafx.async.RunnableFuture;

public class JavaRunnableFuture implements RunnableFuture {

    RunnableFuture runnable;

    public JavaRunnableFuture(RunnableFuture runnable){
        this.runnable = runnable;
    }

    @Override
    public void run() throws Exception {
        System.out.println("Call Java Methods!");
        runnable.run();
    }
    
}


Main.fx

JavaTaskBase{
    override function create():RunnableFuture{
        new JavaRunnableFuture(
            RunnableFuture{
                override function run():Void  {
                    println("Call Java Methods!");
                }
            }
        );
    }

}.start();

Асинхронный вызов JavaFX кода II[]

AsyncProgramMoveImpl.java

import javafx.async.*;
import com.sun.javafx.runtime.async.*;


public class AsyncProgramMoveImpl extends AbstractAsyncOperation{
    RunnableFuture runnable;

    AsyncProgramMoveImpl(RunnableFuture runnable, AsyncOperationListener listener) {
        super(listener);
        this.runnable = runnable;
    }

    @Override
    public Object call() throws Exception {
        runnable.run();
        return null;
    }
}


JavaFXTaskBase.fx

import javafx.async.Task;
import javafx.async.RunnableFuture;
import com.sun.javafx.runtime.async.AsyncOperationListener;

import java.lang.Exception;


public class JavaFXTaskBase extends Task {

    var peer: AsyncProgramMoveImpl;

    public var action:function();

    public override function start() : Void{
     if (peer == null) {
          peer = new AsyncProgramMoveImpl(RunnableFuture{ override function run(){ action() } }, asyncListener );
          peer.start();
        }
    }

    public override function stop() : Void{
    }

    var asyncListener = AsyncOperationListener {
        public override function onProgress(progressValue:Integer, progressMax:Integer):Void {}
        public override function onCompletion(value:Object):Void {}
        public override function onCancel():Void {}
        public override function onException(e:Exception):Void{}
   }
}


Main.fx

import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.Button;

Stage {
    title: "Application title"
    scene: Scene {
        content: Button {
            text: "Asynch Operation"
            action: function() {
                JavaFXTaskBase{
                    action: function(){
                        while(true){
                            println("infinty loop!");
                        }
                    }
                }.start();
            }
        }
    }
}

Интеграция с языком Java[]

Использование Java классов[]

В языке JavaFX Script можно напрямую использовать любые классы из языка Java.

Пример использования класса java.util.Date:

Пример использования Картинка
import java.util.Date;
import javafx.ext.swing.*;


var date = new Date();

SwingFrame {
    title: "Calendar"
    width: 200
    height: 70
    content: FlowPanel {
        content: Label{ text: "Date: {%tF date}"  }
    }
    visible: true
}
Calendar

Реализация Java интерфейсов[]

Пример реализации и использования интерфейса FileFilter языка Java:

import java.io.*;

var imagesDir: File = new File ("resources");

var imageFiles: File[] = imagesDir.listFiles( FileFilter{
        override function accept(pathname:File){
            not pathname.getName().endsWith("Thumbs.db");
        }
    }
);


Пример реализации и использования интерфейса Runnable языка Java:

import java.lang.Thread;
import java.lang.Runnable;

var runnable = Runnable{
    public override function run () {
        println("Run...");
    }
}

new Thread(runnable).start();

Декларативный синтаксис[]

Дерево программы[]

import javafx.stage.*;
import javafx.scene.*;
import javafx.scene.shape.*;
import javafx.scene.paint.*;
import javafx.scene.shape.*;


Stage {
    title: "JavaFX Tree"
    scene: Scene {
        width: 300
        height: 300
        content: [
            Group{
                translateX: 50
                translateY: 100
                content:[
                    Rectangle{
                        width: 100
                        height: 100
                        fill: Color.BLUE
                    }
                    Circle{
                        radius: 50
                        fill: Color.GREEN
                    }
                ]
            }
            Group{
                translateX: 150
                translateY: 100
                rotate: 45
                content: [
                    Polygon {
                            points : [ 0,0, 100,0, 100,100 ]
                            fill: Color.ORANGE
                    }

                ]
            }

        ]
    }
}

Получение доступа к элементу в дереве программы[]

Связывание данных[]

import javafx.scene.*;
import javafx.scene.shape.*;
import javafx.scene.paint.*;
import javafx.scene.control.*;


var radius = 50.0;

Scene {
    width: 200
    height: 200
    content: [
        Slider {
            min: 10
            max: 100
            value: bind radius with inverse
        }
        Circle {
            centerX: 100, centerY: 100
            radius: bind radius
            fill: Color.ORANGE
        }
    ]
}

Получение объекта по имени переменной[]

import javafx.scene.*;
import javafx.scene.shape.*;
import javafx.scene.paint.*;
import javafx.scene.input.*;
import javafx.scene.control.*;


var circle:Circle;

Scene {
    width: 200
    height: 200
    content: [
        circle = Circle {
            centerX: 100
            centerY: 100
            radius: 40
            fill: Color.GREEN
            onMouseEntered: function( e: MouseEvent ):Void {
                circle.fill = Color.ORANGE;
            }
            onMouseExited: function( e: MouseEvent ):Void {
                circle.fill = Color.GREEN;
            }
         }
         Button{
            text: "Set Blue color"
            action: function(){
                circle.fill = Color.BLUE;
            }

         }

    ]
}

Получение объекта по id в дереве[]

import javafx.scene.*;
import javafx.stage.*;
import javafx.scene.layout.*;
import javafx.scene.control.*;

def stage : Stage = Stage {
    title: "Application title"
    width: 300
    height: 300
    scene: Scene {
        content: VBox {
            content: [
                Button {
                    text: "Set default text"
                    action: function() {
                        var t : TextBox = stage.scene.lookup("textBoxID") as TextBox;
                        t.text = t.promptText;
                    }

                }
                TextBox {
                    id: "textBoxID"
                    promptText: "First name"
                }

            ]
        }
    }
}

Каскадные Таблицы стилей[]

Более подробно о каскадных таблицах стилей можно узнать на страничке:


Язык JavaFX Script позволяет изменять свойства компонент программы не изменяя при этом саму программу. Для этого надо создать файл с расширение css и в нем описать имя компонента и его новое занчение свойства.

Например JavaFX Script программа рисует круг:

import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;

import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;

Stage {
    title: "Application title"
    scene: Scene {
        width: 200
        height: 200
        stylesheets: ["{__DIR__}Style.css"]
        content: Circle {
            centerX: 100
            centerY: 100
            radius: 50
            fill: Color.ORANGE
            stroke: Color.GREEN
        }
    }
} 

С помощью css файла можно поменять свойства этого круга, например прозрачность и цвет (файл Style.css):

Circle {
    opacity: 0.5;
    fill: yellow;
}

Локализация[]

Локализационные файлы[]

Файл: Main.fx

import java.util.Locale;
import javafx.ext.swing.SwingLabel;
import javafx.scene.Scene;
import javafx.stage.Stage;

Locale.setDefault(new Locale("ru"));

Stage{
    title: ##"Frame"
    scene: Scene{
        content: SwingLabel{
            text: ##"Hello"
        }
    }
    visible: true
}

Файл: Main_ru.fxproperties

 "Frame"="Окно"
 "Hello"="Привет"

Порядок слов в локализированной строке[]

Пусть нелокализованная строка в коде использует переменные:

var name1 = ##"Peter";
var name2 = ##"John";

var hello = ##"Hello {name1} and {name2}";

тогда строка в локализационном файле будет выглядеть следующим образом:

 "Peter"="Петр"
 "John"="Джон"
 "Hello %s and %s" = "Привет %s и %s"


Где "s" обозначает, что переменная передается в виде строки.

Если надо переменные вывести в другом порядке, тогда можно использовать номер переменной:

 "Hello %s and %s" = "Привет %2$s и %1$s"

Подробнее о способах форматированния данных можно изнать из документации по файлу java.util.Formatter


Storage API[]

Storage API позволяет хранить данные вашей программы локально на компьютере между запусками программы.

Запись данные в Storage:

import java.util.Date;

import javafx.io.Storage;
import javafx.util.Properties;

def storage = Storage {source: "myprogram.properties"};
def properties = new Properties();


properties.put("user", "admin");
properties.put("date", "{new Date()}");

storeConfig(storage, properties);



function storeConfig(storage:Storage, properties:Properties) {
    var outputStream = storage.resource.openOutputStream(false);
    properties.store(outputStream);
    outputStream.close();
}

Чтение данных из Storage:

import javafx.io.Storage;
import javafx.util.Properties;

def storage = Storage {source: "myprogram.properties"};
def properties = new Properties();


loadConfig(storage, properties);

println(properties.get("user"));
println(properties.get("date"));


function loadConfig(storage:Storage, properties: Properties) {
    var inputStream = storage.resource.openInputStream();
    properties.load(inputStream);
    inputStream.close();
}

Вопросы и ответы[]

Задайте интересующий вас вопрос по языку JavaFX Script

Advertisement