原作者: Anghel Leonard
时间:08/01/2007
翻译:Caoer
2007年8月8日
JavaFX 代码同Java代码极容易集成. 这有一个使用JavaFX装载一个图片到窗体例子,它允许
使用者选择一个矩形区域保存这个矩形区域。这个捕捉保存操作由Java代码完成。
源码列表 15
import java.io.*;
import javafx.ui.*;
import javafx.ui.canvas.*;
import javafx.ui.filter.*;
import java.awt.Robot;
import java.awt.Rectangle;
import java.awt.image.RenderedImage;
import javax.imageio.ImageIO;
import java.lang.System;
class CaptureExample extends CompositeNode{
attribute lx: Integer;
attribute ly: Integer;
operation CaptureExample();
attribute CaptureExample.lx = 0;
attribute CaptureExample.ly = 0;
operation saveCapture(lx_copy:Integer, ly_copy:Integer) {
var robot = new Robot();
var rect = new Rectangle (lx_copy, ly_copy, 50, 50);
var BI=robot.createScreenCapture(rect);
var file = new File(".//capture.jpg");
ImageIO.write((RenderedImage)BI, "jpg", file);
}
function CaptureExample.composeNode() =Group{
transform: []
content:[ImageView {
transform: []
image: Image { url: ".//app//Sunset.gif" }
cursor: DEFAULT
onMouseClicked: operation(e:CanvasMouseEvent) {
saveCapture(e.source.XOnScreen,e.source.YOnScreen);
}
onMouseMoved: operation(e:CanvasMouseEvent) {
lx = e.x; ly = e.y;
}
},
Rect{
x: bind lx y: bind ly width: 50 height:50 strokeWidth: 1 stroke: black }]
};
Frame {
centerOnScreen: true
visible: true
height: 230
width: 300
title: "Capture the screen..."
onClose: operation() {System.exit(0);}
content: ScrollPane {
background: white
view: Canvas {
background: black
cursor: DEFAULT
content: CaptureExample }
}
}
bind的用法. 它是一个用作增值和属性的延迟验证的重要JavaFX操作符。你能够从JavaFX编程语言文档中获得关于这个操作符的
更多信息。 同时需要注意的是,在上面程序中,用两个鼠标事件鼠标点击(onMouseClicked)和鼠标移动(onMouseMoved)。
JavaFX支持以下的鼠标事件:
· onMouseClicked --鼠标点击
· onMouseMoved --鼠标移动
· onMousePressed --按住鼠标
· onMouseExited --鼠标关闭
· onMouseEntered --鼠标输入
· onMouseReleased --释放鼠标
· onMouseDragged --鼠标拖拽
你能狗使用JavaFX do later 语句进行异步执行的操作,参考代码如下:
源码列表 16
//使用do later 语句进行异步执行
import java.lang.System;
var s1 = "My name is ";
var s2 = "Anghel Leonard";
do later {
System.out.println(s2);
}
System.out.println(s1);
结果: My name is Anghel Leonard
JavaFX 允许你通过把要执行的代码放在do语句里面而使你能够在一个独立线程里执行代码一部分。使用AWT事件分派线程技术,将能够处理所有的输入事件。先面有一个使用在do语句中使用无线循环的例子。注意即使你有一个无限循环也能正常关闭窗口。
Listing 17
import javafx.ui.*;
import java.lang.System;
import javafx.ui.canvas.*;
import java.util.Random;
class DoExample extends CompositeNode{
attribute randomfill: Color;
operation changeOpacity();
}
attribute DoExample.randomfill = Color{red:0 green:0 blue:0};
operation DoExample.changeOpacity() {
do{
while(true) {
var r = new Random();
var g = r.nextInt(255);
randomfill = Color{red:g green:g blue:g};
}
}
}
function DoExample.composeNode() =Group {
transform: []
content: [ Text { x: 20 y: 20 content: "Because of \"do\" you can close this window..."
font: Font {face: VERDANA, style: [ITALIC, BOLD], size: 20}
fill: bind randomfill opacity: 0.5
onMouseClicked: operation(e:CanvasMouseEvent) { changeOpacity(); } }]
};
Frame {
centerOnScreen: true
visible: true
height: 100
width: 580
title: "\"Do\" example..."
onClose: operation() {System.exit(0);}
content: ScrollPane {
background: white
view: Canvas {
background: black
cursor: DEFAULT
content: DoExample
}
}
}
JavaFX 代码能够用JavaFX标签类同HTML代码集成。这个类支持以web应用程序一样的使用模式使用HTML和CSS技术。
Here is an example that renders an HTML table.
Listing 18
import javafx.ui.*;
import java.lang.System;
import javafx.ui.canvas.*;
class Partners {
attribute name: String;
attribute company: String;
attribute phone: String;
attribute e_mail: String;
attribute partners: Partners*;
}
var myPartners = Partners {
partners: [Partners{
name: "Mary J"
company: "Software ATV Inc."
phone: "0900090345"
e_mail: "maryj@yahoo.com" },
Partners{
name: "Leona W"
company: "Winkle LTD"
phone: "090849435"
e_mail: "leonaw@yahoo.com" },
Partners{
name: "Joe T"
company: "Press OJ"
phone: "340909879"
e_mail: joet@yahoo.com
}
] };
Frame {
content: Label {
text: bind "<html> <h2 align='center'>- My Partners -</h2>
<table align='center' border='0' bgcolor='#BBAAEE'>
<tr bgcolor='#FFEE55'>
<td><b>Name</b></td> <td><b>Company</b></td> <td><b>Phone</b></td> <td><b>E-mail</b></td>
</tr> {
if (sizeof myPartners.partners == 0)
then "<tr bgcolor='#432211'><td colspan='8'><b> I have no partners...</b></td></tr>"
else foreach (t in myPartners.partners)
"<tr bgcolor='#FF25AD'>
<td>{t.name}</td>
<td>{t.company}</td>
<td>{t.phone}</td>
<td>{t.e_mail}</td>
</tr>"
}
</table> </html>" }
visible: true
}
图 7. 运行源码列表 18
在本文章最后一小节,我们将能够看到展示如何简单使用JavaFX构建复杂的动画效果的两个程序。第一个程序仿真一个时钟。这个设计基于使用JavaFX代码创建的四个图片。
see two applications that illustrate how easy it is to build complex animations using JavaFX. The first application simulates an analog clock. The design is based on four images animated with JavaFX code.
Listing 19
import javafx.ui.*;
import javafx.ui.canvas.*;
import javafx.ui.filter.*;
import java.lang.System;
class Clock extends CompositeNode{
attribute seconds: Number+;
attribute minutes: Number+;
attribute hours: Number+;
operation startClock();
}
attribute Clock.seconds = 360;
attribute Clock.minutes = 360;
attribute Clock.hours = 360;
operation Clock.startClock() {
do{
while(true) {
if(seconds>=360)
{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;}
}
}
}
function Clock.composeNode() = Group {
onMouseClicked: operation(e:CanvasMouseEvent) {
startClock();
}
transform: [] content:[ImageView {
image: Image { url: ".//app//clockempty.gif" }
},
ImageView {
transform: bind [translate(203,82),
rotate (seconds,2.5,125)]
image: Image { url: ".//app//l1.gif" }
antialias: true },
ImageView {
transform: bind [translate(203,100),
rotate (minutes,2.5,107)]
image: Image { url: ".//app//l2.gif" }
antialias: true },
ImageView {
transform: bind [translate(203,115),
rotate (hours,2.5,92)]
image: Image { url: ".//app//l3.gif" }
antialias: true },
Circle {
cx: 205
cy: 205
radius: 13
fill: red strokeWidth: 1 }]
};
Frame {
centerOnScreen: true
visible: true
height: 450
width: 450
title: "JavaFX - Clock"
onClose: operation() {System.exit(0);}
content: ScrollPane {
background: white
view: Canvas { background: black cursor: DEFAULT content: Clock }
}
}
图 8. 运行源码列表 19
注意dur(duration)操作符。 JavaFX 提供该操作符主要是为了创建动画。它用来异步产生一个数组构建一个时间间隔 队列。从这个数组返回一个元素之前,JavaFX要等到计时等于指定的毫秒。这个处理重复执行直到所有元素都被返回。有四种插入算法类型:
- linear
- easein
- easeout
- easeboth
默认是 ease-in, ease-out 结合.
第二个程序模拟了一个弹出菜单的集合,菜单能够在屏幕上拖拽。 简单点击以下菜单头部,您就能 使用一个很好的不透明效果隐藏或者显示条目。整个设计使用JavaFX绘画功能实现。
源码列表20
import javafx.ui.*;
import javafx.ui.canvas.*;
import javafx.ui.filter.*;
import java.lang.System;
class MenuOptions extends CompositeNode{
attribute px: Integer;
attribute py: Integer;
attribute lx: Integer;
attribute ly:Integer;
attribute lw:Integer;
attribute itemsOpacity:Number;
attribute menutext: String;
}
trigger on new MenuOptions {
this.px = 0;
this.py = 0;
this.menutext = "";
this.lx = 0;
this.ly = 0;
this.lw = 150;
this.itemsOpacity = 0.0;
}
function MenuOptions.composeNode() = Group {
transform: bind []
opacity: bind itemsOpacity
content:[
Rect {
x: bind lx
y: bind ly
width: lw
height: 20
arcHeight: 10
arcWidth: 10
fill: Color {red:190 green:181 blue:215}
stroke: Color {red:68 green:54 blue:103}
strokeWidth: 2
onMouseEntered: operation(e:CanvasMouseEvent) {
if(itemsOpacity == 0.7)
{itemsOpacity = 1.0;} }
onMouseExited: operation(e:CanvasMouseEvent) {
if(itemsOpacity == 1.0)
{itemsOpacity = 0.7;} }
onMouseClicked: operation(e:CanvasMouseEvent) {
eventListener(this.menutext); }
},
Text {
x: bind lx+5
y: bind ly+5
content: bind menutext
font: Font {face: VERDANA, style: [BOLD], size: 11}
fill:Color {red:68 green:54 blue:103} }]
};
class MainMenu extends CompositeNode{
attribute option: String;
attribute px: Integer;
attribute py: Integer;
attribute lx: Integer;
attribute ly:Integer;
attribute lw:Integer;
attribute menutext: String;
attribute step: Integer;
attribute submenu: MenuOptions+;
operation addSubmenu(t:MenuOptions);operation show_hide();
}
trigger on new MainMenu {
this.option = "";
this.px = 0;
this.py = 0;
this.menutext = "";
this.lx = 0;
this.ly = 0;
this.lw = 150;
this.step = 20;
this.submenu = null;
}
operation MainMenu.addSubmenu(t:MenuOptions) {
t.lx = this.lx;
t.lw = this.lw;
t.ly = this.ly+step;
step=step+20;
insert t into submenu;
}
operation MainMenu.show_hide() {
if(submenu.itemsOpacity[1] == 0.7)
{submenu.itemsOpacity = [0.7,0.6,0.5,0.4,0.3,0.2,0.1,0.0] dur 1200;}
else if(submenu.itemsOpacity[1] == 0.0){ submenu.itemsOpacity = [0.1,0.2,0.3,0.4,0.5,0.6,0.7] dur 1200;}
}
function MainMenu.composeNode() = Group {
transform: bind []
content:[Rect {
x: bind lx
y: bind ly
height: 20
width: bind lw
arcHeight: 10
arcWidth: 10
fill: Color {red:68 green:54 blue:103}
stroke: Color {red:190 green:181 blue:215}
strokeWidth: 2
onMouseDragged: operation(e:CanvasMouseEvent) {
lx += e.localDragTranslation.x;
ly += e.localDragTranslation.y;
submenu.lx += e.localDragTranslation.x;
submenu.ly += e.localDragTranslation.y;
}
onMouseClicked: operation(e:CanvasMouseEvent) {
show_hide();
}
},
Text {
x: bind lx+5
y: bind ly+5
content: bind menutext
font: Font {face: VERDANA, style: [BOLD], size: 11}
fill:Color {red:190 green:181 blue:215} }, bind submenu]};
var menu_1 = new MainMenu();
menu_1.lx = 120;
menu_1.ly = 140;
menu_1.lw = 128;
menu_1.menutext = "Navigate";
var submenu_11 = new MenuOptions();
submenu_11.menutext = "Go to Class...";
var submenu_12 = new MenuOptions();
submenu_12.menutext = "Go to Test";
var submenu_13 = new MenuOptions();
submenu_13.menutext = "Back";
var submenu_14 = new MenuOptions();
submenu_14.menutext = "Forward";
var submenu_15 = new MenuOptions();
submenu_15.menutext = "Go to Line...";
menu_1.addSubmenu(submenu_11);
menu_1.addSubmenu(submenu_12);
menu_1.addSubmenu(submenu_13);
menu_1.addSubmenu(submenu_14);
menu_1.addSubmenu(submenu_15);
var menu_2 = new MainMenu();
menu_2.lx = 260;menu_2.ly = 140;
menu_2.lw = 90;
menu_2.menutext = "Refactor";
var submenu_21 = new MenuOptions();
submenu_21.menutext = "Rename....";
var submenu_22 = new MenuOptions();
submenu_22.menutext = "Pull Up...";
var submenu_23 = new MenuOptions();
submenu_23.menutext = "Push Down...";
menu_2.addSubmenu(submenu_21);
menu_2.addSubmenu(submenu_22);
menu_2.addSubmenu(submenu_23);
operation eventListener(s:String) {
System.out.println("You choose:{s}");
}
Frame {
centerOnScreen: true
visible: true
height: 500
width: 500
title: "JavaFX - Menu"
onClose: operation() {System.exit(0);}
content: ScrollPane {
background: white
view: Canvas {
background: black
cursor: DEFAULT
content: [menu_1, menu_2] }
}
}
图 9. 运行源码列表 20
注意JavaFX使用触发者(与SQL相似)代替构造函数、 instead of constructors.
一个触发者使用trigger 关键字有头部和体构成。头部指示执行体内容以前必须发生的实践。触发者能狗被创建、插入、删除或者替代。你能在OpenJFX网站上发现关于triggers更多细节。
小结
JavaFX 脚本是面向Java平台的一个非常有能力的新语言。使用它你能够在比使用Swing和Java2D更短时间内更容易地建立丰富、动态界面。在本文中,你能够了解关于它的基本语法
,同时找到IDE支持,建立展示JavaFX能力的Demo小程序。JavaFX将很快变成Java开发者的工具箱中必要工具。
资源:
凡是有该标志的文章,都是该blog博主Caoer(草儿)原创,凡是索引、收藏
、转载请注明来处和原文作者。非常感谢。