오픈API 등을 이용하려면 XML을 파싱해서 JavaFX로 가져와야 합니다.
HttpRequest를 이용해서 xml을 요청한 다음에 PullParser를 이용해 한줄한줄 파싱해서 데이터로 가져오는 방식을 사용합니다.

음...JavaFX가 1.2로 업데이트 되었는데요. 기존에 HttpRequest에서 요청할 때 enqueue()라는 함수로 실행을 했는데, start()로 함수명이 바뀌었네요. start()가 깔끔하군요.

간단하게 네이버OpenAPI를 파싱해보겠습니다.
실시간 급상승 검색어를 간단히 뿌려주는 소스입니다.
사용자 삽입 이미지

main.fx
[code]package xmlparser;

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

var rankingInfo:RankingInfo = RankingInfo{
    onDone: function() {
        var content:String = "";
        for (item in rankingInfo.ranking) {
            content += "{item}\n";
        }
        text.content = content;
    }
};

var text:Text = Text {
    font: Font {
        size: 16
    }
    x: 10
    y: 30
}

Stage {
    title: "Application title"
    width: 250
    height: 300
    scene: Scene {
        content: text
    }
}[/code]
RankingInfo.fx
[code]package xmlparser;

import javafx.data.pull.PullParser;
import javafx.io.http.HttpRequest;
import java.lang.Exception;

public class RankingInfo {
    var url:String = "http://openapi.naver.com/search?key=네이버OpenAPI키&target=rank&query=nexearch";
    var p:PullParser;
    var h:HttpRequest;
    public var ranking:String[];
    public var onDone:function() = null;
   
