반응형

이제 JavaFX SDK 기술 Preview가 릴리스되었으므로 자신만의 "사용자 지정 노드"를 빠르게 만드는 방법을 설명하겠습니다. JavaFX에서 사용자 지정 노드는 위젯, 가젯, UI 구성 요소 등 어느 것이나 모두 의미할 수 있으나 목적은 동일합니다. 다시 사용 가능한 JavaFX 프로그램용 UI를 만들 수 있도록 하는 것입니다. 오늘의 예는 사용자 지정 노드(2개)를 만드는 방법을 보여줍니다. 다음 스크린샷을 참조하십시오.

 

그런데 현재 이 예에 구현된 코드가 단순해진 것은 Edgar Merino 덕분입니다. 이 코드를 사용해보려면 Java Web Start 링크를 클릭하십시오. JRE 6 이상이 필요합니다. 또한 자바 SE 6 업데이트 10을 설치하면 배포 시간이 단축됩니다.



JavaFX SDK Packages are Taking Shape 게시물에서 언급한 것처럼 JavaFX는 UI를 개발할 때 그래픽 "노드 중심" 방식을 채택하고 있으므로 JavaFX 사용자 인터페이스의 거의 대부분은 노드(Node)입니다.  사용자 지정 노드를 만들려는 경우 CustomNode 클래스를 확장하여 원하는 특성과 동작을 지정합니다.  아래 코드는 이 예에서 이미지를 표시하고 마우스 이벤트에 응답(예: 마우스를 위에 갖다대면 좀 더 투명해지고 텍스트가 표시되는 이벤트)하는 사용자 지정 노드를 만드는 코드입니다. 

주: javafx.ext.swing 패키지에 있는 Button 클래스를 사용하지 않는 이유가 궁금하실 것입니다. 이유는 Button 클래스는 Node가 아니라 Component이기 때문이며, 위에 언급한 대로 노드 중심 방식으로 변화되는 방향을 따르는 것이 가장 좋다고 생각합니다. 어떤 부분에서는 노드를 하위 클래스로 만드는 버튼이 나타납니다. 이 경우에는 ButtonNode 클래스가 더 이상 필요하지 않을 수 있습니다.

ButtonNode.fx


/*
*  ButtonNode.fx -
*  A node that functions as an image button
*
*  Developed 2008 by James L. Weaver (jim.weaver at lat-inc.com)
*  and Edgar Merino (http://devpower.blogsite.org/) to demonstrate how
*  to create custom nodes in JavaFX
*/


package com.javafxpert.custom_node;

import javafx.animation.*;
import javafx.input.*;
import javafx.scene.*;
import javafx.scene.effect.*;
import javafx.scene.geometry.*;
import javafx.scene.image.*;
import javafx.scene.paint.*;
import javafx.scene.text.*;
import javafx.scene.transform.*;

public class ButtonNode extends CustomNode {
 
/**
   * The title for this button
   */

 
public attribute title:String;

 
/**
   * The Image for this button
   */

 
private attribute btnImage:Image;

 
/**
   * The URL of the image on the button
   */

 
public attribute imageURL:String on replace {
    btnImage
=
     
Image {
        url
: imageURL
     
};
 
}
   
 
/**
   * The percent of the original image size to show when mouse isn't
   * rolling over it.  
   * Note: The image will be its original size when it's being
   * rolled over.
   */

 
public attribute scale:Number = 0.9;

 
/**
   * The opacity of the button when not in a rollover state
   */

 
public attribute opacityValue:Number = 0.8;

 
/**
   * The opacity of the text when not in a rollover state
   */

 
public attribute textOpacityValue:Number = 0.0;

 
/**
   * A Timeline to control fading behavior when mouse enters or exits a button
   */

 
private attribute fadeTimeline =
   
Timeline {
      toggle
: true
      keyFrames
: [
       
KeyFrame {
          time
: 600ms
          values
: [
            scale
=> 1.0 tween Interpolator.LINEAR,
            opacityValue
=> 1.0 tween Interpolator.LINEAR,
            textOpacityValue
=> 1.0 tween Interpolator.LINEAR
         
]
       
}
     
]
   
};

 
/**
   * This attribute is interpolated by a Timeline, and various
   * attributes are bound to it for fade-in behaviors
   */

 
private attribute fade:Number = 1.0;
 
 
/**
   * This attribute represents the state of whether the mouse is inside
   * or outside the button, and is used to help compute opacity values
   * for fade-in and fade-out behavior.
   */

 
private attribute mouseInside:Boolean;

 
/**
   * The action function attribute that is executed when the
   * the button is pressed
   */

 
public attribute action:function():Void;
   
 
/**
   * Create the Node
   */

 
public function create():Node {
   
Group {
     
var textRef:Text;
      content
: [
       
Rectangle {
          width
: bind btnImage.width
          height
: bind btnImage.height
          opacity
: 0.0
       
},
       
ImageView {
          image
: btnImage
          opacity
: bind opacityValue;
          scaleX
: bind scale;
          scaleY
: bind scale;
          translateX
: bind btnImage.width / 2 - btnImage.width * scale / 2
          translateY
: bind btnImage.height - btnImage.height * scale
          onMouseEntered
:
           
function(me:MouseEvent):Void {
              mouseInside
= true;
              fadeTimeline
.start();
           
}
          onMouseExited
:
           
function(me:MouseEvent):Void {
              mouseInside
= false;
              fadeTimeline
.start();
              me
.node.effect = null
           
}
          onMousePressed
:
           
function(me:MouseEvent):Void {
              me
.node.effect = Glow {
                level
: 0.9
             
};
           
}
          onMouseReleased
:
           
function(me:MouseEvent):Void {
              me
.node.effect = null;
           
}
          onMouseClicked
:
           
function(me:MouseEvent):Void {
              action
();
           
}
       
},
        textRef
= Text {
          translateX
: bind btnImage.width / 2 - textRef.getWidth() / 2
          translateY
: bind btnImage.height - textRef.getHeight()
          textOrigin
: TextOrigin.TOP
          content
: title
          fill
: Color.WHITE
          opacity
: bind textOpacityValue
          font
:
           
Font {
              name
: "Sans serif"
              size
: 16
              style
: FontStyle.BOLD
           
}
       
},
     
]
   
};
 
}
}  



위의 ButtonNode.fx 코드 목록에서는 다음 내용을 짚고 넘어가겠습니다.

  • ButtonNode 클래스는 CustomNode를 확장합니다.
  • 이 새로운 클래스는 사용자 지정 노드에 표시될 이미지와 텍스트를 저장하는 속성을 채용합니다.
  • create() 함수는 사용자 지정 노드의 UI 모양과 동작에 관한 선언 표현식을 반환합니다.
  • javafx.scene.effect 패키지의 Glow 효과는 이미지를 클릭할 경우 이미지에 빛나는 효과를 줄 때 사용됩니다.
  • 이미지의 투명도, 이미지의 크기, 사용자 지정 노드의 제목은 마우스를 누르거나 버튼을 놓을 때 전환됩니다. Timeline은 이러한 전환이 점진적으로 이루어지도록 하는 데 사용됩니다.
  • 투명도를 조정하고 Glow 효과를 적용한 후에 onMouseClicked 함수가 목록의 앞 부분에 정의된 action() 함수 속성을 호출합니다. 그러면 사용자 지정 노드가 Button과 유사하게 동작합니다.

"메뉴"에 ButtonNode 인스턴스 배열

Setting the "Stage" for the JavaFX SDK 게시물에서 설명한 것처럼 HBox 클래스는 javafx.scene.layout 패키지에 있으며, 이 패키지 안의 다른 노드를 배열하는 노드입니다. 아래와 같은 MenuNode 사용자 지정 노드는 ButtonNode 인스턴스를 수평으로 배열하고, javafx.scene.effects 패키지의 Reflection 클래스는 해당 버튼 아래에 멋진 반사 효과를 추가합니다. 코드는 다음과 같습니다.

MenuNode.fx

/*
 *  MenuNode.fx -
 *  A custom node that functions as a menu
 *
 *  Developed 2008 by James L. Weaver (jim.weaver at lat-inc.com)
 *  to demonstrate how to create custom nodes in JavaFX
 */


package com.javafxpert.custom_node;
 
import javafx.scene.*;
import javafx.scene.effect.*;
import javafx.scene.layout.*;

public class MenuNode extends CustomNode {

 
/*
   * A sequence containing the ButtonNode instances
   */

 
public attribute buttons:ButtonNode[];
   
 
/**
   * Create the Node
   */

 
public function create():Node {
   
HBox {
      spacing
: 10
      content
: buttons
      effect
:
       
Reflection {
          fraction
: 0.50
          topOpacity
: 0.8
       
}
   
}    
 
}
}  


사용자 지정 노드 사용

이제 사용자 지정 노드를 정의했으므로 간단한 프로그램에서 이 노드를 사용하는 방법을 보여드리겠습니다. 이 블로그를 따라해보신 분은 "JavaFX가 UI와 모델을 바인딩하는 방식"을 알게 되었을 것입니다. 이 간단한 예에서는 사용자 지정 노드를 만드는 방법을 알리는 데 중점을 두기 때문에 모델을 만들어서 이 모델에 UI를 바인딩하는 복잡한 작업까지 보여드리지는 않겠습니다. 대신, ButtonNode 인스턴스를 클릭할 때마다 문자열을 콘솔에 인쇄하는 간단한 작업을 보여드리겠습니다. 이번 예의 기본 프로그램의 코드는 다음과 같습니다.

