2007년 8월과 9월에 썬 개발자 네트워크의 John O'Conner는 JavaFX 스크립트 프로그래밍 언어(이 기사에서는 JavaFX 스크립트라고 줄여서 부름)를 시작하는 사용자에게 도움을 주고자 "학습 곡선 일지(Learning Curve Journal)"라는 제목의 시리즈를 기고했습니다.

그 이후로 이 언어의 많은 중요한 부분이 개선되었습니다. 아마도 가장 중요한 변화는 JavaFX 스크립트의 초기 인터프리터 기반 버전을 대신하여 컴파일러 기반 버전을 사용할 수 있게 되었다는 점입니다. 이전의 학습 곡선 일지에서는 인터프리터 기반 버전 사용에 대해 설명했습니다.

업데이트된 학습 곡선 일지에서는 컴파일러 기반 버전의 언어 사용법을 보여줍니다. 최신 내용을 반영하여 다른 변경 사항도 적용되었습니다.

지난 학습 곡선 기사에서는 간단한 사용자 인터페이스(UI)를 구현하고 UI 시험이 성공적이었음을 확인했습니다. 결과 JavaFX 스크립트는 Flickr에서 이미지를 검색하는 이미지 검색 애플리케이션 구축을 위한 원래 자바 프로그래밍 언어 UI와 비슷하게 보였습니다. 그림 1은 결과적인 기본 프레임을 보여줍니다.


그림 1. 원래 UI를 복제한 JavaFX 이미지 검색 애플리케이션

선언적 JavaFX 스크립트 구문을 사용한 결과 코드는 자바 언어 UI의 이식을 위한 괜찮은 시작이었습니다. 그러나 유휴 상태의 프레임, 응답하지 않는 검색 필드, 비활성 진행 표시줄, 빈 목록 상자 및 빈 이미지 레이블에 대한 추가 작업이 필요합니다. 여기에서는 아무 일도 발생하지 않습니다. 현재까지는 활성 데이터모델에 아무 UI 요소도 연결되지 않았으며 사용자 상호작용에도 응답하지 않습니다. 예를 들어 Search 텍스트 필드는 입력한 문자를 받아서 보여주지만 아직 아무 것도 하지 않습니다.

이 골격 뿐인 UI에는 추가 작업이 필요합니다. 이를 위해 비활성 애플리케이션에서 필요한 작업을 수행하도록 하는 함수가 필요합니다.


함수

