Swing Components 와 JavaFX Graphics 섞기
JavaFX로 여러분은 심지어 그것이 커스텀 컴포넌트 일지라도 기존에 존재하는 스윙 컴포넌트와 원래 하나인것 처럼 그래픽과 효과를 이용해서 하나로 합칠수 있습니다. 이 예제는 SwingLabs.org의 스윙 JXMapViewer 컴포넌트와 JavaFX 그래픽의 커스텀 오버레이와 텍스트를 함께 결합하는 것을 보여줍니다. 여러분은 비록 그것이 JavaFX 화면 안에 있을지라도 여전히 마우스 주위의 지도를 상하로 회전하고확대/축소 할수 있다는것에 주목하세요.
Run Example with Java Webstart
Map data provided by OpenStreetMap.org
코드 이해하기
SwingLabs.org 웹사이트의 JXMapViewer 클래스는 복잡한 스윙 컴포넌트입니다. 이것은 스윙 어플리케이션의 OpenStreeMap.org 처럼 상하로 회전하고 확대/축소 움직임을 완비한 타일형태 지도제작 서버의 이미지를 표현합니다.
JButton 과 JSlider 같은 표준 스윙 컴포넌들은 javafx.ext.swing 패키지 안에 JavaFX wrapper들을 가지고 있습니다. 이러한 컴포넌트들을 위해서 여러분은 JavaFX wrapper 클래스를 사용할수 있습니다. 여러분은 JavaFX 프로그램안에서 여러분이 사용하길 원하는 기존 커스텀 스윙 컴포넌트를 가지고 있을지도 모릅니다. 이러한 컴포넌트들을 위해서 여러분은 자동으로 Swing wrapper를 생성해주는 SwingComponent.wrap() 함수를 사용할수 있습니다.
이 예제는 일반 자바 코드를 사용해서 지도 제작 컴포넌트를 생성해주는 SetupMap 자바 클래스안에 static 메소드를 가지고 있습니다. 이것은 Figure 1에서 보여주는것과 같이 여러분이 작성할 일반 자바 데스크톱 어플리케이션과 같은 코드입니다.
public class SetupMap {
public static JComponent create() {
JXMapViewer map = new JXMapViewer();
final int max = 17;
TileFactoryInfo info = new TileFactoryInfo(1,max-2,max,
256, true, true, // tile size is 256 and x/y orientation is normal
"http://tile.openstreetmap.org",
"x","y","z") {
public String getTileUrl(int x, int y, int zoom) {
zoom = max-zoom;
String url = this.baseURL +"/"+zoom+"/"+x+"/"+y+".png";
return url;
}
};
TileFactory tf = new DefaultTileFactory(info);
map.setTileFactory(tf);
map.setZoom(11);
map.setAddressLocation(new GeoPosition(51.5,0));
return map;
}
}
Figure 1: JXMapViewer Component 생성하기
JavaFx graphic scene에서 JXMapViewer 컴포넌트를 사용하기 위해서는 SwingComponent.wrap() 함수를 사용하는 원래 컴포넌트로 부터 SwingComponent 인스턴스를 생성해야 합니다. 그리고 나서 여러분은 Figure 2에서 처럼 직접 컴포넌트에 크기를 지정해 줘야합니다(이 경우 400x200).
var map = SetupMap.create(); map.setPreferredSize(new java.awt.Dimension(400,300)); var mapComp = SwingComponent.wrap(map);
Figure 2: SwingComponent Class 으로 JXMapViewer 감싸기
SwingComponent는 javafx.scene.Node의 subclass이기 때문에 여러분이 다른 노드들에 애니메이션, 변형(transforms) 그리고 특별한 효과들을 할수 있는 멋진 것들을 할수 있습니다. 이 예제에서 저는 모둥이를 둥글게 하기 위해서 모서리가 둥근 사각형 클립을 컴퍼넌트 위에 놓고나서 컴퍼넌트의 최상단에 가장자리(border)를 추가 했습니다. Figure 3를 보세요.
mapComp.clip = Rectangle {
width: 400 height: 300
arcHeight: 30 arcWidth: 30
};
var mapGroup = Group {
opacity: 0.01
translateX: 300-400/2
translateY: 200-300/2
scaleX: bind scale
scaleY: bind scale
content: [
mapComp,
Rectangle { width: 400 height: 300
arcHeight: 30 arcWidth: 30
stroke: Color.WHITE
strokeWidth: 3
fill: null
}
]
};
Figure 3: 선과 둥근 모서리 추가하기
마지막으로 저는 Figure 4에서 보여지는 것 처럼 화면 전체 위에 지도 확대 기능과 움직이는 텍스트를 만들기 위해 스케일 효과를 사용하곤 합니다. 모든 이런 변화중에도 스윙 컴포넌트는 여전히 어떤 일반적인 스윙 컴포넌트라도 하는 마우스 이벤트를 받고 자신을 repaint 할수 있는것을 의미하는 "live" 상태입니다. 지도 아래 텍스트는 true로 설정하여 어떤 클릭을 하더라도 지도를 통과할수 없도록 하는 blocksMouse 변수를 가지고 있습니다. 그러나 만약 여러분이 지도 위에서 드래그를 시작하고 테스트를 넘어가더라도 지도는 여전히 드래그 이벤트들을 올바르게 받을 것입니다. JavaFX 런타임은 JavaFX 그래픽과 함께 Swing interact를 고르게 만들기 위해서 conversion necessary의 모든걸 다룹니다.
var bigText:Text = Text {
content: "Swing + JavaFX"
font: Font.font("Verdana",FontWeight.BOLD,50)
fill: Color.BLACK
stroke: Color.ORANGE strokeWidth: 2
y: 130 x: -600
blocksMouse: true
onMouseEntered:function(e:MouseEvent) {
bigText.fill = Color.WHITE
}
onMouseExited:function(e:MouseEvent) {
bigText.fill = Color.BLACK
}
};
var scale = 0.3;
var zoomIn = Timeline {
keyFrames: [
at(0s) { scale=>0.3 tween Interpolator.LINEAR},
at(0s) { mapGroup.opacity=>0.0 tween Interpolator.LINEAR},
at(1s) { scale=>1.0 tween Interpolator.LINEAR},
at(1s) { mapGroup.opacity=>1.0 tween Interpolator.LINEAR},
at(0.5s) { bigText.x => -300 tween Interpolator.LINEAR},
at(2s) { bigText.x => 85 tween Interpolator.LINEAR},
]
};
Stage {
width: 600
height: 400
scene: Scene {
fill: Color.BLACK
content: [
Rectangle { x: 35 width: 40 height: 20 fill: Color.web("#444444") stroke: Color.web("#888888")
onMousePressed: function(e:MouseEvent) {
zoomIn.playFromStart();
}
},
Text { content: "Show" x: 40 y: 15 fill: Color.BLACK},
mapGroup,
bigText,
]
}
}
Figure 4: Putting Text Above the Map
Josh Marinacci썬마이크로시스템즈의 엔지니어