MenuNodeExampleMain.fx

/*
 *  MenuNodeExampleMain.fx -
 *  An example of using the MenuNode custom node
 *
 *  Developed 2008 by James L. Weaver (jim.weaver at lat-inc.com)
 *  to demonstrate how to create custom nodes in JavaFX
 */

package com.javafxpert.menu_node_example.ui;

import javafx.application.*;
import javafx.scene.paint.*;
import javafx.scene.transform.*;
import java.lang.System;
import com.javafxpert.custom_node.*;

Frame {
 
var stageRef:Stage;
 
var menuRef:MenuNode;
  title
: "MenuNode Example"
  width
: 500
  height
: 400
  visible
: true
  stage
:
    stageRef
= Stage {
      fill
: Color.BLACK
      content
: [
        menuRef
= MenuNode {
          translateX
: bind stageRef.width / 2 - menuRef.getWidth() / 2
          translateY
: bind stageRef.height - menuRef.getHeight()
          buttons
: [
           
ButtonNode {
              title
: "Play"
              imageURL
: "{__DIR__}icons/play.png"
              action
:
               
function():Void {
                 
System.out.println("Play button clicked");
               
}
           
},
           
ButtonNode {
              title
: "Burn"
              imageURL
: "{__DIR__}icons/burn.png"
              action
:
               
function():Void {
                 
System.out.println("Burn button clicked");
               
}
           
},
           
ButtonNode {
              title
: "Config"
              imageURL
: "{__DIR__}icons/config.png"
              action
:
               
function():Void {
                 
System.out.println("Config button clicked");
               
}
           
},
           
ButtonNode {
              title
: "Help"
              imageURL
: "{__DIR__}icons/help.png"
              action
:
               
function():Void {
                 
System.out.println("Help button clicked");
               
}
           
},
         
]
       
}
     
]
   
}
}

앞서 언급한 대로 사용자가 해당 ButtonNode를 마우스로 클릭할 때마다 호출된 함수에 action 속성이 할당됩니다. 그리고 __DIR__ 표현식은 CLASS 파일이 있는 디렉토리로 평가됩니다. 이 경우 그래픽 이미지는 com/javafxpert/menu_node_example/ui/icons 디렉토리에 있습니다.

이 기사의 이미지를 다운로드한 후 이 그래픽으로 이 예에서 소개한 대로 작성하고 실행할 수 있습니다. 이 이미지는 프로젝트의 클래스 경로에서 확장할 수 있는 zip 파일입니다.

이 파일은 JavaFX SDK Technology Preview에 유용한 사용자 지정 노드 라이브러리를 작성하여 이 블로그의 JFX Custom Nodes 카테고리에 게시하기 위해 만든 것입니다. 사용자 지정 노드와 관련하여 아이디어가 있거나 자신이 개발한 사용자 지정 노드를 공유하려면 lat-inc.com의 jim.weaver로 연락해주십시오.

이 게시물을 실행한 후에 Weiqi Gao가 Java WebStart Works On Debian GNU/Linux 4.0 AMD64 게시물에 몇 가지 좋은 소식을 올렸습니다. JavaFX 스크립트 설명서의 기술 검토를 훌륭하게 해주셔서 저는 Weiqi(발음: 웨이치) 씨가 매우 좋습니다. ;-)

감사합니다.
Jim Weaver
JavaFX Script: Dynamic Java Scripting for Rich Internet/Client-side Applications

지금 바로 the book's Apress site에서 eBook(PDF)을 다운로드할 수 있습니다.

이 글의 영문 원본은
Rolling Your Own JavaFX "Custom Nodes": A Graphical Menu Example
에서 보실 수 있습니다.

반응형
http://www.javapassion.com/handsonlabs/javafxdraggableapplets/index.html

가장 흥미로웠던 부분이다. JAVAFX에 관한 관심을 증폭시킬만한 데모이니 한번 따라해보세요
반응형
제공 : 한빛 네트워크
저자 : Anghel Leonard
역자 : 김인희
원문 : Introduction to JavaFX Script


JavaFX 갖고 놀기

이 절에서는, JavaFX의 다양한 특징과 가능성을 엿볼 수 있는 몇 가지 예제를 보도록 하겠다. 예제들을 보여주는 이유는, 첫 번째로 JavaFX 코드 작성과 JavaFX 응용프로그램의 논리적 구조에 익숙해지도록 하기 위함이다. 두 번째로는 단지 몇 줄의 코드만으로 GUI, 애니메이션을 멋지게 만들거나 세련된 효과를 넣고 싶을 때, JavaFX가 시간을 들여 자세히 볼 만큼의 가치가 있다는 것을 알려주고 싶었기 때문이다. 여기서 소개하는 모든 예제들은 JavaFX만의 독특한 기술들을 포함하고 있다.

예제에 대한 간략한 설명을 한 후에 소스 코드를 보여주는 방식으로 진행할 것이고, 모든 예제가 혼자서 할 수 있는 정도로 쉽기 때문에 코드에 대한 설명을 따로 하지는 않았다.

System.out.println의 따옴표 안에 변수나 속성의 이름을 넣으면, 해당 값을 출력할 수 있다.

[예제 2]
//expressions within quoted text
import java.lang.System;
var mynumber:Number = 10;
System.out.println("Number is: {mynumber}");

결과 - Number is: 10
JavaFX는 변수의 집합 원소 개수(cardinality)를 표시하기 위해, 다음과 같이 세가지 연산자를 지원한다.
l	?: 선택 (null값일 수도 있다)
l	+: 1 또는 그 이상
l	*: 0 또는 그 이상
[예제 3]
//cardinality of the variable
import java.lang.System;
var mynumbers:Number* = [1,2,7];
System.out.println("Numbers are: {mynumbers}");

결과 – Numbers are: 1 2 7
JavaFX에서는 타입을 지정하지 않고 변수 선언을 할 수가 있다. JavaFX가 자동으로 변수의 값에 해당하는 타입을 지정하기 때문에, 이러한 방식이 허용된다.

[예제 4]
//the variable's type is optional
import java.lang.System;
var days = ["Monday,","Friday,","Sunday"];
System.out.println("You have to work: {days}");

결과 – You have to work: Monday, Friday, Sunday
sizeof 연산자를 사용하여 배열의 크기를 구할 수 있다.

[예제 5]
//getting the size of an array
import java.lang.System;
var lotto = [21,30,11,40,5,6];
System.out.println("Array size:{sizeof lotto}");

결과 – Array size: 6
어떤 특정한 조건을 만족시키는 부분 배열(subarray)을 얻기 위해 [] 연산자를 사용한다. 조건문은 []사이에 넣으며, 조건문의 결과는 Boolean이다. 이 방식은 Xpath의 조건 서술부(predicate)와 유사하다.

[예제 6]
//using the [] operator - similar to its use in XPath
import java.lang.System;
var mynumbers = [1,2,7,3,30,15,14,6,4];
var numbers = mynumbers[n|n < 10];
System.out.println("Numbers smaller that 10 are: {numbers}");

결과 – Numbers smaller than 10 are: 1 2 7 3 6 4
indexof 연산자로 배열에 있는 특정 요소의 순서 위치를 구할 수 있다.

[예제 7]
//returning the ordinal position of an element within an array
import java.lang.System;
var mynumbers = [1,2,7,3,30,15,14,6,4];
var number_four = mynumbers[indexof . == 4];
System.out.println("Number four:{number_four}");

결과 – Number four: 30
배열에 요소를 넣기 위해서 다음 중에 하나를 선택해서 insert문을 작성한다
l	as first: 배열의 첫 번째 위치에 넣는다
l	as last: 배열의 마지막 위치에 넣는다 (기본 설정값)
l	before: 특정 위치 앞에 넣는다
l	after: 특정 위치 뒤에 넣는다
delete문으로 배열 내에 한 요소를 삭제할 수 있다.