JavaFX 스크립트 함수는 자바 프로그래밍 언어 메소드와 비슷합니다. 이들 메소드와 마찬가지로 함수는 매개 변수와 반환 값을 갖습니다. 또한 속성 및 변수와 if-then, while 루프, for 루프 및 기타 조건문도 가질 수 있습니다. 다음은 몇 가지 유효한 함수의 예입니다.


 
function z(a,b) {
      var x = a + b;
      var y = a - b;
      return sq(x) / sq (y);
  }

  function sq(n) {return n * n; }

  function main() {
      return z(5, 10);
  }

  function min(x1 : Number, x2 : Number ): Number {
      if (x1 < x2) {
        return x1;
      }
      else {
        return x2;
  }
 

반환 값 유형이나 매개 변수 유형을 선언할 필요가 없습니다. 그러나 자바 언어 프로그래머인 저에게는 min 함수에서와 같이 유형을 사용하는 것이 익숙하므로 가능한 경우에는 항상 사용하곤 합니다. 매개 변수 유형을 선언하는 것은 명확성에 도움이 됩니다. 따라서 z 함수를 다음과 같이 다시 작성하겠습니다.


function z(a: Number, b: Number): Number {
   var x: Number = a + b;
   var y: Number = a - b;
   return sq(x) / sq (y);
}
 


return 키워드는 선택 사항입니다.

   function sq(n) {n*n;}

위 함수는 다음과 같습니다.

   function sq(n) {return n*n;}

함수는 function 키워드로 시작합니다. 그 뒤에는 함수 이름과 매개 변수 목록이 나옵니다. JavaFX 스크립트에서는 유형이 변수나 함수 이름 다음에 나옵니다. 예를 들면 b: Number 매개변수는 b 라는 인수의 유형이 Number라는 의미입니다. 마지막으로 함수는 Number를 반환하므로 이를 매개 변수 목록 뒤에 선언할 수 있습니다. 함수의 본문 앞뒤에는 자바 언어에서 메소드 본문을 둘러싸는 것과 같이 괄호가 있습니다.

함수는 매개 변수나 기타 참조 변수가 변경될 때마다 반환 값을 재평가합니다. 이 기능은 개체를 자주 변경될 수 있는 특정 값에 바인드하려는 경우 유용합니다. 바인딩에 대해서는 나중에 자세히 설명하겠습니다.

클래스에 대해 함수가 정의될 수도 있습니다. 다음은 Friends 클래스에 대해 정의된 함수의 예입니다.


   import java.lang.System;
  import javafx.lang.Sequences;

  class Friends {
      attribute knownNames: String[];
      function sayHello(name: String): String {
          var index = Sequences.indexOf(knownNames,name);
          if (index >= 0) {
              return "Hello, {name}!";
              } else {
              return "Sorry, I can't talk to strangers.";
              }
      }
  }

  var buddies = Friends {
      knownNames: ["John", "Robyn", "Jack", "Nick", "Matthew",
      "Tressa", "Ruby"]
  };

  var greeting = buddies.sayHello("John");
  System.out.println(greeting);
 


이 작은 프로그램은 sayHello 메소드에 아는 이름을 입력하면 "Hello"라고 응답합니다. 그렇지 않은 경우엔 "can't talk to strangers"라고 합니다. Friends 클래스에는 한 가지 속성과 속성을 사용하여 메시지를 반환하는 함수가 포함되어 있습니다. Sequences 클래스를 사용하는 것에 유의합니다. 이 클래스는 시퀀스 조작을 위한 다양한 함수를 포함합니다. 시퀀스는 이 예제에서 아는 이름의 목록과 같이 개체의 순서별 목록을 나타냅니다. SequencesindexOf 함수는 지정된 시퀀스에서 같은 값을 갖는 개체를 검색합니다. 여기에서 indexOf는 아는 이름 시퀀스에서 지정된 이름(이 예제에서는 "John")과 매칭되는 개체를 검색합니다.


반응적 UI 요소

UI 요소(JavaFX 스크립트 라이브러리에서는 노드)는 키 입력이나 마우스 클릭과 같은 사용자 상호작용에 응답할 수 있습니다. 위젯은 action, onMouseClicked, onKeyTyped 및 기타 이벤트 기반 속성을 갖습니다. 이들 속성과 함수를 연관시킬 수 있습니다. 예를 들어 함수를 TextFieldaction 속성과 연관시키면 해당 함수는 필드 내에서 Enter를 누를 때 실행됩니다. Button 위젯의 동일한 action 속성은 사용자가 클릭할 때마다 활성화됩니다.

JavaFX 이미지 검색 애플리케이션과 관련된 함수가 필요하므로 UI 요소에 대한 이벤트 핸들러를 작성하기로 했습니다. 다음 애플리케이션은 두 개의 버튼과 하나의 레이블을 생성합니다. Bigger 버튼을 누르면 레이블의 글꼴 크기가 증가하고 텍스트가 변경됩니다. Smaller 버튼을 누르면 레이블의 글꼴 크기가 감소하고 텍스트가 변경됩니다.

이 애플리케이션에서는 계층 구조적인 Swing 기반 접근 방법을 따릅니다. 이 시리즈의 1편에서 언급한 것처럼 앞으로는 JavaFX 스크립트 개발자가 노드 기반 접근 방법을 사용하도록 할 것입니다.


   import javafx.ext.swing.SwingFrame;
  import javafx.ext.swing.BorderPanel;
  import javafx.ext.swing.FlowPanel;
  import javafx.ext.swing.Button;
  import javafx.scene.Font;
  import javafx.scene.HorizontalAlignment;
  import javafx.ext.swing.Label;

  var font = Font { size: 18 };

  class FontDataModel {
      attribute text: String;

      function increaseFontSize() {
         font = Font { size: font.size + 1 };
         text= "Font Test ({font.size})";
         }
      function decreaseFontSize() {
         font = Font { size: font.size - 1 };
         text= "Font Test ({font.size})";
      }
  }

  SwingFrame {
       var myFont = FontDataModel {
           text: "Font Test (18)"

       }

      content:
      BorderPanel {
          top: FlowPanel {
              alignment: HorizontalAlignment.LEADING
              content: [
                  Button { text:"Bigger"
                      action :
                      function() {
                           myFont.increaseFontSize();
                      }
              },

              Button { text:"Smaller"
                  action : function() {
                      myFont.decreaseFontSize();
                  }
              }

              ]
          }
          center:
              Label {
                  width: 200
                  font: bind font
                  text: bind myFont.text

          }

       }
       visible: true
  }
 

이 코드를 잘라내어 JavaFX 애플리케이션에 바로 붙여넣을 수 있습니다. Preview 버튼을 사용하면 그림 2의 결과가 보입니다.


그림 2. 미리보기 기능을 사용하여 JavaFX 스크립트 언어를 대화형으로 시험

이 Bigger-Smaller 글꼴 애플리케이션은 텍스트 문자열 속성을 갖는 FontDataModel을 생성합니다. 애플리케이션은 FontDataModel 인스턴스를 생성하고 text 속성을 초기화합니다. FontDataModel에도 increaseFontSizedecreaseFontSize라는 두 가지 함수가 있습니다. 이들 함수는 텍스트 속성을 변경하고 Font 클래스의 인스턴스를 생성하며 인스턴스의 글꼴 크기를 업데이트합니다.

왜 글꼴을 FontDataModel의 속성으로 지정하고 텍스트 속성과 같은 방법으로 함수에서 업데이트하지 않는지 궁금할 지도 모릅니다. 이러한 접근 방법은 Font가 변경할 수 없는 개체, 즉 원래 개체의 속성을 변경할 수 없기 때문에 사용할 수 없습니다. 개체의 인스턴스에서만 속성을 변경할 수 있습니다.

각 버튼은 연관된 함수를 포함하는 action 속성을 갖습니다. 예를 들어 Bigger 레이블이 있는 버튼은 myFont 변수의 increaseFontSize 함수를 호출합니다.


           
Button { text:"Bigger"
       action :
      function() {
           myFont.increaseFontSize();
      }
   
}
 

버튼을 누를 때마다 글꼴 크기와 텍스트가 변경되는 것을 볼 수 있습니다. 그림 3은 Bigger 버튼을 두 번 눌렀을 때의 결과를 보여줍니다.


그림 3. 버튼을 클릭하면 텍스트와 글꼴 크기 변경

분명히 increaseFontSize 메소드는 글꼴과 텍스트를 변경합니다. 이를 위해 바인딩이라는 JavaFX 스크립트 기능을 사용했습니다.


뷰와 모델 바인딩

JavaFX 스크립트에는 하나의 속성이 다른 속성의 변경을 추적하도록 하는 bind 연산자가 있습니다. 하나의 속성을 다른 속성에 바인딩한다는 것은 바인딩된 속성이 대상 속성의 변경 사항을 항상 인지한다는 것을 의미합니다. 이 Bigger-Smaller 글꼴 애플리케이션에서는 Label이 글꼴과 텍스트의 변경 사항을 추적하도록 하려고 합니다. 이를 위해 Labelfont 속성을 Font 변수에 바인드하도록 bind 연산자를 사용했습니다. 또한 Labeltext 속성을 FontDataModeltext 속성에 바인드하도록 bind 연산자를 사용했습니다.

다음은 Label 선언입니다.


 
Label {
      width: 200
      font: bind font
      text: bind myFont.text

  }
 

bind 연산자는 함수에도 사용할 수 있습니다. 함수는 인수나 참조 변수가 변경될 때마다 결과를 업데이트하므로 함수에의 바인딩은 단일 속성에의 바인딩과 마찬가지로 작용합니다. 사실 함수는 실제로 바인딩과 함께 사용하도록 설계되었습니다. 본문 내의 매개 변수 및 참조 변수를 모두 포함하는 모든 종속성을 자동으로 추적하는 재사용 가능한 하위 루틴으로의 바인딩을 리팩터링하기 위해 이들을 사용할 수 있습니다.

표 1에서 코드의 일부를 참조하십시오.

표1. 함수와 함께/함수 없이 바인드 사용
함수 없이 바인드
함수와 함께 바인드
   import java.lang.System;

class Data {
attribute foo: Number;
attribute baz: Number;
}

var data = Data {
foo: 4
baz: 7
};

var zoo = bind data.foo +
data.baz + 10;
System.out.println(zoo);
data.baz = 12;
System.out.println(zoo);
   import java.lang.System;

class Data {
attribute foo: Number;
attribute baz: Number;
function add(x, y, z): Number {
return x+y+z;
}
}

var data = Data {
foo: 4
baz: 7
};

var zoo = bind data.add(data.foo, data.baz, 10);
System.out.println(zoo);
data.baz = 12;
System.out.println(zoo);
출력:
21.0
26.0
출력:
21.0
26.0

요약

JavaFX 애플리케이션에 동작을 추가하기 위해 함수를 사용합니다. UI 구성요소의 속성은 함수에 매핑됩니다. action, onMouseClickedonKeyTyped와 같은 UI 이벤트 처리를 위해 이들 함수를 정의할 수 있습니다. 함수에는 함수 본문 내에서 매개 변수 및 참조 변수를 재평가하는 추가적인 등록 정보가 있습니다.

bind 연산자를 사용하여 하나의 속성을 다른 속성에 연결할 수 있습니다. 이는 UI 위젯이 모델 속성을 추적하도록 할 때 특히 유용합니다. 뷰 속성을 모델 속성에 바인딩한다는 것은 모델과 뷰가 동일한 데이터로 항상 동기화됨을 의미합니다.

JavaFX 이미지 검색 애플리케이션의 UI에 아직 기능을 추가하지 않았지만 함수가 필요하다는 것을 알게 되었습니다. 검색 텍스트를 가져오기 위해서는 거의 확실히 함수를 사용해야 합니다. 같은 함수가 이미지를 가져오기 위해 Flickr 사이트에도 액세스할 것입니다. 또한 뷰를 기본 모델에 연결하기 위해 bind 연산자도 사용해야 할 것입니다.

이제 UI를 일부 기본 작업 및 함수에 연결하는 방법을 알게 되었습니다. 또한 UI를 기본 모델에 연결하기 위해 bind 연산자도 사용할 수 있습니다.

자세한 정보
이 글의 영문 원본은
Learning Curve Journal, Part 3: JavaFX Script Functions
에서 보실 수 있습니다.
블로그 이미지

맨오브파워

한계를 뛰어 넘어서..........

,