    init {
        ranking = [];
        h = HttpRequest {
            location: url
            onException: function(exception:Exception) {
                exception.printStackTrace();
            }
            onInput: function(input) {
                var i;
                p = PullParser {
                    documentType: PullParser.XML
                    input: input
                    onEvent: function(event) {
                        if (event.type == PullParser.START_DOCUMENT) {
                            ranking = [];
                            i = 0;
                        }
                        else if (event.type == PullParser.END_ELEMENT
                            and event.level == 3) {
                           if (event.qname.name == "K") {
                               println("{event.text}");
                               ranking[i] = event.text;
                               i++;
                           }
                        }
                        else if (event.type == PullParser.END_DOCUMENT) {
                            onDone();
                        }
                    }
                }
                p.parse();
                p.input.close();
            }
        }
        h.start();
    }
}
[/code]
PullParser와 HttpRequest를 이용합니다. HttpRequest를 이용해서 url을 지정해서 가져오면 onInput이 발생합니다. 여기에서 input을 PullParser에 지정을 해주면 한줄씩 읽을 때마다 onEvent가 발생하게 됩니다.
onEvent에서는 한줄씩 읽으면서 Parsing을 해주면 됩니다.
해당 엘리먼트를 가져오기위해선 문서의 레벨과 태그의 이름으로 알 수 있습니다.
[code]<result>
<item>
<R1>
<K>투시안경</K>
<S>+</S>
<V>105</V>
</R1>
</item>
</result>[/code]
위와 같은 xml이라면 <K>값을 가져오기 위해서는 K의 레벨과 K를 알면 됩니다. K레벨은 result를 0, item을 1, R1을 2, K는 3이 됩니다.
[code]if (event.type == PullParser.END_ELEMENT and event.level == 3) {
if (event.qname.name == "K") {
    println("{event.text}");
}[/code]
3이고, qname.name이 K인걸 찾으면 돼요. END_ELEMENT에서 해야하는 이유는 START_ELEMENT에서하면 값이 아직 파싱이 안된 상태여서 그렇습니다-_-

JSON인 경우도 비슷해요.
단지 Pullparser.START_ELEMENT나 END_ELEMENT가 아닌, END_VALUE로 파악을 하면 됩니다.
documentType: PullParser.JSON으로 바꿔주셔야 해요.
 
Posted by 머드초보
,
 
JTable에 대한 사용법은 여기에 있습니다.
http://jfx.wikia.com/wiki/SwingComponents#Table

그 외에 작년에 preview버전에서 구현한 것 같은 소스도 있군요.
http://www.jroller.com/peter_pilgrim/entry/javafx_reintroduce_swing_jtable

Java에서 사용하는 방법이랑 같은 방법으로 하는군요.
근데, JTable에서는 기본적으로는 편집이 가능하게 되어있습니다.
JTable에서 Model을 구현하는데, AbstractTableModel를 상속받아 구현한 모델을 JTable에 적용하는 방법이 있구요. 기본적인 Table기능만 있으면 되면 DefaultTableModel을 이용하는 것 같습니다.
Java에서 편집이 안되게 막으려면 아래와 같은 방법으로 하면 됩니다.
[code]
mod = new DefaultTableModel(data,title) {
public boolean isCellEditable(int rowIndex, int mColIndex) {
return false;
}
};
[/code]
출처: http://nkdk.tistory.com/entry/%EC%9E%90%EB%B0%94-jtable-%EC%97%B4-%EC%A1%B0%EC%A0%95-%EC%95%88%EB%90%98%EA%B3%A0-%EB%82%B4%EC%9A%A9-%EC%88%98%EC%A0%95-%EB%AA%BB%ED%95%98%EA%B2%8C-%ED%95%98%EA%B8%B0
근데, 저 문법을 JavaFX에 적용하려고 하니까-_- 안되더군요-_-
그래서 상속받아서 해결했습니다.

DefaultTableModel을 상속받은 MyTableModel
[code]
public class MyTableModel extends DefaultTableModel {

    override function isCellEditable(row:Integer, col:Integer): Boolean {
        return false;
    }
}
[/code]
사용시에는
[code]
model = MyTableModel {}
model.addColumn("name");
table.setModel(model);
[/code]
이렇게 하면 편집 불가능한 JTable을 만들 수 있습니다.

PS. 분명 누군가가 좋은 데이터그리드를 만들꺼야....-_- JavaFX는 역시 컴포넌트가 부족하군ㅠ
 
Posted by 머드초보
,
 
JavaFX는 신뢰할 수 있는지에 대해서 동의만 얻으면 로컬에 있는 파일에 접근할 수 있습니다. 그렇다는 얘기는 JavaFX로 사용자 컴퓨터를 맛이가게 할 수 있는건가....-_-
JavaFX는 브라우저에서 돌아갈 때 오래전에 영광을 누렸던 Applet기반으로 돌아갑니다. 예전엔 채팅사이트나 왠만한 사이트에 Applet이 꼭 들어갔었죠. 보안문제나 속도문제 때문에 아마 Flash에 밀렸을겁니다.
혹시나 했는데 스카이러브라는 예전에 유명했던 채팅사이트는 아직도 애플릿을 사용하네요-_-

암튼 JavaFX에서 사운드재생은 Flash처럼 매우 간단합니다.
MediaPlayer라는 클래스가 있습니다.
http://java.sun.com/javafx/1.1/docs/api/javafx.scene.media/javafx.scene.media.MediaPlayer.html
그리고 Media라는 클래스가 있습니다.
http://java.sun.com/javafx/1.1/docs/api/javafx.scene.media/javafx.scene.media.Media.html

[code]
var mediaPlayer:MediaPlayer = MediaPlayer {
    volume: 0.5
    autoPlay: false
    onError: function(e:MediaError) {
        println("got a MediaPlayer Error : {e.cause} {e}");
    }
    onEndOfMedia: function() {
        println("reched end of media");
        playList.next();
    }
}

mediaPlayer.media = Media {
    source: "URL경로 및 FILE경로",
    onError: function(e:MediaError) {
        println("got a media error {e}");
    }
}
mediaPlayer.play()
[/code]
이렇게 하면 됩니다. 아....URL은 그냥 http://www.~~~.com/1.mp3 이렇게 하면 되는데요. 로컬에 있는 파일을 읽어올 경우에는 C:\1.MP3 이게 아니더군요.
file:/D:/임재범-비상.mp3 이렇게 해야되더군요.

아 그리고, JavaFX에서는 flash에 있는 DataGrid같은 게 없습니다-_- swing컴포넌트를 이용해서 만들어야해요. 구글링을 해보니 JTable로 만들어 놓은 게 있더라구요. 그걸 이용해서 플레이리스트르 만들었습니다.

근데, 가끔 브라우저(FireFox나 IE, Opeara는 안됨ㅠ)에서 버튼이 클릭이 안될 때가 있습니다-_- 왜그런지 모르겠네요. 근데 크롬은 100%클릭이 잘 됩니다. 왜그럴까요....-_- 테스트 하시는 분들은 크롬으로 하세요 ^^ 크롬짱-_-
사용자 삽입 이미지

이미지에요-_- 주소는 아래에-_-


예제 데모주소입니다(크롬으로....-_-)
http://mudchobosample.appspot.com/JavaFXMP3Player/JavaFXMP3Player.html

소스주소입니다.
http://my-svn.assembla.com/svn/mudchobosample/trunk/JavaFXMP3Player/

 
Posted by 머드초보
,
 
음...아직 JavaFX는 삽질할 것이 못되는군요. 얼마전 세미나에서 실버라이트1.0때 열악함을 말해줬는데 그것이 생각나는군요. JavaFX가 지금 현재 열악함 상태입니다.

우선 이 예제는 ManiaDB의 OpenAPI를 이용한 나름(?) 매쉬업 애플리케이션입니다 ㅠ 해당 가수명을 입력하면 매니아디비에서 앨범목록을 가져와서 앨범이미지를 DisplayShelf형태로 뿌려주는 애플리케이션입니다.

여러가지 문제점이 있었는데요ㅠ

1. JavaFX HttpRequest, PullParser 문제점

이 놈을 알아야지 API데이터를 가져올 수 있습니다. 이걸 사용하면서 뭔가 문제점이 있다면...XML파싱할 때 복잡합니다. Flex의 HTTPService는 축복입니다-_- 그리고, XML의 값이 없는 경우(ex:<description><![CDATA[]]></description>)에는 nullpointException을 내뿜으며 파싱에러를 냅니다-_- 매니아디비는 description이 없는 앨범이 있어서 저런 에러를 내뿜더군요.
그래서 꼼수(?)를 사용했습니다. JSON으로 변환해서 쓰면 됩니다-_- JSON은 에러를 안뿜어요. JSON으로 바꾸려면 역시 야후파이프가 짱-_-
야후파이프주소 : http://pipes.yahoo.com/pipes/
앨범검색파이프 : http://pipes.yahoo.com/pipes/pipe.info?_id=5e24977627eb6c03b1d7e9aeb820aca7
앨범검색파이트에서 Get as JSON으로 받으시면 JSON으로 받을 수 있습니다. 이걸가지고 HttpRequest클래스를 이용해서 파싱하면 됩니다.

파싱할 때 XML같은 경우에는 ELEMENT명과 LEVEL로 구분을 해서 값을 가져올 수 있습니다. PullParser라는 클래스를 이용해서 파싱하는데, XML엘리먼트마다 onEvent함수가 발생합니다. 거기서 해당 엘리먼트명과 level(얼마나 깊이 들어갔는지-_-)를 if문으로 구분해서 맞으면 값을 가져오는 그런 식으로 파싱합니다-_-
JSON도 비슷합니다. 예를 들어 값이 끝날 때 "로 끝나면 END_VALUE인지 확인 후 원하는 이름인지 확인 후 가져오면 됩니다. 생각해보니...뭐 그리 복잡하지도 않군요.


2. 과도한 {}로 불편한 문법-_-

조금 하다보니 이제 익숙해지려고 하는 듯하면서도 헷깔리는 과도한 {}-_- 이건 JSON도 아니고, Javascript도 아니고, Java도 아닌데, 3가지 문법이 짬뽕이 되었습니다. 재미있는 건 Java클래스를 그대로 쓸 수 있는 듯합니다. 어느정도인지는 안해봤는데, URI를 encode해야해서 어떻게 해야하나 생각하던중에 Java클래스에 있는 URIEncoder를 사용하니 그냥 되더군요-_- 예전에 선테크데이에서도 Java를 임포트할 수 있다고 들은 것 같아서^^
이 문법도 계속 보니....적응이 되는군요.

그 외에 문제가 굉장히 많았는데, 기억이 안나네요-_-

사용자 삽입 이미지

이건 스크린샷이에요-_- 낚이지 마세요-_-

실행예제 http://mudchobosample.appspot.com/AlbumSearch/AlbumSearch.html
실행 시 신뢰할꺼냐고 물어보는데, 신뢰한다고 해야 실행됩니다 ㅠ 외부파일을 끌어쓰기에..-_- 그리고 자기 인증서기때문에 6개월 뒤에 만기된다고 합니다 ㅠㅠ 인증서를 사야지 JavaFX를 제대로 쓸 수 있는 듯 합니다.

소스코드입니다.
http://my-svn.assembla.com/svn/mudchobosample/trunk/AlbumSearch/


참고자료
http://www.javafx.com/samples/InterestingPhotos/index.html
http://www.javafx.com/samples/DisplayShelf/index.html

PS. 활성화가 로컬에서 할 때에는 잘 되는데, 올리니까 안되네요. 그래서 TextInput부분을 강제로 활성화를 시켜버렸습니다ㅠ Swing컴포넌트를 써서 그런가....
 
Posted by 머드초보
,