[예제 8]
//insert and delete statement
import java.lang.System;
var mynumbers = [1,2,7];
System.out.println("Before inserting anything:
    {mynumbers}");
insert 10 into mynumbers;
System.out.println("After inserting at the end
    the "10" value:{mynumbers}");
insert [8,6,90] as first into mynumbers;
System.out.println("After inserting at the first
    positions the "8,6,90" values:{mynumbers}");
insert 122 as last into mynumbers;
System.out.println("After inserting at the
    end the "122" value:{mynumbers}");
insert 78 before mynumbers[3];
insert 11 after mynumbers[3];
System.out.println("After inserting the "78"
    and "11" values before/after the 3rd
    element:{mynumbers}");
delete mynumbers[. == 122];
System.out.println("After deleting:{mynumbers}");

결과:
Before inserting anything: 1 2 7
After inserting the 10 value at the end: 1 2 7 10
After inserting the 8, 6, and 90 values at the first positions: 8 6 90 1 2 7 10
After inserting the 122 value at the end: 8 6 90 1 2 7 10 122
After inserting the 78 and 11 values before/after the 3rd element: 8 6 90 78 11 1 2 7 10 122
After deleting: 8 6 90 78 11 1 2 7 10
JavaFX에서 select와 foreach 연산자로 리스트 내장(list comprehensions)을 구현할 수 있으며, 이 기능은 꽤 유용하다. 다음 (각각 select와 foreach를 사용한) 두 예제는 특정 간격마다 홀수를 찾는다.

[예제 9]
//JavaFX select and foreach operators
import java.lang.System;
function odd(p:Number) {
    return select i from i in [1.0 ..p]
        where (i%2 == 1.0);
    }
var result = odd(10.0);
System.out.println("Odd numbers:{result}");

결과 – Odd Number: 1.0 3.0 5.0 7.0 9.0
[예제 10] (select 대신에 foreach 사용)
//JavaFX select and foreach operators
import java.lang.System;
function odd(p:Number) {
    return foreach (i in [1.0 ..p] where (i%2 == 0.0)) i;
    }
var result = odd(10.0);
System.out.println("Odd numbers:{result}");
다음 예제는 foreach로 얼마나 멋진 효과를 낼 수 있는지를 보여준다.

[예제 11]
//JavaFX select and foreach operators
import java.lang.*;
import javafx.ui.*;
import javafx.ui.canvas.*;
Frame {
    centerOnScreen: true
    visible: true
    height: 500
    width: 500
    title: "Foreach demo..."
    onClose: operation() {System.exit(0);}
    content: ScrollPane {
    background: white
    view: Canvas {
        content: bind foreach (i in [1..8], j in [1..8])
        Rect {
        x: i*30
        y: j*30
        width:30
        height:30
        fill: Color {red: (100+i) green: (100+j) blue: (100+(i*j))}
        stroke:white
        strokeWidth:1
        }
    }
    }
}

[그림 4] 예제 11 실행 결과

JavaFX 키워드와 같은 이름의 변수나 속성을 사용하려면, 다음과 같이 이중 괄호(double angle)사이에 이름을 넣으면 된다.

[예제 12]
//Identifier quotes
import java.lang.System;
for (<> in [0..3]) {
    System.out.println("for = {<>}");
    }

결과 – for = 0 for =1 for=2 for=3
JavaFX는 Swing 인터페이스 개발시에 코드의 수를 획기적으로 줄어주며, javax.swing.* 패키지와도 궁합이 잘 맞기 때문에 상당히 좋은 툴이라 할 수 있다. 앞 장(NetBeans5.5 용 JavaFX 플러그인을 사용한 Hello World 프로그램 작성)에서, 얼마나 손쉽게 간단한 프레임을 만들었는지 이미 경험을 했을 것이다. 다음으로 버튼(Button)과 텍스트 필드(TextField)를 생성하는 두 예제를 보도록 하자.

[예제 13]
import javafx.ui.*;
import java.lang.System;
Frame{
    content: Button {
    text: "Exit"
    action: operation() {
    System.exit(0);
    }
    }
    visible: true
}

[그림 5] 예제 13 실행 결과

[예제 14]
import javafx.ui.*;
Frame {
    content: GroupPanel {
    var myRow = Row { alignment: BASELINE }
    var label_col = Column { alignment: TRAILING }
    var field_col = Column { alignment: LEADING  }
    rows: [myRow]
    columns: [label_col, field_col]
    content:
    [SimpleLabel {
    row: myRow
    column: label_col
    text: "Type your text here:"
    },
    TextField {
    row: myRow
    column: field_col
    columns: 50
    }]
    }
    visible: true
};

[그림 6] 예제 14 실행 결과

Java.net에서 JavaFX로 Swing 인터페이스 만들기에 관한 튜토리얼을 찾을 수 있다.
반응형
제공 : 한빛 네트워크
저자 : Anghel Leonard
역자 : 김인희
원문 : Introduction to JavaFX Script

JavaFX는 무엇인가?

2007년 봄, 썬은 JavaFX라 불리는 새로운 프레임워크를 발표했다. JavaFX는 두 가지 중요한 컴포넌트인 스크립트 컴포넌트와 모바일 컴포넌트를 아우르는 일반적인 용어이며, 향후에 썬은 더 많은 컴포넌트들을 추가할 계획이다.

JavaFX의 핵심 컴포넌트는 선언형 언어인 JavaFX 스크립트(Script)이며, 코드 스타일은 자바와 상당히 다르지만 자바 클래스와 상호 작용하는 능력은 뛰어나다. 수 많은 JavaFX 스크립트 클래스들은 스윙이나 자바 2D 기능들을 손쉽게 구현할 수 있도록 설계되었다. 단지 몇 줄의 코드만으로 GUI와 애니메이션을 보여주거나 텍스트와 그래프에 화려한 효과를 넣을 수 있다. 또 다른 기능으로, JavaFX 스크립트에 자바와 HTML 코드를 넣을 수도 있다.

또 다른 컴포넌트인 JavaFX 모바일(Mobile)은 휴대용 기기에 들어가는 자바 응용프로그램 개발을 위한 플랫폼이다. JavaFX 모바일은 JavaFX 스크립트가 사용될 최대 플랫폼이 될 예정이지만, 아직은 이 기사의 내용과는 크게 관련이 없다.

JavaFX 응용프로그램 예제

새로운 언어를 배우기에 앞서, 몇 가지 JavaFX 코드 예제들을 살펴보도록 하자. JavaFX 공식 사이트는 예제를 얻기 위한 좋은 정보처이며, JavaFX 스크립트 2D 그래픽스 튜토리얼을 클릭하면 몇 가지 예제들을 포함한 tutorial.jnlp 파일을 다운받을 수 있다. 이 파일을 더블 클릭하면 [그림 1]과 같은 프로그램이 실행된다. (프로그램이 실행되지 않는다면, 자바 웹스타트에서 .jnlp 확장자 파일이 실행되도록 설정해야 한다.)


[그림 1] tutorial.jnlp 튜토리얼 파일 실행

tutorial.jnlp에 포함된 예제와 코드들을 천천히 살펴보면, 단지 몇 줄의 코드만으로 다양하고 흥미로운 그래픽 효과를 얻을 수 있음을 알게 될 것이다.

JavaFX가 과연 유용한 것인가 여전히 의문이 가는 독자라면, OpenJFK 프로젝트에서 Studiomoto와 Tesla Motors 사이트를 부분적으로 재현한 두 가지 데모(JavaFX Script Studiomoto Demo, JavaFX Script Tesla Demo)를 다운받아 보길 바란다. 데모를 실행하기 위해서는 자바 웹스타트가 필요하며, 컴퓨터 설정에 따라 자동적으로 실행될 수 있지만 그렇지 않다면 다운받은 .jnlp 파일을 직접 실행시켜야 한다.

JavaFX 다운로드와 설치

JavaFX 응용프로그램 개발을 배우기 원하는가? 그렇다면 우선 JavaFX로 작업하는데 최소한 3가지 방법이 있으며, JavaFX 응용프로그램은 브라우저 기반이 아니라는 사실을 염두에 두도록 하자. 첫번째로, JavaFXPad라는 가벼운 툴을 사용하는 것이 가장 쉽고 빠른 방법이다. 이 툴의 가장 큰 장점은 에디터에서 작업한 코드의 결과를 바로 볼 수 있다는 점이다. OpenJFK 프로젝트의 JavaFX 스크립트 JavaFXPad 데모를 클릭하면 JavaFXPad를 다운받을 수 있다. 거듭 말하지만, 자바 웹스타트가 있어야 해당 파일을 실행할 수 있다. ([그림 2]를 보자)


[그림 2] JavaFXPad 에디터 실행

또 다른 방법으로, NetBeans 5.5용 JavaFX 스크립트 플러그인(Plug-in)이나 Eclipse 3.2용 JavaFX 스크립트 플러그인(Plug-in)을 사용하는 방법이 있다. (물론, 이 플러그인들을 설치하기 전에 NetBeans 5.5나 Eclipse 3.2를 미리 설치해야 한다)

NetBeans 5.5용 JavaFX 플러그인을 사용하기로 했다면, OpenJFK 프로젝트에 있는 NetBeans용 JavaFX 문서가 많은 도움이 될 것이다. 마찬가지로, Eclipse용 JavaFX 플러그인을 선택했다면 Eclipse용 JavaFX를 방문해 보길 바란다. 앞으로 설명할 모든 예제는 NetBeans 5.5용 JavaFX 플러그인에서 테스트 하였지만, 다른 환경에서도 잘 돌아갈 것이다.

NetBeans 5.5용 JavaFX 플러그인을 사용한 Hello World 프로그램 작성

새로운 언어를 배울 때 처음으로 작성하게 되는 것이 Hello World 프로그램일 것이다.

[예제 1]
import javafx.ui.*;
import java.lang.System;
Frame {
    centerOnScreen: true
    visible: true
    height: 50
    width: 350
    title: "HelloWorld application..."
    background: yellow
    onClose: operation() {System.exit(0);}
    content: Label {
        text: "Hello World"
        }
    }
NetBeans 5.5에서 다음과 같은 순서로 이 간단한 예제를 작성하고 실행할 수 있다.
  • NetBeans 5.5를 실행한다.
  • 메인 메뉴의 File에 있는 New Project를 선택한다.
  • New Project 창의 Category에서 General을, Projects에서 Java Application을 선택한다. (Next를 클릭한다)
  • New Java Application 창에서 Project Name에 “FXExample”라고 넣는다.
  • Browse 버튼을 클릭하여 프로젝트의 위치를 지정한다.
  • “Set as main project”와 “Create main class” 체크박스는 해제한다. (Finish를 클릭한다)
  • FXExample에 있는 Source Packages에서 오른쪽 마우스를 클릭한 후에, New에 있는 File/Folder를 선택한다.
  • New File 창의 Categories에서 Other를, File Types에서 JavaFX File을 선택한다.
  • New JavaFX File 창에서 File Name에 “Hello World”를, Folder에는 “src’를 넣는다.
  • 예제 1의 코드를 복사해서 HelloWorld.fx에 넣는다.
  • FXExample 프로젝트를 오른쪽 마우스 클릭하고 Properties를 선택한다.
  • Project Properties의 FXExample에서, Categories에 있는 Run를 선택한다.
  • Arguments 텍스트 필드에 “Hello World”를 넣는다. (OK를 클릭한다)
  • FXExample 프로젝트를 오른쪽 마우스 클릭하고 Run Project를 선택한다.
지금까지 아무런 문제가 없었다면, [그림 3]과 같은 프레임을 확인할 수 있을 것이다.


[그림 3] NetBeans 5.5로 Hello World 프로그램 실행

이제 여러분은 JavaFX 응용프로그램을 개발하고 실행할 수 있는 소프트웨어 환경을 갖추게 되었다.

JavaFX 구문

JavaFX를 시작하기에 앞서, JavaFX 구문의 몇 가지 우수한 점들에 대해 알아보도록 하자. 자바 언어 구문에 대해 잘 알고 있는 독자라면, JavaFX 구문이 자바와 매우 비슷하면서도 한편으로 몇몇 부분은 상당히 다르다고 생각할 것이다.

JavaFX 데이터형

JavaFX는 4가지 데이터형을 지원한다: String (java.lang.String와 대응), Boolean (java.lang.Boolean과 대응), Number (java.lang.Number와 대응), Integer (byte, short, int, long, BigInteger와 대응)

JavaFX 변수

JavaFX 변수는 var 키워드로 선언하며 다음과 같이 사용한다.
var x:Number = 0.9;
var name:String = "John";
var y:Integer = 0;
var flag:Boolean = true;

var numbers:Number = [1,2,3,4,5];
JavaFX 연산자

여러분이 잘 알고 있는 자바 연산자 &&, ||, !는 JavaFX에서 다음과 같이 바뀐다.
l	Java: &&
JavaFX: and 
l	Java: ||
JavaFX: or 
l	Java: !
JavaFX: not
JavaFX 함수

JavaFX는 함수를 지원한다. 다음 예제는 인수, 변수 선언, 리턴문으로 구성된 간단한 함수이다.
function taxes(x) {
    var t:Number = (19.0/100.0)*x;
    return t;
    }
JavaFX – if문

if문을 사용해 조건 블록(block)을 설정하며, 중괄호 사용은 필수이다. 만약 else절이 또 다른 if문이라면 중괄호를 생략할 수 있다.
if (place_your_condition_here) {
        //do something
    } else if (place_your_condition_here) {
        //do something
    } else {
        //do something
    }
JavaFX – while문

자바의 while 문과 유사하며 중괄호 사용은 필수다.
while (place_your_condition_here)
    {
    //do something
    }
JavaFX – for문

일정 간격마다 반복하는 for문을 만들 수 있다. ( [] 괄호와 .. 기호로 간격 범위를 설정한다. )
//i will take the values: 0, 1, 2, 3, 4, 5
for (i in [0..5])
    {
    //do something with i
    }
JavaFX 프로시저

다음과 같이 JavaFX 프로시저 앞에 operation 키워드를 붙인다.
operation startClock() {
do{
    while(true)
        {
        if(seconds>=360)
    {seconds = 0; seconds = [0,6..360] dur 60000 linear;}
        if(minutes>=360)
    {minutes = 0; minutes = [0,6..360] dur 3600000 linear;}
        if(hours>=360)
    {hours = 0; hours = [0,6..360] dur 43200000 linear;}
        }
    }
}
JavaFX 클래스

JavaFX 클래스 앞에 class 키워드를 넣는다. JavaFX 클래스는 extends 키워드와 클래스 이름 사이에 콤마를 넣어 다수의 클래스들을 상속받을 수 있다. 다음 Order 클래스에는 속성, 함수, 프로시저가 있으며 중괄호 사이에 놓여있다.
class Order {
    attribute order_nr: String;
    attribute ordertype: Order inverse Order.products;
    attribute products: Order* inverse Order.ordertype;
    function getOrderNr(): String;
    operation addOrder(order: Order);
    }
속성은 attribute 키워드로 선언하며, 함수와 프로시저의 바디(body)는 클래스의 바디(body)에 포함되지 않는다. 앞으로 보게 되겠지만, 함수와 프로시저의 구현은 클래스를 선언한 후에 이루어진다.

inverse 옵션은 한 속성과 그 속성이 속한 클래스의 다른 속성과의 양방향 관계를 나타낸다. 이 경우에, JavaFX는 삽입, 수정, 삭제와 같은 업데이트를 자동으로 수행한다.

Java.net에서 더 자세한 정보를 얻을 수 있다.
반응형
 

plug-in 설치

eclipse에서 JavaFX를 사용하려면 다음과 같은 순서로 plug-in을 설치한다.

  1. Help -> Software Updates -> Find & Install
  2. Search for new features to install -> Next
  3. New Remote Site
  4. Name: javaFX URL: http://download.java.net/general/openjfx/plugins/eclipse/site.xml
  5. Finish

그 다음부터는 Next만 계속 눌러주면 된다.

새 파일 만들기

File -> New -> Others -> JavaFX -> JavaFX file 후 원하는 프로젝트를 선택하고 파일명을 써넣는다.

실행하기

Run -> Run... -> JavaFX Application -> Project: 해당 프로젝트 이름 -> Arguments 탭 -> Program arguments: JavaFX 파일명(확장자 제외)

반응형
JavaFX 효과

썬의 흥미로운 새 제품군 JavaFX를 통해 개발자들은 광범위한 장비에서 Java를 활용하는 훌륭하고 풍부한 사용자 인터페이스를 구축할 수 있으며, 이는 "한번 작성하여 어디서든 실행할 수 있도록 한다"는 목표를 향해 한 단계 더 나아간 것입니다.

썬의 CTO인 Bob Brewin은 Global Systems Engineering 부문 부사장 Hal Stern과 본 Innovating@Sun 최신판에서 통합형 리치 클라이언트의 진화 즉, 과도한 TV 스크린 형식의 클라이언트에서 인대시(In-Dash) 타입의 자동차 시스템으로 또는 인터넷 상에서 이용할 수 있는 서비스 및 컨텐츠를 모두 활용할 수 있는 webtop으로의 진화를 이끄는 소프트웨어 기술에 대해 대담을 나누었습니다.

Java FX 제품군에서는 JavaFX 스크립트를 사용하여 개발자들이 전개하고자 하는 플랫폼에 관계 없이 장치들을 동일한 방식으로 대상화하여, 일관된 표준 선언문 형식의 스크립트 언어로 작성할 수 있도록 합니다. 주목할 만한 점들은 다음과 같습니다.

  • JavaFX Script 및 JavaFX Mobile의 기능
  • 사용자 생성 컨텐츠가 애플리케이션을 구동시키는 급증하는 컨텐츠 지향 환경에서 JavaFX의 위치
  • 보다 흥미롭고 유용한 애플리케이션을 위해 클라이언트에 기능 추가
  • 선언문 형식의 스크립트 언어, 특히 Java UI를 생성하는 것을 목적으로 하는 언어가 컨텐츠가 풍부한 애플리케이션 구축을 용이하게 하는 방법
  • 코드 재사용 경향을 지속시키며 그것을 UI에 적용하기
  • 개발자들이 UI 레벨에서 동일한 집합의 API로 작성하면서 “한 번 작성하여 어디서든 실행할 수 있도록 한다"는 목표를 달성하는 방법

Links :


Podcast의 스크립트 다운로드

  1. 영문판 보기
  2. 한글판 보기
  3. 영문 & 한글판 함께 보기

* 출처 : 이노베이션 블로그 - 2007년 6월 20일 수요일 작성

이 글의 원문은 http://blogs.sun.com/innovation/entry/the_java_fx_effect 에서 보실 수 있습니다.

반응형
Robert Eckstein 및 JavaFX Programming Language Reference 필진 작성, 2007년 7월

JavaFX Script 프로그래밍 언어(JavaFX)는 Sun Microsystems, Inc.에서 제공하는 선언적, 정적 형식의 스크립팅 언어이다. Open JavaFX (OpenJFX) 웹 사이트에서 언급한 대로, JavaFX 기술은 Java 기술 API에 직접 호출하는 것을 비롯한 다양한 기능으로 구성되어 있다. JavaFX 스크립트는 정적 형식인 만큼 동일한 코드 구조, 재사용 및 캡슐화 기능을 갖추고 있어(예: 패키지, 클래스, 상속, 별도의 컴파일 및 배포 단위) Java 기술을 사용해 매우 큰 규모의 프로그램을 만들고 유지 관리할 수 있다.

시리즈로 구성된 이 세 기사는 JavaFX 프로그래밍 언어를 처음 사용하는 데 도움이 될 것이다. 이번 시리즈의 1부에서는 JavaFX 프로그래밍 언어를 소개하며, 이미 Java 기술과 스크립팅 언어의 기초를 알고 있는 독자를 대상으로 한다. 시리즈 2부와 3부에서는 JavaFX 기술과 RMI(Remote Method Invocation)JAX-WS(Java API for XML Web Services)와 같은 기술을 이용하여 원격 서버에 연결하는 방법을 소개한다.

JavaFX Pad 응용 프로그램

시스템에 JRE(Java Runtime Environment)가 있는 경우, JavaFX 기술을 가장 손쉽게 시작하는 방법은 Java Web Start 사용 가능 데모 프로그램인 JavaFX Pad를 시작하는 것이다. 응용 프로그램을 시작했으면 그림 1과 같은 화면이 나타나야 한다.

그림 1. Microsoft Windows Vista, JDK 6에서 실행 중인 JavaFX Pad 응용 프로그램
그림 1. Microsoft Windows Vista, JDK 6에서 실행 중인 JavaFX Pad 응용 프로그램

JavaFX Pad는 기본 응용 프로그램이 로드된 상태에서 시작하므로, 이 응용 프로그램이 즉시 실행된다. 그러나 이 기사의 JavaFX 소스 코드를 잘라내어 샘플에 붙여 넣어 수정 사항을 볼 수도 있다. 또한 JavaFX 소스 예제를 로컬 디스크에 저장하고 로드할 수 있다. JavaFX Pad 응용 프로그램은 런타임 시 수행하는 작업을 정확하게 파악하고 진행 과정에서 수정하며 즉시 그 결과를 볼 수 있는 효과적인 방법이다.

JavaFX 기술: 정적 형식 언어

JavaFX 프로그래밍 언어는 정적(static) 형식의 스크립팅 언어이다. 이는 정확하게 어떤 의미인가? 다음을 살펴 본다.

var myVariable = "Hello";

JavaScript 기술에서 볼 수 있는 것과 비슷한 이 선언에서는 myVariable이라는 변수를 만들고 여기에 string 값 Hello를 지정한다. 그러나 변수를 선언한 다음에 string이 아닌 다른 것을 지정해 보겠다.

myVariable = 12345;

이 코드에서는 12345를 따옴표로 묶지 않았기 때문에 이 변수에는 string이 아니라 integer가 지정된다. JavaScript 기술에서는 변수 형식을 동적으로 재지정할 수 있다. 그러나 JavaFX와 같은 정적 형식의 언어는 이를 허용하지 않는다. myVariable은 원래 String 형식으로 선언되었지만, 나중에 코드에서 이 변수를 integer로 재지정하려고 하기 때문이다. JavaFX를 사용할 경우, String으로 선언된 변수는 String으로 유지되어야 한다.

실제로 JavaFX Pad 데모에서 이 두 줄의 코드를 만나면 그림 2와 같이 창 맨 아래에 즉시 오류가 표시된다.

그림 2. JavaFX 기술에서는 정적 형식의 변수에서 형식을 변경할 수 없다.
그림 2. JavaFX 기술에서는 정적 형식의 변수에서 형식을 변경할 수 없다.



JavaFX 기술: 선언적 스크립팅 언어

JavaFX 기술은 선언적 스크립팅 언어이기도 하다. 그러나 선언적이란 정확하게 무엇을 의미하는가? 이 질문에 답하기 위해 OpenJFX 웹 사이트의 이 Hello World 프로그램을 살펴 보겠다.

class HelloWorldModel {
    attribute saying: String;
}

var model = HelloWorldModel {
    saying: "Hello World"
};

var win = Frame {
    title: bind "{model.saying} JavaFX"
    width: 200
    content: TextField {
        value: bind model.saying
    }
    visible: true
};

Java 프로그래밍 언어를 비롯하여 대부분의 컴파일된 언어는 imperative 프로그래밍 언어로 간주된다. 무엇보다도 이는 Java 기술의 main() 메소드와 같은 시작점에 의존한다는 뜻이다. 이 시작점으로부터 다른 클래스나 필드를 인스턴스화거나 변수 또는 프로그램 상태에 따라 자원을 처리한다. 이 예제를 다소 확장하자면, imperative 프로그래밍 언어에서는 런타임 시 "공식을 통해(formulaically)" 실행 경로를 결정한다고 할 수 있다. 이 공식이 각 실행에서 동일한 경로를 만들 수도 있으나, 이 언어에서는 그 실행 경로를 런타임에 결정한다.

그러나 앞서 소개한 Hello World와 같은 JavaFX 프로그램에는 main() 메소드가 없다. 그 대신, 스크립팅 엔진에서는 실행 직전에 전체 프로그램을 읽으므로, 인터프리터가 프로그램을 올바르게 실행하는 데 필요한 모든 단계를 적용할 수 있다. 더 정확하게 말하자면, 스크립팅 엔진에 필요한 것은 실행 시작 전에 선언되며 모든 선언이 주어진 가운데 엔진은 명시된 목표 달성에 필요한 작업을 결정한다.

JavaFX Pad에서 System.out.println() 사용

곧 살펴 보겠지만, JavaFX는 기존의 Java 라이브러리를 호출할 수 있다. 그러나 JavaFX Pad 응용 프로그램에서 System.out.println()를 사용하려면 콘솔 지원을 활성화해야 한다. 그 방법은 다음과 같다.

  • Microsoft Windows XP 또는 Vista를 사용 중이라면 제어판에서 Java 아이콘을 클릭하고 고급 탭을 선택한 다음 Java 콘솔 항목에서 콘솔 표시를 선택한다.

  • Solaris 사용자라면 Preferences 탭에서 Java 아이콘을 클릭하고 Advanced 탭을 선택한 다음 Java Console 항목에서 Show Console을 선택한다. Preferences 탭에 Java 아이콘이 없으면 Java 배포판의 bin 디렉토리에서 ControlPanel 응용 프로그램(또는 jcontrol)을 실행한다.

  • Linux 사용자라면 해당 Java 배포판의 bin 디렉토리에서 ControlPanel(또는 jcontrol)이라는 응용 프로그램을 찾는다. 이를 실행한 다음 Preferences 탭에서 Java 아이콘을 클릭하고 Advanced 탭을 선택한 다음 Java Console 항목에서 Show Console을 선택한다.

  • Mac OS X 사용자라면 /Applications/Utilities/Java/[Java version]/ 아래에서 Java Preferences 응용 프로그램을 연다. 그런 다음 Advanced 탭을 선택하고 Java Console 항목에서 Show Console을 선택한다. 참고: Intel Mac에서 Java Preferences를 변경한 후 Java Web Start가 제대로 시작하지 않을 경우, 홈 디렉토리에서 Library/Caches/Java/deployment.properties 파일을 열고 모든 osarch 변수를 i386에서 ppc로 다시 변경해 본다.

JavaFX Pad에서 Run 메뉴의 Run Automatically 설정을 비활성화하고, JavaFX 응용 프로그램을 수동으로 실행하기 직전에 Java Console을 지운다. 응용 프로그램을 수동으로 실행하려면 JavaFX Pad 응용 프로그램의 Run 메뉴에서 Run 메뉴 항목을 사용한다.

그림 3에서는 Intel 기반 Macintosh에서 콘솔이 열린 상태로 실행 중인 JavaFX Pad를 보여 준다. 그림 4는 OpenSolaris에서 실행 중인 JavaFX Pad이다.

그림 3. Mac OS X, JDK 1.5.0_07의 Java Console에서 실행 중인 JavaFX Pad

그림 3. Mac OS X, JDK 1.5.0_07의 Java Console에서 실행 중인 JavaFX Pad


그림 4. OpenSolaris, JDK 6의 Java Console에서 실행 중인 JavaFX Pad 

그림 4. OpenSolaris, JDK 6의 Java Console에서 실행 중인 JavaFX Pad

마지막으로, JavaFX에서 string 내부에 변수를 포함시킨 경우(주로 Java 프로그래밍 언어에서 System.out.println()을 사용), 알맞은 JavaFX 구문은 다음과 같다.

    import java.lang.System;

    System.out.println("Text {variable} and more text");

이는 Java 언어 구문과 다르다.

    import java.lang.System;

    System.out.println("Text " + variable + " and more text");

JavaFX 기술 알아보기

이 섹션에서는 JavaFX 기술의 기본 사항을 살펴 본다. 이 정보의 대부분은 정식 JavaFX Programming Language Reference에서 직접 발췌한 것이며, 단 이 기사의 작성자들이 Java 프로그래머를 위해 그 내용을 수정했다.

Primitive

JavaFX 프로그래밍 언어는 String, Boolean, NumberInteger의 4개 primitive 형식만 제공한다. Java 프로그래밍 언어와 달리 primitive는 대문자로 시작한다. 표 1에서는 JavaFX 인터프리터 내부의 형식 그리고 이 형식이 매핑되는 Java 객체를 보여 준다.

JavaFX의 Primitive 매핑 JavaFX 기술의 Primitive 대표적인 Java 기술 Primitive 또는 클래스
String     java.lang.String
Boolean Number          java.lang.Number
Integer byte, short, int, long,          java.math.BigInteger

참고: 복잡성을 피하기 위해, Integer는 작은 수와 큰 수를 모두 나타내는데, Java 프로그래머는 short 또는 long과 같이 서로 다른 primitive 형식을 사용하기도 한다. Java 기술의 부동 소수점 숫자(예: float, double)는 Number 형식으로 표현한다.

Java 객체가 이 primitive를 나타내므로 이 형식 각각에서 기존의 Java 메소드를 호출할 수 있다.

var s:String = "Hello";
s.toUpperCase();      // String method that yields "HELLO";
s.substring(1);       // String method that yields "ello";

var n:Number = 1.5;
n.intValue();         // Number method that yields integer 1
(1.5).intValue();     // Number method that yields integer 1

var b:Boolean = true;
b instanceof Boolean; // Boolean method that yields true

그 결과를 보고 싶다면 System.out.println() 문에서 각 표현식을 줄바꿈하고 반드시 맨 위에 java.lang.System을 가져온다. 또한 호환되지 않는 형식이라는 오류가 발생할 경우, 우선 스크립트 끝에 null return을 추가하면 된다. 예제 코드는 다음과 같다.

import java.lang.System;

var s:String = "Hello";
System.out.println(s.toUpperCase());      // String method that yields "HELLO";
System.out.println(s.substring(1));       // String method that yields "ello";

var n:Number = 1.5;
System.out.println(n.intValue());         // Number method that yields integer 1
System.out.println((1.5).intValue());     // Number method that yields integer 1

var b:Boolean = true;
System.out.println(b instanceof Boolean); // Boolean method that yields true

return null;                              // Final node returned for JavaFX Pad display

역시 var 키워드 사용에 주목한다. Java 기술에서 사용되지는 않지만 var는 JavaFX 및 그 밖의 스크립팅 언어에서 새 변수를 선언할 때 쓰인다. JavaFX는 정적 형식 언어이므로, 선언에서 변수의 형식을 지정할 수 있으며 그렇지 않으면 JavaFX 인터프리터는 변수의 쓰임새로부터 변수의 형식을 유추하려고 한다. 예를 들어, 다음 세 가지 모두 JavaFX에서 유효하다.

var s:String;
var s:String = "A New String";
var s = "A New String";

첫 번째와 두 번째 선언에서는 공식적으로 String 형식을 변수에 지정하지만, 세 번째에서는 등호 (=) 부호의 오른쪽에 있는 초기값으로부터 이를 String으로 유추한다. 이를 더 공식적으로 나타낸다면 JavaFX 변수 선언을 이렇게 표현할 수 있다.

var variableName [: typeName] [? | + | *] [= initializer];

물음표, 더하기 부호 및 별표는 카디널리티 연산자라고 부른다. 표현식 언어를 사용한 적이 있으면 이 용어가 익숙할 것이다. 이 세 연산자 중 하나를 사용하여 변수의 카디널리티(구성원 수)를 나타낼 수 있다. 표 2를 참조한다.

표. JavaFX 카디널리티 연산자
연산자
의미
?
선택 사항(예를 들어 null이 될 수 있음)
+
하나 이상
*
0 이상

다음은 그 예제이다.

var nums:Number* = [5, 9, 13];

이 예제에서 선언하는 새 변수, nums의 값은 Number 형식의 인스턴스 0개 이상으로 구성되도록 정의되며, 초기 값은 3개의 숫자, 5, 9 그리고 13이다.

선언에서 typeName, 카디널리티 연산자와 초기값은 선택 사항이므로, 다음은 위의 예제와 동일하다.

var nums = [5, 9, 13];

리터럴

JavaFX 기술에서 리터럴 문자 스트링은 작은 따옴표 또는 큰 따옴표로 지정된다.

var s = 'Hello';
var s = "Hello";

필자가 앞서 언급한 대로, 변수와 심지어 JavaFX 표현식 전체를 중괄호({})로 묶을 수 있다.

var name = 'Joe';
var s = "Hello {name}"; // s = 'Hello Joe'
 

포함된 표현식 자체가 따옴표가 붙은 스트링을 포함할 수 있으며, 이 스트링이 다시 표현식을 포함하기도 한다.

var answer = true;
var s = "The answer is {if answer then "Yes" else "No"}";
    // s = 'The answer is Yes'
 

마지막으로, Java 기술과 달리 큰 따옴표로 묶인 String 리터럴은 새 행을 포함할 수 있다.

var s = "This
         contains
         new lines";
 

어레이 및 리스트 이해

앞서 카디널리티 연산자가 어레이를 생성하는 것을 보았을 것이다. JavaFX에서 어레이는 대괄호와 쉼표로 표시한다. Java와 마찬가지로 JavaFX 어레이의 요소는 모두 형식이 동일해야 한다.

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

어레이는 객체의 시퀀스를 나타낸다. JavaFX에서는 어레이 자체가 객체는 아니다. 또한 중첩된 어레이를 만드는 표현식(예: 앞의 코드 예제에서 두 번째 변수 days의 초기화)은 자동으로 평면화된다.

days == ["Mon","Tue","Wed","Thur","Fri","Sat","Sun"];
     // returns true
 

System.out.println(days)을 실행하면 어레이의 첫 번째 요소만 표시된다. 나머지 요소를 얻으려면 어레이 색인을 사용한다. 또한 존재하지 않는 색인을 지정할 경우, Java와 같이 ArrayIndexOutOfBoundsException이 발생하지 않고 0을 얻을 뿐이다.

sizeof 연산자를 사용하여 현재 어레이 크기를 구할 수 있다.

var n = sizeof days;     // n = 7
 

또한 간략하게 마침표 2개(..)를 사용하여 요소가 산술적 시리즈를 형성하는 어레이를 나타낼 수 있다. 예를 들어, 다음은 100개 요소의 어레이를 생성한다.

var oneToAHundred = [1..100];
var arraySize = sizeof oneToAHundred;   // size == 100
 

JavaFX 기술은 어레이 사용 시 insertdelete 문도 지원한다. 다음은 값을 어레이에 삽입하는 예제이다.

var x = [1,2,3];
insert 12 into x;                 // yields [1,2,3,12]
insert 10 as first into x;        // yields [10,1,2,3,12]
insert [99,100] as last into x;   // yields [10,1,2,3,12,99,100]
 

into 외에도 다음과 같이 beforeafter 키워드를 사용할 수 있다.

var x = [1,2,3];
insert 10 after x[. == 3];        // yields [1,2,3,10]
insert 12 before x[1];            // yields [1,12,2,3,10]
insert 13 after x[. == 2];        // yields [1, 12, 2, 13, 3, 10];
 

대괄호로 묶인 표현식 중 일부가 이상하게 보이더라도 신경 쓸 필요 없다. 실제로 Xquery-Update(XPath와 유사) 술어이다. 여기서 괄호 안의 마침표는 색인을 나타내지 않지만, 대신 색인의 을 의미한다. JavaFX 기술은 표현식이 true가 될 때까지 어레이의 요소 각각을 테스트한 다음 insert를 적용한다. 예를 들어, 마지막 문은 어레이의 각 값을 거치면서 반복되다가 (어레이의 세 번째 요소인)2와 동일한 어레이 값을 찾아내면 숫자 13을 삽입한다. 여기서 중지한다.

delete 문도 거의 동일하게 실행된다. 대괄호 안의 표현식이 생략될 경우, 어레이 전체가 지워진다.

var x = [1,2,3];
insert 10 into x;          // yields [1,2,3,10]
insert 12 before x[1];     // yields [1,12,2,3,10]
delete x[. == 12];         // yields [1,2,3,10]
delete x[. >= 3];          // yields [1,2]
insert 5 after x[. == 1];  // yields [1,5,2];
insert 13 as first into x; // yields [13, 1, 5, 2];
delete x;                  // clears the array and yields []
 

마지막으로, selectfor each 연산자를 사용하여 어레이에 대해 더 복잡한 쿼리를 수행할 수 있다. 이를 list comprehension이라고 한다. 다음은 select를 사용하는 간단한 예제이다.

var a:Integer* = select n*n from n in [1..10];
    //  yields [1,4,9,16,25,36,49,64,81,100]
 

이는 "[1..10] 어레이의 각 숫자를 루프하면서 로컬 변수 n에 지정한 다음 각 n에 대해 새 요소 n squared를 생성하고 이를 Integers a의 어레이에 추가한다"는 뜻이다.

또한 다음을 사용하여 필터를 추가할 수 있다.

var a:Integer* = select n*n from n in [1..10] where (n%2 == 0);
    //  yields [4,16,36,64,100]
 

이는 정의를 다음으로 변경한다. "[1..10] 어레이의 각 숫자를 루프하면서 그 숫자를 2로 나눈 나머지가 0인 경우에만, 즉 짝수인 경우에만 로컬 변수 n에 지정한다. 그런 다음 결과 값인 n 각각에 대해 새 요소 n squared를 생성하고 이를 Integers a의 어레이에 추가한다."

마지막으로, 여러 개의 리스트를 선택에 추가할 수도 있다.

var a:Integer* = select n*m from n in [1..4], m in [100,200] where (n%2 == 0);
    //  yields [200, 400, 400, 800]
 

실제로 이는 루프 안에 루프가 존재하면서 공식적으로는 Cartesian Product.를 생성한다. 먼저 첫 번째 유효한 n(즉 2)을 얻고 여기에 첫 번째 유효한 m인 100을 곱한다. 그런 다음 다시 2를 다음 번 유효한 m인 200과 곱한다. 그리고 나서 다음 번 유효한 n인 4를 사용하여 유효한 m의 리스트(100과 200)를 반복해 400과 800을 얻는다. 여기서 선택이 종료하며, 최종 어레이(어레이 a)가 얻어진다.

동일한 내용을 foreach 연산자를 사용하여 표현할 수 있다.

var a:Integer* =
    foreach(n in [1..4], m in [100,200] where (n%2 == 0) )
            n*m;      // also yields [200, 400, 400, 800]
 
형식 지정

format as 연산자는 표 3에서 보여주는 것처럼 몇 가지 형식 지정 지시문을 지원한다.

JavaFX 형식 지정 지시문 지시문사용된 형식의 클래스%로 시작하는 형식 지정 지시문java.util.Formatter표현식이 Numberjava.text.DecimalFormat표현식이 java.util.Date java.text.SimpleDateFormat

다음은 몇 가지 예제이다.

import java.util.Date;

100.896 format as <<%f>>; // yields '100.896000'
31.intValue() format as <<%02X>>;
    // yields '1F'
var d = new Date();
d format as <<yyyy-MM-dd'T'HH:mm:ss.SSSZ>>;
    // yields '2005-10-31T08:04:31.323-0800'
0.00123 format as <<00.###E0>>;
    // yields '12.3E-4'

이 예제에서는 프랑스어 따옴표, 즉 guillemets(<< >>)가 사용되었다. JavaFX 기술에서는 공백을 비롯하여 프랑스어 따옴표로 묶인 문자 시퀀스를 모두 식별자로 취급한다. 따라서 JavaFX 키워드 또는 평소에는 적합하지 않은 식별자를 클래스, 변수, 함수 또는 속성 이름으로 사용할 수 있다. 다음은 그 예제이다.

var <<while>> = 100;

이 기능에서는 이 예제와 같이 JavaFX 키워드와 이름이 같은 Java 메소드를 호출할 수 있다.

import javax.swing.JTextArea;

var textArea = new JTextArea();
textArea.<<insert>>("Hello", 0);
클래스 선언

클래스를 지정하는 JavaFX 구문은 class 키워드 다음에 클래스 이름, extends 키워드(옵션) 그리고 쉼표로 구분된 기본 클래스 이름의 목록이다. Java와 달리 JavaFX 기술에서는 둘 이상의 클래스를 확장할 수 있다. 그 다음에 여는 중괄호, 속성, 함수 및 연산의 목록(각각 세미콜론(;)으로 끝남)과 닫는 중괄호가 이어진다. 다음은 그 예제이다.

class Person {

    attribute name: String;
    attribute parent: Person;
    attribute children: Person*;

    function getFamilyIncome(): Number;
    function getNumberOfChildren(): Number;

    operation marry(spouse: Person): Boolean;
}

속성, 함수 및 연산

세 가지 형식의 클래스 구성원 선언을 자세히 살펴 보도록 한다. 속성(Attribute)attribute 키워드 다음에 속성의 이름, 콜론(:), 속성의 형식, 카디널리티 사양(옵션) 및 역 절(inverse clause)(옵션)을 사용하여 선언한다. 카디널리티를 사용하는 경우, 종종 그 속성을 다중 값 속성(multivalued attribute)이라고 한다.

더 공식적으로 설명하자면, 속성이 다음 구문을 사용한다.

attribute AttributeName [: AttributeType] [? | + | *] [inverse ClassName.InverseAttributeName];
>

맨 끝에 오는 inverse 절 옵션은 다른 속성과의 양방향 관계를 지정한다. inverse 절이 존재하는 경우, JavaFX 기술은 inverse 절에 지정된 속성이 수정될 때마다 그 속성을 자동으로 업데이트한다(속성의 업데이트 및 카디널리티 종류에 따라 insert, delete 또는 replace 사용).

함수(Function)는 JavaFX 프로그래밍 언어의 순수 기능 하위 집합을 나타낸다. 즉 함수의 본문은 일련의 변수 선언과 return 문만 포함할 수 있다. 그 정도면 속성 접근자(getter) 및 간단한 수학적 절차 구현에 충분하다. 몇 가지 함수의 예제를 소개한다.

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

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

JavaFX에서 연산(Operation)operation 키워드를 사용하여 선언한다. 함수와 달리 연산은 조건문, 루핑문, trycatch 문을 비롯하여 개수 제한 없이 문을 포함할 수 있다. 따라서 Java 기술의 클래스 메소드와 더 비슷하다. 본문을 선언할 때 연산의 이름이 주어지고 괄호로 묶인 입력 변수, 콜론 그리고 반환 변수 형식이 이어진다. 다음은 그 예제이다.

operation substring(s:String, n:Number): String {
    try {
        return s.substring(n);
    } catch (e:StringIndexOutOfBoundsException) {
        throw "sorry, index out of bounds";
    }
}

선언된 속성 초기화

함수 및 프로시저와 마찬가지로, 속성의 초기 값은 클래스 정의의 외부에서 선언한다. 이 초기값은 새로 생성된 객체의 컨텍스트에 따라 클래스 선언에서 속성이 지정된 순서대로 평가된다.

import java.lang.System;

class X {
    attribute a: Number;
    attribute b: Number;
}

attribute X.a = 10;
attribute X.b = -1;

var x = new X();
System.out.println(x.a); // prints 10
System.out.println(x.b); // prints -1
>

JavaFX 객체는 선언적 구문을 사용하여 초기화할 수도 있다. 이 구문은 클래스 이름, 중괄호로 구분된 속성 초기값 목록의 순서로 구성된다. 각 초기값은 속성 이름, 콜론 그리고 그 값을 정의하는 표현식의 순서로 구성된다. new 키워드는 생략된다. 다음은 동일한 예제이다.

var myXClass = X {
    a: 10
    b: -1
};

선언적 구문은 JavaFX 기술에서 자주 사용된다. 그러나 Java 객체 할당 구문도 지원된다. Java 클래스의 경우, Java 기술에서처럼 클래스의 구성자에 인수를 전달하거나 선언적 구문을 사용할 수 있다.

import java.util.Date;
import java.lang.System;

var date1 = new Date(95, 4, 23);    // call a Java constructor
var date2 = Date {  // create the same date as an object literal
    month: 4
    date: 23
    year: 95
};

System.out.println(date1 == date2);   // prints true

함수 및 연산 정의

Java 메소드와 달리 모든 구성원 함수 및 연산의 본문은 클래스 선언의 외부에서 정의된다. 이 구문이 맨 처음에는 Java 프로그래머에게 약간 이상하게 보일 수 있으나 비교적 간단하게 이해할 수 있다. JavaFX 기술을 사용하면 연산 이름의 함수 앞에 그 함수가 속한 클래스 및 마침표가 온다. 반환 값은 함수 또는 연산 이름 뒤에 나열할 수 있으며, 앞에 콜론이 온다. 매개 변수는 서명 괄호에 포함시킬 수 있다. 이들은 쉼표로 구분되며, 앞서 연산에 대해 설명했던 name:type 구문을 따른다. 다음은 그 예제이다.

operation Person.marry(spouse: Person): Boolean {
    //  Body of operation
}

클래스 선언 내부의 연산 및 함수 선언에서는 괄호와 반환 값이 반드시 필요하다. 그러나 외부 정의에서는 생략 가능하다. 따라서 다음과 같이 쉽게 표현할 수 있다.

operation Person.marry() {
    //  Body of operation
}

트리거

Java 기술과 달리, JavaFX 클래스는 구성자가 없으며 JavaFX 속성은 일반적으로 "setter" 메소드를 갖지 않는다. 그 대신 JavaFX 기술에서는 데이터 수정 이벤트를 처리할 수 있도록 SQL과 비슷한 트리거를 제공한다. 이 트리거에서는 trigger 키워드를 사용한다.

객체 생성 트리거

생성 트리거를 지정하는 방법으로 새로 생성된 객체의 컨텍스트에서 작업을 트리거할 수 있다.

import java.lang.System;

class X {
     attribute nums: Number*;
}

trigger on new X {
     insert [3,4] into this.nums;
}

var x = new X();
System.out.println(x.nums == [3,4]); // prints true

이 예제에서는 X 클래스의 새 인스턴스가 만들어질 때마다 실행될 트리거를 정의한다. 여기서는 두 개의 숫자를 nums 속성에 삽입한다. 트리거의 컨텍스트에서 현재 객체를 가리킬 때 this 키워드를 사용한다.

Insert 트리거

또한 다중 값 속성에 요소가 삽입될 때마다 어떤 작업을 트리거할 수 있다.

import java.lang.System;

class X {
     attribute nums: Number*;
}

trigger on insert num into X.nums {
     System.out.println("just inserted {num} into X.nums at position {indexof num}");
}

var x = new X();
insert 12 into x.nums;
    // prints just inserted 12 into X.nums at position 0
insert 13 into x.nums;
    // prints just inserted 13 into X.nums at position 1

Delete 트리거

동일한 방법으로 다중 값 속성에서 요소가 삭제될 때마다 어떤 작업을 트리거할 수 있다.

import java.lang.System;

class X {
     attribute nums: Number*;
}

trigger on delete num from X.nums {
     System.out.println("just deleted {num} from X.nums at position {indexof num}");
}

var x = X {
     nums: [12, 13]
};

delete x.nums[1];
    // prints just deleted 13 from X.nums at position 1
delete x.nums[0];
    // prints just deleted 12 from X.nums at position 0

Replace 트리거

마지막으로, 속성의 값이 대체될 때마다 작업을 수행할 수 있다. 다음 예제에서 oldValuenewValue는 대체되는 요소의 이전 값과 현재 값을 참조하는 임의의 변수 이름이다. 다른 변수 이름을 자유롭게 선택할 수 있다.

import java.lang.System;

class X {
     attribute nums: Number*;
     attribute num: Number?;
}

trigger on X.nums[oldValue] = newValue {
     System.out.println("X.nums: replaced {oldValue} with {newValue} at position {indexof newValue}");
}

trigger on X.num[oldValue] = newValue {
     System.out.println("X.num: replaced {oldValue} with {newValue}");
}

var x = X {
     nums: [12, 13]
     num: 100
};

x.nums[1] = 5;
    // prints replaced 13 with 5 at position 1 in X.nums
x.num = 3;
    // prints X.num: replaced 100 with 3
x.num = null;
    // prints X.num: replaced 3 with null

JavaFX 기술에서는 Java 기술의 해당 문과 비슷하지만 똑같지 않은 몇몇 문을 지원한다. 이 섹션에서는 그 차이점을 간략하게 소개한다.

If

JavaFX if 문은 중괄호가 필요하다는 점을 제외하고 Java 기술의 문과 같다.

if (condition1) {
    System.out.println("Condition 1");
} else if (condition2) {
    System.out.println("Condition2");
} else {
    System.out.println("not Condition 1 or Condition 2");
}

While

JavaFX while 문 역시 본문을 중괄호로 묶어야 한다.

var i = 0;
while (i < 10) {
    if (i > 5) {
       break;
    }
    System.out.println("i = {i}");
    i += 1;
}

Try, CatchThrow

JavaFX trycatch 문은 JavaFX 변수 선언 구문을 제외하고 Java 기술의 문과 같다. JavaFX 기술에서는 java.lang.Throwable을 확장하는 객체 외에 어떤 객체도 throw 및 catch할 수 있다.

try {
   throw "Hello";
} catch (s:String) {
   System.out.println("caught a String: {s}");
} catch (any) {
   System.out.println("caught something not a String: {any}");
} finally {
   System.out.println("finally...");
}

For

JavaFX for 문의 헤더에서는 앞서 설명한 foreach list-comprehension 연산자와 동일한 구문을 사용한다. 문의 본문은 list comprehension에서 생성한 각 요소에 대해 실행된다. 다음은 그 예제이다.

for (i in [0..10]) {
     System.out.println("i = {i}");
}

// print only the even numbers using a filter
for (i in [0..10] where (i%2 == 0) ) {
     System.out.println("i = {i}");
}

// print only the odd numbers using a range expression
for (i in [1,3..10]) {
     System.out.println("i = {i}");
}

// print the cartesian product
for (i in [0..10], j in [0..10]) {
     System.out.println(i);
     System.out.println(j);
}

Return

JavaFX return 문은 Java 기술의 문과 동일하다.

operation add(x, y) {
    return x + y;
}

BreakContinue

JavaFX breakcontinue 문은 레이블이 지원되지 않는다는 점을 제외하고 Java 기술의 문과 같다. Java 프로그래밍에서처럼 breakcontinuewhile 또는 for 문의 본문에 나타나야 한다.

operation foo() {
   for (i in [0..10]) {
       if (i > 5) {
           break;
       }
       if (i % 2 == 0) {
           continue;
       }
       System.out.println(i);
   }
}

operation bar() {
    var i = 0;
    while (i < 10) {
        if (i > 5) {
            break;
        }
        if (i % 2 == 0) {
            continue;
        }
        System.out.println(i);
        i += 1;
    }
}

DoDo Later

JavaFX do 문에서는 JavaFX 코드의 블록을 실행할 수 있다. 그러나 do 본문은 항상 백그라운드 스레드에서 실행된다. 일반적으로 JavaFX 코드는 AWT EDT(Event Dispatch Thread)에서 실행된다. do 문의 본문에 포함된 코드만 다른 스레드에서 실행 가능하다. 다음 예제를 살펴 본다.

import java.net.URL;
import java.lang.StringBuffer;
import java.lang.System;
import java.io.InputStreamReader;
import java.io.BufferedReader;

// in the AWT Event Dispatch Thread (EDT)
var result = new StringBuffer();

do {
    // now in a background thread
     var url = new URL("http://www.foo.com/abc.xml");
     var is = url.openStream();
     var reader = new BufferedReader(new InputStreamReader(is));
     var line;
     while (true) {
          line = reader.readLine();
          if (line == null) {
               break;
          }
          result.append(line);
          result.append("\n");
     }
}

// now back in the EDT
System.out.println("result = {result}");

do 문의 본문이 실행되는 중에 EDT 블록에서 실행되는 코드이다. 그러나 백그라운드 스레드가 완료될 때까지 기다리는 동안 스택에서 새로운 이벤트 디스패치 루프가 생성된다. 그 결과, do 문이 실행되는 동안 GUI(graphical user interface) 이벤트는 계속 처리된다.

do 문은 do later라는 두 번째 형식을 갖는데, 이 형식은 java.awt.EventQueue.invokeLater()의 기능과 비슷하게, 백그라운드 스레드에서 동시 실행이 아니라 EDT에서 본문이 비동기식으로 실행될 수 있게 한다. 다음은 그 예제이다.

import java.lang.System;
var saying1 = "Hello World!";
var saying2 = "Goodbye Cruel World!";
do later {
     System.out.println(saying1);
}
System.out.println(saying2);

이 코드를 실행하면 다음과 같은 출력이 생성된다.

Goodbye Cruel World!
Hello World!

증분 평가

증분 평가(incremental evaluation)는 JavaFX 기술에서 가장 강력한 기능 중 하나이다. 프로그래머가 복잡한 동적 GUI를 선언적으로 정의할 수 있다. JavaFX 기술에서는 bind 연산자를 사용하면 속성 초기값을 증분식으로 평가할 수 있다. 바인딩된 이 속성은 스프레드시트의 셀처럼 작동하면서 리터럴 값 대신 공식을 포함한다. 초기값 표현식의 오른쪽에서 참조하는 객체가 변경될 때마다 속성의 값인 왼쪽이 자동으로 업데이트된다.

다음은 간단한 예제이다.

import java.lang.System;

class X {
    attribute a: Number;
    attribute b: Number;
}

var x1 = X {
    a: 1
    b: 2
};

var x2 = X {
    a: x1.a           // nonincremental
    b: bind x1.b      // incremental
};

System.out.println(x2.a); // prints 1
System.out.println(x2.b); // prints 2

x1.a = 5;
x1.b = 5;

System.out.println(x2.a); // prints 1
System.out.println(x2.b); // prints 5

이 예제에서 x2b 속성은 x1b 속성에 바인딩된다. 즉 x1b 속성이 업데이트될 때마다 x2b 속성도 업데이트된다.

함수의 본문은 bind 연산자가 없더라도 항상 증분식으로 평가되지만, 연산의 본문은 그렇지 않다. 함수와 달리, 연산 내부의 로컬 변수가 변경되더라도 증분 평가가 트리거되지 않는다. 표현식 앞에 명시적으로 bind라는 접두어가 붙지 않는 한 연산의 본문 내부에서는 증분 평가가 수행되지 않는다.

느린 증분 평가(lazy incremental evaluation)도 사용하도록 예제를 수정할 수 있다. 여기서는 attribute 값이 맨 처음 액세스될 때까지 바인딩이 적용되지 않는다.

import java.lang.System;

class X {
    attribute a: Number;
}

var x1 = X {
    a: 1
};

var x2 = X {
    a: bind lazy x1.a
    // no value is assigned yet
};

System.out.println(x2.a);
// Now the value is accessed, so x2.a is set to 1

느린 증분 평가 기능은 재귀적 데이터 구조(예: 트리, 그래프)를 처리할 때 자주 쓰인다.

결론

이 기사에서는 JavaFX 플랫폼을 간단하게 소개했다. 2부와 3부에서는 JavaFX 기술 기반의 GUI를 사용하여 클라이언트 서버 통신을 처리하는 방법을 다룬다.

자세한 정보
반응형
 

소개

JavaFX는 SUN에서 새로 발표한 스크립트 언어이다. JavaFX는 다음과 같은 특징들을 가지고 있다.

  1. 서술형 언어
  2. 정적 자료형
  3. 함수형 언어
  4. 리스트 내포(list comprehension)
  5. 점증식 의존성 기반 평가(incremental dependency-based evaluation)

개발환경 꾸미기

JavaFX를 간단히 접해보기 위한 용도로는 JavaFXPad가 괜찮다.

IDE에서 JavaFX를 사용하는 방법은 아래 링크들을 참조

  1. eclipse에서 개발환경을 꾸미는 방법
  2. NetBeans에서 개발환경을 꾸미는 방법

튜토리얼

  1. Hello World JavaFX 시작하기
  2. 클래스, 객체 그리고 bind

참고 자료

아직까지 JavaFX에 대한 참고 자료는 많지 않지만 JavaFX 공식 커뮤니티의 튜토리얼과 레퍼런스만 봐도 충분하다. 나머지는 Java 클래스를 가져다 쓰는 것 뿐이기 때문에 Java 문서들을 참조하면 된다.

JavaFX 홈
JavaFX 공식 커뮤니티

< 출처: http://functional.or.kr/javafx/tutorial/intro >

+ Recent posts