用纯Java代码调用JavaFX的功能

分类: JavaFX技巧, JavaFX编程.
标签: , , , ,

在JavaFX 1.0发布之后,本人撰写的文章JavaFX和Java之间的互操作性被各网站转载。文中总结了3种从Java调用JavaFX的方法。这三种方法分别为:

1. 用ScriptEngineManager类。这是基于JSR-223规范的java脚本API( scripting API)。可以在java程序中运行一些脚本,如 JavaFX script, javascript等。
2. 通过JavaFX reflection API。这是JavaFX提供的反射API,几乎可以调用所有的JavaFX类。
3. 先用JavaFX类实现一个Java的interface,然后Java程序可以通过这个interface来调用JavaFX的功能。这中间的interface起了个桥梁的作用。


第三种方法应该是比较“正规”而且“优美”的调用方式。但是也有一点不足:程序代码的入口必须从JavaFX启动。这是因为JavaFX程序比较容易生成JavaFX类的实例,从而可以供Java方使用。可是我们有时会碰到一些特定的情况,需要从Java端启动代码。例如,如果你已经有了一个较完整的Java程序,你需要用调用JavaFX的某些功能,这时候较好的方法是把Java作为程序的入口。为了解决这个问题,我把第2和第3种方法作了融合,大家可以看看下面的例子。


假定我们需要从Java中调用JavaFX的图表(charting)功能。我们首先用JavaFX reflection API生成JavaFX类的实例。然后我们再通过java的interface来使用它。因此,我们先定义一个Java的interface:

/*
 * JavaInterface.java
 *
 * @author Henry Zhang      http://www.javafxblogs.com
 */
package javatest;
public interface JavaInterface {
  public void addData(String name, float data);
  public void showChart();
}


下一步是创建JavaFX类MyChart来实现这个interface:

/*
 * MyChart.fx
 *
 * @author Henry Zhang     http://www.javafxblogs.com
 */
package javatest;

import javafx.scene.chart.PieChart;
import javafx.scene.Scene;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import javafx.scene.chart.PieChart3D;

public class MyChart extends JavaInterface {
  var chartData :  PieChart.Data[] = [];

  public override function addData( l:String, v: Number):Void {
    var labelString = l;

    var data =  PieChart.Data {
      label : l
      value : v
      action: function() {
        println("{labelString} clicked!");
      }
     } ;

    insert data into chartData;
  }

  public override function showChart() : Void {
    var chart =
      PieChart3D {
        data : chartData
        pieThickness: 25
        pieLabelFont: Font{ size: 9 };
        pieToLabelLineOneLength: 10
        pieToLabelLineTwoLength : 20
        pieLabelVisible: true
        pieValueVisible: true
        translateY: -50
     };

    Stage {
      title: "PieChart Window"
      width: 520
      height: 300
      scene: Scene {
        content: [
          Text {
            font : Font {
                    size : 16
                   }
            x: 200
            y: 20
            content: "Pie Chart"
          },
          chart
        ]
      }
    }
  }
}


最后就是从java类JavaTest中调用图表功能:

/*
 * JavaTest.java
 * @author Henry Zhang    http://www.javafxblogs.com
 */
package javatest;

import javafx.reflect.FXClassType;
import javafx.reflect.FXLocal;
import javafx.reflect.FXLocal.Context;
import javafx.reflect.FXLocal.ObjectValue;

public class JavaTest {
  public static void main(String args[]) {
    Context context = FXLocal.getContext();
    FXClassType instance = context.findClass("javatest.MyChart");
    ObjectValue obj = (ObjectValue)instance.newInstance();

    JavaInterface ji = (JavaInterface)obj.asObject();

    String [] labels = {"January", "Febuary", "March", "April"};
    int [] values = { 18, 20, 25, 37 };

    for ( int i=0; i < values.length; i++ ) {
      ji.addData(labels[i], values[i]);
    }

    ji.showChart();
  }
}


在代码中,这3句是创建JavaFX类javatest.MyChart实例,

    Context context = FXLocal.getContext();
    FXClassType instance = context.findClass("javatest.MyChart");
    ObjectValue obj = (ObjectValue)instance.newInstance();



而一下这句则是把JavaFX实例转化为Java可用的对象:

    JavaInterface ji = (JavaInterface)obj.asObject();


如果你用的是NetBeans IDE, 你可以在项目属性中把javatest.JavaTest类设为主类(Main class)(即启动类)。编译之后会生成一个javatest.jar文件。程序运行的结果如图:

Java PieChart via JavaFX


在命令行中可以采用以下方式:

   javafx -jar javatest.jar


实际上,可以用纯Java的方式来启动程序,只要把JavaFX的运行环境带上即可,如:

 java -Djava.library.path="<path to javafx sdk lib>"
     -classpath "<all javafx sdk jars>" -jar javatest.jar



因为JavaFX需要的jar文件很多,因此这种“最纯”的java方法使用起来比较麻烦。我觉得还是用javafx命令简洁些, 而且javafx就是上述java命令的封装而已。


如果有问题,请留言讨论。

本文的英文译文同步发表于:Calling JavaFX Classes from Pure Java Code.

评论 (0) 2009年06月21日

JavaFX吃豆人游戏的编写过程之四

分类: JavaFX编程, 吃豆人游戏.

JavaFX吃豆人游戏的第五篇文章上周已经发表。在最后的这篇文章中,详细介绍了精灵追逐吃豆人的算法。这可能是该游戏代码中最有趣的部分了。


在游戏编写时,通常需要考虑一些要素,如算法的效率、随机性、简洁度等。在文章中对这些问题都作了讨论。 在追逐算法中,程序采用了比较简单的距离优先的逼近算法。如下图所示:


图中的红色精灵从右到左移动,当它在交叉路口时,它可以选择向上或者向左移动。如果我们把它和吃豆人之间的X/Y方向上的距离和作为一个评估指标的话,我们可以得到这样一个结论: 向左走的距离为14,向上走距离缩短为12。因此向上可以使得红精灵更加逼近吃豆人。通过计算,我们就可以知道向上是个比较好的选择。如果吃豆人吞下魔法豆,我们只需要把积分方式取负运算,就可以立刻成为一个精灵的逃离算法。网上还有许多关于算法的介绍,但作为例子,本文中仅介绍一个最简单和最易实现的算法。全文可以参考这里。点击下图可以启动完整的吃豆人游戏:(JDK 1.5以上)


启动游戏

启动游戏


相关文章:

JavaFX应用实例、例子
用JavaFX编写的游戏Pac-Man
JavaFX实例探索教程
JavaFX特性和编程实例代码
JavaFX 1.2 程序迁移指南

快速升级到JavaFX SDK 1.2的方法
JavaFX吃豆人游戏的编写过程之二
JavaFX游戏吃豆人的编写过程


英文文章连载:


2009年5月14日 - 2009年6月11日:
Writing the Pac-Man Game in JavaFX


评论 (0) 2009年06月18日

JavaFX吃豆人游戏在JavaOne上演示

分类: JavaFX新闻, 吃豆人游戏.
标签: , , , ,

JavaOne 2009的内容可以下载了,链接是http://developers.sun.com/learning/javaoneonline/。其中JavaFX的讲座在“Rich Media Applications and Interactive Content”类别中,需要注册一个Sun Developer Network的帐号才能看到这些PDF文件。


JavaOne的演讲者之一Stephen Chin告知,我写的JavaFX Pac-Man(吃豆人)游戏在他的两个讲座中都作了现场演示,非常成功。这个游戏是Jim Weaver提出的一个挑战,他希望我把Pac-Man游戏改写成WidgetFX的widget,Stephen也答应在JavaOne上demo。虽然只有不够一周的时间,但好在WidgetFX的API比较易用,所以我仅用了2天就完成了(详见英文博客Challenge on Pac-Man Game Widget)。等WidgetFX SDK 1.2推出之后,再把代码更新后给大家分享一下。虽然不能亲临JavaOne,但是自己的游戏能登上大讲台,也是件很高兴的事。


JavaOne 吃豆人游戏演示
JavaOne 吃豆人游戏演示



这两个JavaOne演示吃豆人游戏的讲座是:

Pro JavaFX Platform: RIA Enterprise Application Development with JavaFX Technology

Getting Started with WidgetFX: Open-Source Widget Desktop Platform with JavaFX Technology



相关文章:

JavaFX吃豆人游戏编写过程详解(英文)

JavaFX吃豆子游戏编写过程(中文)

评论 (0) 2009年06月16日

JavaFX 1.2 程序迁移指南

分类: JAVAFX技术, JavaFX编程.
标签: , , ,

javafxblogs.com Rss_google Rss_zhuaxia Rss_xianguo


本文系经原作者Stephen Chin授权翻译,英文原文:The Definitive 1.2 Migration Guide,为方便起见,英文原文的副本也可参见本站转载。有关代码迁移和JavaFX 1.2新特性内容,还可以参考JavaFX网站的文章,或者本站文章JavaFX 1.2的新特性。以下译文中的红字部分为译者加注。



本文包含了从JavaFX 1.1迁移程序到JavaFX1.2最常见的变化,例如如语言本身、功能以及API的改变。如果你发现本文没有提到的变化,请在评论中留言。


基本原则

1) JavaFX 1.2 的二进制不兼容性:对于原来的jar文件或者其它第三方的JavaFX库,如JFXtras,必须经过重新编译才能在和JavaFX 1.2的代码兼容,否则会有编译错误。JFXtras将发布基于JavaFX 1.2的更新,新的版本就快就绪了。

2)内部的API将不能用了,如果你的代码包含了impl_或者sun.com的包,你的代码肯定需要修改。

3) 支持Linux和Solaris, 这是应该说是个新功能,这样你可以对用户自豪的宣称支持Linux。译者注:这里的Solaris应指OpenSolaris。


语言上的变化 JavaFX教程、实例、Demo

1)嵌套的块语句中不可以再有变量屏蔽(Shadowing)。原来可以有同名的变量分别处于内层和外层的块语句中,在内层的语句中的变量可以覆盖外层的同名变量。在JavaFX 1.2种,需要修改变量的名字来避免重名。

2)用mixin代替多类继承性。JAVAFX不再支持多类继承性,但是你可以继承一个类和多个mixin类。Mixin就像java中的interface,不同的是它可以有变量和已实现的方法,使得所有子类都可以使用。这点需要的修改也不多,只需要把原来多继承的类加上mixin关键字即可,如:

public mixin class Resizable { /* variables and functions here */ }

译者注:mixin也可以理解成可以多继承的抽象类(abstract class)

3) 在Sequence中,需要用逗号来分隔元素(除了那些用花括号结束元素)。这有点不方便,但实际上是件好事,因为可以避免以前很难追查的语言陷阱。JavaFX 1.2的新特性


Node类的变化 JavaFX编程实例

1)Node.boundsInScene 属性没有了,主要是性能方面的原因,好在有个容易替换且功能相同的调用:

node.localToScene(node.boundsInLocal)


2) Node.focusable 变为 Node.focusTraversable,虽是很小的API变化,但你应知道这点以免碰上编译错误。这是有关focus功能修正的一部分:当某个Node可见(visible)、可聚焦遍历(focusTravserable)并且没被禁用时,可以得到聚焦。(key listener将不再需要)

3) CustomNode.create() 将在 init 块之前调用,原来的方式是create()方法调用在init之后,在postinit之前。既然现在的调用在init之前,那么需要注意的是变量初始化的顺序,可能需要调整一些代码。

4) SwingControl.enabled -> Node.disable 这是一个在Node类中新的标志,统一地控制启用和禁用(enable/disable)。与之矛盾的SwingControl.enabled变量已经去掉了。

5) Rectangle2D -> Bounds 所有Rectangle2D的引用已经改为javafx.geometry.Bounds类了,在代码中可能会产生连锁反应。升级到JavaFX 1.2的简便方法


Layout类的变化 JavaFX Demo Game

1) min/max/pref -> getters 所有Resizable类的属性 (minimumWidth, minimumHeight, maximumWidth, maximumHeight, preferredWidth, preferredHeight) 已被替换为getter函数(getMinWidth, getMinHeight, getMaxWidth, getMaxHeight, getPrefWidth, getPrefHeight respectively)。其中 prefWidth/Height 函数可以代一个额外的参数,即在另一维度的空间大小。在高/宽有约束的layout中,如Flows,会非常有用,但也可以用-1来忽略该参数。

2) impl_layoutX/Y -> layoutX/Y 方法impl_layoutX和impl_layoutY正式替换为layoutX和layoutY变量。建议你使用这组变量来移动node到某个位置,这比translateX/Y要好。

3) impl_requestLayout() -> requestLayout()。 requestLayout 函数类似地从内部转为公开的API.

4) impl_layout -> doLayout()。 原来是用函数类设置layout,现在改为覆盖Parent.doLayout().

5) 增加了Panel类的声明式Layout。如果你在寻找功能上替代Container的方法,可以看看新的Panel类,它可以声明式设置layout,而且,它还能够通过变量覆盖min/max/pref缺省值,从而不用产生Container的子类.

6) Container中的新函数帮助实现布局(layout)。Container类里面有很多新函数,使得很容易来使用新的布局系统。切记要先完全读一遍,因为这样可以使你节约时间,同时可以遵循布局的最佳实践。

7) 不同的变换(transformation)顺序。过去transforms[]变量可让你在layoutBounds中使用变换,而scaleX/translateX/rotate等可以作用在布局之后. 现在transforms[]和transformation变量都统一在布局之后进行计算。


Skin/Control的变化: JavaFX技术应用编程交流

1) Skin.scene -> Skin.node。这个属性名称的变化可以减少易混淆的Scene类所带来的困惑。

2)去掉了Skin.computeXXX的方法。曾经有过一系列的computePreferredWidth/Height等方法,现在可直接用getPrefWidth/Height等函数,参见上文提到的Resizable类。


3)Skin成为抽象类。需要你实现contains和intersects方法。你可以使用新的JFXtras中的AbstractSkin类,或使用以下样板代码:

override function contains(localX:Number, localY:Number):Boolean {
    return node.contains(localX, localY);
}   

override function intersects(localX:Number, localY:Number,
      localWidth:Number, localHeight:Number):Boolean {
    return node.intersects(localX, localY, localWidth, localHeight);
}


4)新的行为(Behavior)类。这个类可以和Control及Skin一起使用来提供可重用的行为。

5)TextBox.text -> rawText, TextBox.value -> text。TextBox类现在重新调整了,text变为rawText,意义不变.


异步处理的变化: JavaFX Guy的博客
1) RemoteTextDocument类没有了。直接用HttpRequest类替代. 译者注:对于原来和后台Server交互的程序要小心这个变化,代码需要调整。

2) AbstractAsyncOperation类没有了。用新的任务基础设施来替代后台Java线程的通信。


动画(Animation)的变化: JavaFX教程、例子、编程论坛

1) Transition.interpolate -> Transition.interpolator。属性名称的改变,使得interpolate标志具有新的含义:可以成为是否做插值运算的开关。

2)Transition现在是继承Timeline类。这是个受欢迎的修改,使得Transitions很容易与Timelines一起使用。因为这个变化,ParallelTransition和SequentialTransition类现在可以有一个sequence保存的Timeline实例。 译者注:这个变化比较有意义,因为原来的Transition也可以作为动画的一种机制,容易令人糊涂。

译者注:以下两点从javafx.com中摘录翻译。

3)KeyFrame中不再提供timelines变量,但是可以用ParallelTransition和SequentialTransition这两个类来实现同样的功能。

4)Transition类中的timelineDirty变量由markDirty()方法替代。


和Java相同的函数: JavaFX Discussion Blog

1)java.lang.Math -> javafx.util.Math。新的JavaFX数学函数库, 使用JavaFX数学库的好处是可以在移动设备上应用(包括pow, log, 等)。

2)java.lang.Properties -> javafx.util.Properties。和Java相似的又一个类,但是可以移植到移动设备上。但需要注意的是,JavaFX的属性文件和Java属性文件格式不一致。


CSS支持的变化:

1)CSS 更新的缺陷(RT-4817)。样式(Stylesheet)的更新不再影响新增的Nodes。同时,你可以强制stylesheet的更新,方法如下:

def senators = bind model.senators on replace {
    delete sceneRef.stylesheets;
    sceneRef.stylesheets = "{__DIR__}styles.css";
}


2) CheckBoxSkin.textFill 不接受样式(RT-4819)。选项标志本身可以使用你所设置的样式(style),但是文本却不行。现在变通的做法是创建没有文本的checkbox,然后在旁边加上一个具有样式和事件处理机制的文本接点(text node)。

3) 不能从CSS中更新control中的skin属性 (RT-4820) 。这曾经是另一个skin支持上的bug。现在可以在代码中实现了。


Production Suite: 作者Henry Zhang的JavaFX技术博客

1) UiStub -> FXDNode。UiStub类现用FXDNode替代了, 增加了更多的功能,包括后台加载(backgroundLoading)和临时替代图像(placeholder images)。 译者注:以下代码示例来自javafx.com:

Scene {
  content: FXDNode {
     url: "{__DIR__}mygraphics.fxz"
     backgroundLoading: true
     placeholder: Text { x: 10 y: 10 content: "Loading graphics ..."}
   }
}


其它:
1) Image.fromBufferedImage()取消了。功能移至SwingUtils.toFXImage()。要记住的是,使用这个函数会在移植代码到移动设备时受到限制。

2) Color.fromAWTColor()取消了。这又是一个AWT痕迹的销除。JavaFX的Color类应该是非常完善的了,所以没有什么理由我们还要继续使用AWT的色彩体系。

3) Duration.toDate没有了。据我所知,应该没有相应的函数,但是我们总是可以获取duration的整数值然后直接操作它。

4) Affine类中不同的变量名称。如果你用到了Affine类, 你的代码很可能需要修改了,因为变量名称换成了更有说明性的方法名,但是功能还是一样的。


评论 (0) 2009年06月14日

JavaFX 1.2 迁移指南(英文)

分类: JAVAFX技术, JavaFX编程.
标签: , , ,

本文经授权转载自Stephen Chin的英文文章The Definitive 1.2 Migration Guide中文翻译参见这里

Below is the JavaFX 1.2 migration guide written by Stephen Chin. The original article can be found on his blog steveonjava.com. I post his article here for readers who cannot visit Stephen’s blog due to networking problem. Steve, thanks a lot for allowing me to share it here. The Chinese translation can be found here.

The Definitive 1.2 Migration Guide

by Stephen Chin


If you have made it this far, you are a serious JavaFX hacker!  This section covers the most common language, functionality, and API changes that you will encounter when migrating applications from JavaFX 1.1.  If you notice anything that is not covered, feel free to add it in the comments and I will update the guide as appropriate.


General:

  • JavaFX 1.2 is not binary compatible – If you use any jars or third-party JavaFX libraries (such as JFXtras), they must be recompiled for the new release or you will get compilation errors.  Speaking of JFXtras, a new version which has been updated for JavaFX 1.2 is nearly ready, and will be announced here when it is complete!
  • All internal-only APIs are broken – More details broken out by section below, but if you rely on any impl_ or com.sun packages, your code will definitely need to be updated.
  • Linux and Solaris are now supported – This is more of a feature than a migration issue, but if you have users on multiple platforms you can now proudly state that Linux is supported.


Language Changes:

  • No more variable shadowing in nested blocks – It previously was valid to name a variable the same in both the inner and outer block of an expression.  The variable in the inner block would simply replace the one in the outer.  However, this will throw a compiler error in JavaFX 1.2.  The fix is simple…  just use a different variable name.
  • Use Mixins instead of Multiple Inheritance – JavaFX no longer supports multiple inheritance.  Instead you can extend one class and as many mixins as you like.  Mixins are like interfaces in Java, except they can have variables and implementations that are shared by all the classes that extend them.  The only change you have to make in your application to start using mixins is to add the mixin keyword when you define a new class like this:
public mixin class Resizable { /* variables and functions here */ }
  • Commas are required in sequences – Sequences now require commas between elements (except those that end in braces).  This is a little less convenient, but actually a very good thing, because it avoids several language pitfalls that were hard to track down before.


Node Changes:

  • Node.boundsInScene is gone – This was removed for performance reasons, fortunately there is an easy replacement that offers the same functionality:
node.localToScene(node.boundsInLocal)
  • Node.focusable -> Node.focusTraversable – Small API change, but good to know when you get the compilation error on focusable not found.  This is part of a larger focus fix where any Node that is visible, focusTraversable, and not disabled will be eligible for focus (a key listener is no longer required).
  • CustomNode.create() gets called before init – Previously the CustomNode create() method would get called after init and before postinit.  Now that it gets called even earlier than init, some of your code may not work correctly.  Make sure that any variables you are depending upon in the create() method are either initialized inline or have a bind declaration so they get updated once set.
  • SwingControl.enabled -> Node.disable – There is a new disable flag on the Node class that is used universally across all controls to enable or disable them.  This conflicted with the old SwingControl.enabled variable, which has now been removed.
  • Rectangle2D -> Bounds – All references to Rectangle2D have been changed to the new javafx.geometry.Bounds class, which may have a ripple effect through your code.


Layout Changes:


  • min/max/pref -> getters – All of the Resizable methods (minimumWidth, minimumHeight, maximumWidth, maximumHeight, preferredWidth, preferredHeight) have been replace with function getters (getMinWidth, getMinHeight, getMaxWidth, getMaxHeight, getPrefWidth, getPrefHeight respectively).  The prefWidth/Height functions take an extra parameter, which is the amount of space in the opposite dimension.  This is very useful for doing height or width constrained layouts, such as Flows, but can be ignored by passing -1.
  • impl_layoutX/Y -> layoutX/Y – The impl_layoutX and impl_layoutY methods have been replaced with official layoutX and layoutY variables.  It is recommended that you use these variables over translateX/Y if you are moving nodes into position.
  • impl_requestLayout() -> requestLayout() – The requestLayout function has similarly moved from an internal to a public API.
  • impl_layout -> doLayout() – Rather than having a function to set the layout on, you now override Parent.doLayout().
  • Panel class added for declarative layouts – If you are looking for a functional alternative to Container, take a look at the new Panel class, which lets you set the layout declaratively.  It also has variables to override the default min/max/pref values without subclassing Container.
  • New functions on Container to help with layouts – There are a whole slew of new functions on the Container class that make it easier to work with the new layout system.  Make sure to read through them, because they will both save you time and help you follow the best practices for layout design.
  • Different transformation order – Previously the transforms[] variable allowed you to apply transformations included in the layoutBounds, while scaleX/translateX/rotate etc. were applied after layout.  Now both transforms[] and the transformation variables are calculated after layout uniformly.


Skin/Control Changes:


  • Skin.scene -> Skin.node – The name of the Node on Skin has changed from scene to node, which helps reduce confusion with the Scene class.
  • Skin.compute* methods removed – There were a series of computePreferredWidth/Height/etc. methods that were removed.  Instead you can directly use the getPrefWidth/Height/etc. methods on the Resizable class mentioned above.
  • Skin is now abstract – The Skin class is now abstract, and required that you implement your own contains and intersects methods.  You can either do this by using the new JFXtras AbstractSkin class or using the following boilerplate code:
override function contains(localX:Number, localY:Number):Boolean {
    return node.contains(localX, localY);
}

override function intersects(localX:Number, localY:Number,
   localWidth:Number, localHeight:Number):Boolean {
    return node.intersects(localX, localY, localWidth, localHeight);
}
  • New Behavior class – There is a new Behavior class that is meant to be used together with Control and Skin to provide reusable behaviors.
  • TextBox.text -> rawText, TextBox.value -> text – There was some swizzling of variables on the TextBox class.  What used to be text changed to rawText, and value now has the same semantics text used to have.


Asynchronous Changes:


  • RemoteTextDocument has been removed – Use HttpRequest directly instead.
  • AbstractAsyncOperation has been removed – Use the new Task infrastructure instead for communcating with Java code running in a background thread.


Animation Changes:


  • Transition.interpolate -> Transition.interpolator – A small name change to make room for a new interpolate flag that allows you to turn on or off interpolation altogether.
  • Transition now extends Timeline - This is a welcome change, which makes it much easier to work with Transitions and Timelines together.  To support this change ParallelTransition and SequentialTransition now take a sequence of Timeliens.


Java Equivalent Functions:

  • java.lang.Math -> javafx.util.Math – There is a new JavaFX math library, which is a drop-in replacement for the Java math library.  The main advantage of using the new JavaFX math library is that all functions are supported on mobile devices (including pow, log, etc.).
  • java.lang.Properties -> javafx.util.Properties – Another class that is similar in functionality to the Java equivalent, but portable to mobile.  Be warned, however, that the JavaFX properties file format is not the same as the standard Java properties file format.


CSS Changes:

  • CSS Update Defect (RT-4817) – Stylesheet updates no longer affect newly added Nodes due to a known defect.  In the meantime, you can do this to force a stylesheet refresh:
def senators = bind model.senators on replace {
    delete sceneRef.stylesheets;
    sceneRef.stylesheets = "{__DIR__}styles.css";
}
  • CheckBoxSkin.textFill doesn’t accept styles (RT-4819) - The check mark will pick up the style you set, but the text won’t.  The workaround for now is to create a checkbox with empty text and add a text node beside it with the correct styling and event handlers.
  • Can’t update the skin property of Control from CSS (RT-4820) – Another bug in the skin support.  You can set this in code instead for now.


Production Suite:

  • UiStub -> FXDNode – UiStub has been replaced with FXDNode, which includes some extra functionality, such as backgroundLoading, and placeholder images.


Miscellaneous:

  • Image.fromBufferedImage() removed – This has moved to SwingUtils.toFXImage().  Remember that if you use this function it will limit portability to mobile devices.
  • Color.fromAWTColor() removed – Yet another AWT-ism that has been removed. The JavaFX Color class is pretty thorough, so there shouldn’t be any reason to work with AWT Colors.
  • Duration.toDate is gone – As far as I know there is no equivalent functionality, but you can always get a duration’s value as a long and manipulate it directly.
  • Different variable names for the Affine class – If you use the Affine class, then your code is likely to break due to the new, more descriptive, method names, but the functionality is the same.


Whew!  …that was quite a lot to take in.  If you are interested to read more about the JavaFX 1.2 release including the new controls, layouts, and other functionality, the best source is to checkout the Pro JavaFX book that Jim, Dean, Weiqi, and I are writing.  It is almost fully updated for the JavaFX 1.2 release, and is available in Alpha right now from the book website.


I want to give a special thanks to Richard Bair and Amy Fowler from the Sun JavaFX team for providing a lot of valuable information on the JavaFX 1.2 release along the way.

Happy hacking on JavaFX 1.2!

评论 (0) 2009年06月13日

快速升级到JavaFX 1.2的方法

分类: JAVAFX技术.
标签: , , ,

javafxblogs.com Rss_google Rss_zhuaxia Rss_xianguo


JavaFX 1.2给我们带来了许多功能和性能上的提升,因此,我需要对原来的JavaFX 1.1的IDE和SDK进行升级来使用JavaFX 1.2的新特性。对于从来没有使用过JavaFX的用户来说,安装JavaFX SDK 1.2应该很简单,可以从javafx.com下载一个NetBeans 6.5.1+JavaFX 1.2 SDK混合包,那就OK了。可是对于我这种已经使用NB 6.5.1和JavaFX 1.1.1的用户,就需要考虑一些其它问题。因为我有不少程序是按照JavaFX 1.1的API写的,骤然升级可能会使得无法使用这些程序。同时由于两个SDK的IDE版本都是NetBeans 6.5.1,重新安装一遍也太浪费空间和时间,于是我查阅了一些资料并找到了快速升级的方式,同时还可以保留两个版本的SDK。


如果需要同时支持2个版本的JavaFX SDK,可以在升级前先把旧版本备份一下,这样可以避免被新的SDK覆盖。JavaFX SDK 1.1的缺省目录在C:\Program Files\NetBeans 6.5.1\javafx2\javafx-sdk,把它拷贝到另外一个目录,如C:\jfxsdk11\ 。


接下来就是升级了。在NB6.5.1 中,选择菜单Tools-〉Plugins,这时会列出一些可更新的plugin,如果没有看到列表,可以点击“Reload Catalog”按钮。如果plugin太多,可以在Search框中输入JavaFX过滤一下。有3个Plugin和JavaFX相关:

Plugins    说   明
JavaFX Kit     改进过的NetBeans IDE, Version 1.8
JavaFX SDK for Windows     JavaFX SDK 1.2, Versions 1.7
JavaFX Weather Sample     JavaFX演示程序, Versions 1.7



其中前面两个plugin是必需的,演示程序可自己决定取舍。选择安装之后,需要重新启动NetBeans。重新启动后,新的JavaFX SDK1.2 就安装完成了。如果要配置JavaFX 1.1的环境,则可以在菜单Tools->Java Platforms中配置。点击“Add Platform…”按钮添加平台,下一步中再选择JavaFX平台,输入平台名称如”Java SDK 1.1″,平台文件夹中输入刚才备份的目录C:\jfxsdk11\,点击”结束”即可。系统可能会有一个不支持之类的警告,但是不用理会。

如果你的项目需要使用JavaFX 1.1,可在项目的属性(右键点击该项目,选Properties)中配置libraries(库),可以选择JavaFX平台。这样,在同一个NetBeans IDE中就可以同时使用两个JAVAFX SDK环境了。当然,如果你没有太多JavaFX 1.1的程序,或者现有的程序和JavaFX 1.2兼容,那就基本上没有必要配置两个SDK版本了。


在用JavaFX 1.2重新编译了原来的程序后,发现JavaFX1.2的性能提升了不少。原来我用JavaFX 1.1写的吃豆人游戏,要占用50%左右的CPU利用率,现在只需要10-20%,进步还是比较明显的。所以建议尽可能使用JavaFX 1.2。


最新文章:

JavaFX吃豆人游戏的编写过程之三
JavaFX 1.2的新特性
JavaFX吃豆人游戏的编写过程之二
JavaFX游戏吃豆人的编写过程


英文文章连载:
第一篇文章,2009年5月14日:
Writing the Pac-Man Game in JavaFX - Part 1

第二篇文章,2009年5月21日:
Writing the Pac-Man Game in JavaFX - Part 2

第三篇文章,2009年5月28日:
Writing the Pac-Man Game in JavaFX - Part 3

第四篇文章,2009年6月4日:
Writing the Pac-Man Game in JavaFX - Part 4

评论 (0) 2009年06月07日

JavaFX吃豆人游戏的编写过程之三

分类: JavaFX编程, 吃豆人游戏.
标签: ,

javafxblogs.com Rss_google Rss_zhuaxia Rss_xianguo

6月4日发表了英文连载中的第4篇文章。在这篇文章中,主要介绍了吃豆人和精灵之间互动的代码实现。代码可在“JavaFX游戏实例共享网站”中下载。


到上一篇文章为止,我们已经实现了游戏中所有的人物。现在我们来增加吃豆人和精灵追逐和互“吃”的处理逻辑。如果吃豆人和精灵相遇,只有两种情况,吃豆人吃掉精灵或者反之。如果吃豆人刚刚吞吃了魔法豆,他可以吃掉精灵,否则吃豆人就会损失一条命,这时,需要播放一段吃豆人消失的动画(如下图所示):
shriking pac-man


这个动画在DyingPacMan类中实现,代码如下:


public class DyingPacMan extends Arc {

   var timeline = Timeline {
      repeatCount: 1
      keyFrames: [
        KeyFrame {
           time: 600ms
           action: function() {
        // hide the pacMan character and ghosts before the animation
              maze.pacMan.visible = false;

              for ( g in maze.ghosts ) {
                 g.hide();
              }
              visible = true;
            }
           values: [ startAngle => 90, length=>360 ];
         },
        KeyFrame {
           time: 1800ms
           action: function() {
              visible = false;
            }
           values: [ startAngle => 270 tween Interpolator.LINEAR,
                     length => 0 tween Interpolator.LINEAR ]
         },
      ]
    }

 ... 代码省略 ...
}


在这个动画中,定义了2个KeyFrames,一个在600ms,另一个在1800ms。在这两个关键帧中采用了JavaFX的线性插值(Interpolator.LINEAR)方式。线性插值的作用就是把动画中数据按照时间关系,在帧与帧之间线性变化,从而实现平滑的动画效果。在上述代码中,两个实例变量:startAnglelength, 通过线性的均匀变化,实现了我们需要的动画过程。参考下图的时间轴。第一个关键帧的时间是600ms而不是0ms,是因为我们希望游戏在这瞬间稍微停顿600ms。
timeline pac-man


好啦,到目前为止,游戏已经基本完成了,可以玩了。唯一不足就是精灵现在还是随机移动的,游戏的难度不大。不要紧,我们将在下周的文章中详细讨论。现在就点击下图来试一下这个游戏吧:(JDK1.5以上, Java Web Start 自动启动)


click to run
click to run



相关文章:

JavaFX应用实例、例子
用JavaFX编写的游戏Pac-Man
JavaFX Guy的博客
JavaFX 1.2的新特性
怎样用JavaFX编写游戏:吃豆人(Pac-Man)

JavaFX吃豆人游戏的编写过程之二
JavaFX游戏吃豆人的编写过程


英文文章连载:


第一篇文章,2009年5月14日:
Writing the Pac-Man Game in JavaFX - Part 1

第二篇文章,2009年5月21日:
Writing the Pac-Man Game in JavaFX - Part 2

第三篇文章,2009年5月28日:
Writing the Pac-Man Game in JavaFX - Part 3

第四篇文章,2009年6月4日:
Writing the Pac-Man Game in JavaFX - Part 4

评论 (0) 2009年06月06日

JavaFX 1.2的新特性

分类: JavaFX新闻.
标签: , ,

javafxblogs.com Rss_google Rss_zhuaxia Rss_xianguo


虽然JavaFX 1.2版本还有未正式发布,但是已经可以在javafx.com下载了(显示是下载SDK1.1.1版本,实际是SDK1.2)。


JavaFX 1.2在功能上和API上都有了较大的提高,较为不便的是,对先前写成的JavaFX 1.0/1.1的代码,虽然可以在旧的runtime中继续运行,但是如果要利用JavaFX1.2的功能等优点,可能需要做迁移和语法修正并且重新编译。JavaFX 1.2 主要的新功能如下:


0)支持OpenSolaris和Linux
1)BoxBlur等新效果(effect)
2)异步的处理模式(Asynchronous Processing Model)
3)内置的数学和属性类(即JavaFX写的Math,Properties类)
4)更多新的Layout类
5)更多的Skinnable控件
6)RSS和Atom的支持
7)图表功能(饼图,柱状图、散点图等)
8)Mixin类替代了多继承性
9)Java数组的直接引用(无需通过Sequence的转换)
10)Stage的支持功能,如Screen,Alerts等
11)本地数据存储,可以支持会话状态的保存。
12)客户化UI控件的增强支持(Behavior类等)

评论 (0) 2009年05月31日

JavaFX吃豆人游戏的编写过程之二

分类: 吃豆人游戏.
标签: , , , ,

上周介绍了关于编写JavaFX吃豆人游戏的前2篇文章。本周发表了5篇连载文章中的第3篇。在最新的这篇文章中,详细介绍了精灵(ghost)动画的机理,基本上和Pac-Man人物是一样的:改变坐标位置,并且不断切换画面(frame)。和Pac-Man不同的是,精灵有3组图,分别是正常(normal)、空心(hollow)以及闪烁(flashing),如下图所示:





为了说明程序结构,精灵的移动算法是随机的,也就是不能追踪Pac-Man的足迹。更好算法的介绍将在第5篇文章中详细讨论。到目前为止,游戏中的角色都齐了:4个精灵和1个吃豆人。他们现在还是相安无事,即使见面也互相不会吃掉。在下一篇文章中将介绍有关的处理逻辑。有兴趣的可以试一下目前这个半成品游戏(点击图画启动游戏):



相关文章:

JavaFX游戏吃豆人的编写过程

第一篇文章,2009年5月14日:
Writing the Pac-Man Game in JavaFX - Part 1

第二篇文章,2009年5月21日:
Writing the Pac-Man Game in JavaFX - Part 2

第三篇文章,2009年5月28日:
Writing the Pac-Man Game in JavaFX - Part 3

用JavaFX编写的游戏Pac-Man
怎样用JavaFX编写游戏:吃豆人(Pac-Man)之二

评论 (0) 2009年05月29日

JavaFX游戏吃豆人的编写过程

分类: JavaFX编程.
标签:

在JavaFX 1.0发布不久时,作为编程练习,我写了一个JavaFX游戏:Pac-Man,又称为PC MAN或“吃豆人”。Pac-Man是上世纪80-90年代非常著名的一款游戏,起源于日本,风靡全球。我写的JavaFX Pac-Man游戏引起了不少关注(参见文章:JavaFX 演示游戏:PAC-MAN   http://www.javafxblogs.com/%e7%94%a8javafx%e7%bc%96%e5%86%99%e7%9a%84%e6%b8%b8%e6%88%8fpac-man/),很多读者询问如何用JavaFX编制这样的游戏,并且希望能得到原代码。


点击启动游戏


点击启动游戏



(点击画面可以启动JavaFX的Pac-Man游戏)



最近,我把编制该游戏的过程写成介绍文章,在O’Reilly出版社的insideRIA.com上连载。由于时间关系,文章暂时只有英文的,稍后会把它改写成中文的版本。感兴趣的读者可以先看看英文原文,下源代码看看。在文章中,有多处Java Web Start的链接,可以一边阅读一边看看程序是如何运行的。目前,连载的前2篇文章已经发表,以后每周四(中国时间周五)发表一篇。第一篇文章介绍了Java的数据模型,用基本JavaFX的Shape类来绘制迷宫以及豆子。第二篇文章介绍了如何实现Pac-Man的动画,如何用键盘控制人物来吃豆子的动作等。相关的JavaFX功能演示包括:



. shapes
. animation
. keyboard handling
. java code integration
. Transfromation


相关信息:

第一篇文章,2009年5月14日:
Writing the Pac-Man Game in JavaFX - Part 1

第二篇文章,2009年5月21日:
Writing the Pac-Man Game in JavaFX - Part 2

用JavaFX编写的游戏Pac-Man
如何编写JavaFX游戏:Pac-Man(吃豆人)

评论 (4) 2009年05月22日

JavaFX许愿树程序:Effect功能的应用(3)

分类: JAVAFX技术, 许愿树.
标签:

在上篇文章中,我们可以在许愿树上悬挂许多愿望星了。现在,我们给程序增加些功能,可以在星星上记录许愿者的名字和愿望。你可以点击以下画面启动许愿树,点击许愿树后,可以看到一个弹出的窗口来输入姓名和愿望,点击“OK”确认。如果再次点击同一颗星星,就可以修改愿望的内容,快来试试看吧:(JDK1.5+或JDK 1.6)



点击启动许愿树程序


点击启动许愿树程序3

我们来看看如何增加一个半透明的输入窗口,代码在Dialog类中。首先,我们定义一个CustomNode。javafx.scene.CustomNode提供了用户自定义图形结点(Node)的方法,程序中需要继承该类,然后实现create()函数并返回自定义的Node。我们的CustomNode由一个Group实例来实现,包括一个蓝色半透明的外围框,两个输入框,两个文本以及一个“OK”按钮。Dialog.fx的代码如下:

( JAVAFX参考文章:
用JavaFX的Effect实现许愿树(1)
用JavaFX的Effect功能编写许愿树(1)
JavaFX 1.1和1.0的兼容性 http://blog.sina.com.cn/javafxcenter
JavaFX和Java之间的互操作性
Java和JavaFX的互操作性


/*
 * Dialog.fx
 *
 * http://www.javafxblogs.com
 */

package wishtree;

import javafx.ext.swing.SwingButton;
import javafx.ext.swing.SwingTextField;
import javafx.scene.CustomNode;
import javafx.scene.Group;
import javafx.scene.layout.VBox;
import javafx.scene.Node;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
import javafx.scene.text.Text;
import javafx.scene.text.TextOrigin;
import javafx.stage.Stage;

/**
 * @author Henry Zhang
 */

public class Dialog extends CustomNode {

  public var stage: Stage;
  public var star : Star;

  var w = bind stage.width;
  var h = bind stage.height;

  public var nameField : SwingTextField;
  public var wishField : SwingTextField;

  public function show( s: Star): Void {
    star = s;
    wishField.text = s.wish;
    nameField.text = s.name;
    visible = true;
  }

  public override function create(): Node {
    Group {
      blocksMouse: true;
      translateX: bind w / 6
      translateY: bind h / 4

      content: [
        Rectangle {
          stroke: Color.WHITE
          strokeWidth: 3
          width: bind w * 2 / 3
          height: bind h / 2
          fill : Color.BLUE;
          opacity: 0.5
          arcHeight: 10
          arcWidth: 10
        },
        // 本文发表自 http://www.javafxblogs.com
        VBox {
          spacing: 15
          translateX: bind w / 6
          translateY: bind h / 8
          content: [
            Text {
              content: "名字:"
              textOrigin: TextOrigin.TOP
              fill: Color.YELLOW
              font: Font.font ( null, FontWeight.BOLD, 20);
            },
            nameField = SwingTextField {
              text: "your name"
              width: bind w / 4
            },
            Text {
              content: "愿望:"
              textOrigin: TextOrigin.TOP
              fill: Color.YELLOW
              font: Font.font ( null, FontWeight.BOLD, 20);
            },
            wishField = SwingTextField {
              text:  "我希望..."
              width: bind w * .4
            },
            SwingButton {
              text: "OK"
              action: function():Void {
               star.name = nameField.text;
               star.wish = wishField.text;

               visible = false;
              }
            }
          ]
         },
     ]
   }
  }
}



在create()函数中,我们定义了圆角矩形的透明度为0.5,即可产生半透明的效果,arcHeight和arcWidth两个变量决定了圆角的大小。JavaFX技巧、编程和技术JavaFX Guy技术应用博客

 // http://www.javafxblogs.com
 Rectangle {
          stroke: Color.WHITE
          strokeWidth: 3
          width: bind w * 2 / 3
          height: bind h / 2
          fill : Color.BLUE;
          opacity: 0.5
          arcHeight: 10
          arcWidth: 10
        },

VBox的作用是把UI元素在垂直排列,相当于LayoutManager的作用。当点击OK按钮时,我们把对话框隐藏,并且把输入值赋给相关的Star对象。Group的属性中,我们设置了blocksMouse的属性,从而防止鼠标事件传导到下层的图形元素中。


接下来,我们把Main.fx略作修改,在生成Star实例时加入事件处理逻辑,使得星星在点击时可以弹出修改对话框,代码如下:

var tree : ImageView = ImageView {
  x: 80
  y: 0
  image: Image {
           url: "{__DIR__}images/tree.png"
           width: 640
           preserveRatio: true
         }
  onMousePressed:
    function(e:MouseEvent) : Void {

      // do nothing when the dialog is enabled
      if ( dialog.visible ) return;

      if ( e.y < 343 ) {
        currentStar = Star{
                  translateX: e.x
                  translateY: e.y

                  onMousePressed: function(e:MouseEvent) : Void {
                    // do nothing when the dialog is enabled
                    if ( dialog.visible ) return;

                    var self = e.node as Star;
                    dialog.show(self);
                  }
                 } ;

        dialog.show(currentStar);
        insert currentStar after stage.scene.content[currentIndex++];
      }
    }
};


至此,单机版的许愿树就完成了。代码可以在这里下载:许愿树代码。下一步,我们会把这个单机版的改成联网版,这样不同的用户可以通过网页在同一棵许愿树上许愿了。需要做的工作包括把用户的许愿请求发送到网站,然后存入数据库中,再通过许愿树展现出来。服务器端的代码可重用原来PHP版本的代码,或者新写都可以。

评论 (0) 2009年05月17日

JavaFX许愿树程序:Effect功能的应用(2)

分类: JavaFX编程, 许愿树.
标签: ,

在上篇文章“JavaFX许愿树程序:Effect功能的应用(1)”中,我们介绍了用JavaFX作出白云蓝天绿树的构图。接下来我们制作冒泡的动画,使得在白云中不断有气泡升起。然后我们再画上星星。


JAVAFX相关参考文章:
JavaFX 多维数组
用JavaFX的Effect功能编写许愿树(1)
JavaFX 1.1和1.0的兼容性
JavaFX和Java之间的互操作性


我们创建一个JavaFX类Bubble.fx,它是javafx.scene.shape.Circle类的子类,然后加上动画就可以实现气泡升腾的效果,我们一起来看看代码:


/*
 * Bubble.fx
 *
 * JavaFX技术交流  http://www.javafxblogs.com
 *
 */
package wishtree;

import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.scene.effect.GaussianBlur;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import java.lang.Math.*;

/**
 * @author Henry Zhang
 * JavaFX编程技巧及应用 http://www.javafxblogs.com
 */
public class Bubble extends Circle {

  var counter = 0;
  var startCounter = 10.0;

  var radiusDelta = -0.15;
  var destinationY:Double = 200;

  var timeline : Timeline =
    Timeline {
      repeatCount:   Timeline.INDEFINITE
      keyFrames : [
        KeyFrame {
          time : 100ms
          action: function () {
                    moveOneStep();
                  }
          }
      ]
    }

  init {
    effect = GaussianBlur { radius: 3}
    fill = Color.WHITE;

    radius = 4;
    resetStatus();
    timeline.play();
  }

  function moveOneStep() : Void {

    counter++;

    if ( counter > startCounter) {
      if ( not visible ) visible = true;

      centerY -= 2;
      radius += radiusDelta;

      if ( radius < 1 or radius > 4 )
        radiusDelta = -radiusDelta;
    }

    if ( centerY < destinationY+100 ) {
      visible = false;
      if ( opacity > 0.03 )
        opacity -= 0.03
      else
        opacity = 0;

      visible = true;
    }

    if ( centerY < destinationY ) {
      resetStatus();
    }
 } // JavaFX Game Demo   http://www.javafxgame.com

 function resetStatus(): Void {
   visible = false;
   centerY = 500 + random()*50;
   centerX = 200 + random()*350;
   counter = 0;
   startCounter = 80 + random()*400;

   destinationY = 150+random()*30;
   radius = 1 + random()*2;
   opacity = 0.6;
 }
}

首先,在init块和resetStatus()函数中我们初始化气泡的大小,透明度,位置等变量。我们在resetStatus()里调用了java.lang.Math里的随机函数random(),使得气泡的出现位置是随机的。从这可以看出JavaFX调用Java的便易性。在确定了初始状态后,我们定义一个动画的时间线(timeline)实例,里面只有一个关键帧(KeyFrame)。相关代码如下:

  var timeline : Timeline =
    Timeline {
      repeatCount:   Timeline.INDEFINITE
      keyFrames : [
        KeyFrame {
          time : 100ms
          action: function () {
                    moveOneStep();
                  }
          }
      ]
    }

. . . . 

  function moveOneStep() : Void {

    counter++;

    if ( counter > startCounter) {
      if ( not visible ) visible = true;

      centerY -= 2;
      radius += radiusDelta;

      if ( radius < 1 or radius > 4 )
        radiusDelta = -radiusDelta;
    }

    if ( centerY < destinationY+100 ) {
      visible = false;
      if ( opacity > 0.03 )
        opacity -= 0.03
      else
        opacity = 0;

      visible = true;
    }

    if ( centerY < destinationY ) {
      resetStatus();
    }
 }


每隔100ms,timeline都会调用处理函数moveOneStep(),从而可以不断改变气泡的状态,产生动画效果。在这个函数中,我们需要改变的实例变量有centerY,opacity,visible,radius。counter变量则是作为时间计数器,以控制状态的变化。这样,一个若隐若现、一张一弛不断上升的气泡就完成了。


下一步,我们再创建一个Star类,用来显示悬挂的“愿望星”。每颗星星可以看作是个10个结点连线组成的多边形,所以我们通过扩展Polygon类来编制星星的代码,一起来看看:

/*
 * Star.fx
 *
 * http://www.javafxblogs.com
 * http://developers.sun.com.cn/blog/henry
 */

package wishtree;

import javafx.scene.effect.DropShadow;
import javafx.scene.paint.*;
import javafx.scene.shape.Polygon;
import java.lang.Math.*;

/**
 * @author Henry Zhang
 *
 * http://www.javafxblogs.com
 *
 */

public class Star extends Polygon {
  def r1 : Double = 18;
  def r2 : Double = r1 / 1.6;

  var r = [r1, r2];

  var strokeColor =
    [ Color.PINK, Color.YELLOW, Color.GOLDENROD, Color.CYAN,
      Color.PURPLE, Color.BLUEVIOLET, Color.CORAL, Color.CRIMSON ];
  var fillColor =
    [ Color.GOLD, Color.BLUE, Color.RED, Color.DARKSLATEBLUE,
      Color.DARKORANGE, Color.MAGENTA, Color.BROWN, Color.CHOCOLATE ];

  init {
    // compute the coordinates of the star polygon
    points = for ( i in [0..9] ) [
      r[i mod 2] * cos( toRadians(i*36) ),
      r[i mod 2] * sin( toRadians(i*36) )
    ];

    blocksMouse = true;
    strokeWidth = 1; // 本文 发 表 于 http://www.javafxblogs.com/
    var which : Integer = random() * sizeof(strokeColor) as Integer;

    stroke = strokeColor[which];

    fill = LinearGradient {
             startX: 0 startY: 0  endX: 0  endY: 1.0
             proportional: true
             stops: [
                     Stop { offset: 0.1 color: Color.WHITE }
                     Stop { offset: 1.0 color: fillColor[which] }
                    ]
           };
    effect = DropShadow { color: Color.WHITE };
  }
}

在init块中,我们用for语句来计算星星的10个接点,每次循环产生一个节点的(x,y)坐标,共计10组,最后产生的一个sequence赋值给points变量,我们可以看到JavaFX的代码非常简洁:

    points = for ( i in [0..9] ) [
      r[i mod 2] * cos( toRadians(i*36) ),
      r[i mod 2] * sin( toRadians(i*36) )
    ];


fill变量我们再次采用了LinearGradient的渐变效果,填充的颜色是随机选择的。我们还增加了DropShadow的影子效果,在星星的背后加上了白色的影子,增强了视觉效果。blocksMouse属性是屏蔽鼠标事件传给星星下面的其他图形。


这个星星类产生的实例位置都是在坐标(0,0)的位置,在下面的程序中,我们会通过改变translateX和translateY的值,动态地把星星挂在树上。


我们对Main.fx略为修改一下,首先把数个泡泡加入scene中:

     for ( i in [1..5] ) Bubble { }


然后在许愿树的图形上增加鼠标点击的处理,每当点击到树叶和树枝时,会在该处挂上一颗星星,在鼠标事件(MouseEvent)中,x,y属性可以告诉我们点击的位置,然后我们就可以设置星星出现的地方。通过insert操作,我们把新创建的星星增加到scene中。注意,这里采用了currentIndex计数器来确保星星是出现在云层下方,我们可以看到被云层遮掩的星星:

var tree : ImageView = ImageView {
  x: 80
  y: 0
  image: Image {
           url: "{__DIR__}images/tree.png"
           width: 640
           preserveRatio: true
         }
  onMousePressed:
    function(e:MouseEvent) : Void {
      if ( e.y < 343 ) {
        var s = Star{ translateX: e.x translateY: e.y } ;
        insert s after stage.scene.content[currentIndex++];
      }
    }
};


完整的代码如下:

/*
 * Main.fx
 *
 * http://www.javafxblogs.com
 *
 */
package wishtree;

import javafx.scene.effect.GaussianBlur;
import javafx.scene.effect.PerspectiveTransform;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import javafx.scene.paint.LinearGradient;
import javafx.scene.paint.Stop;
import javafx.scene.Scene;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
import javafx.scene.text.Text;
import javafx.stage.Stage;

/**
 * @author Henry Zhang
 * JavaFX编程 http://javafxguy.javaeye.com
 * JavaFX技术交流应用 http://www.javafxblogs.com
 */

var xx = 170;
var yy = 430;

var currentIndex = 0;

var tree : ImageView = ImageView {
   x: 80
   y: 0
   image: Image {
            url: "{__DIR__}images/tree.png"
            width: 640
            preserveRatio: true
          }
  onMousePressed:
    function(e:MouseEvent) : Void {
      if ( e.y < 343 ) {
        var s = Star{ translateX: e.x translateY: e.y } ;
        insert s after stage.scene.content[currentIndex++];
      }
    }
  };

var tree2 =
  Image {
    url: "{__DIR__}images/tree2.png"
    width: 130
    preserveRatio: true
 };

var stage =
  Stage {
    title: "Wish Tree"
    width: 830
    height: 620
    resizable: false

    scene: Scene {
             fill: LinearGradient {
                     startX: 0,
                     startY: 0.0,
                     endX: 0,
                     endY: 1.0
                     proportional: true
                     stops: [ Stop { offset: 0.0 color: Color.web("#14acf8") },
                              Stop { offset: 1.0 color: Color.web("#a4e6f8") }]
                   }

    content: [
      ImageView {
        x: 50
        y: 280
        image: Image {
                 url: "{__DIR__}images/cloud2.png"
                 preserveRatio: true
                 width: 160
               }
        effect: GaussianBlur { radius: 25 }
      },
      ImageView {
        x: 520
        y: 300
        image: Image {
            url: "{__DIR__}images/cloud2.png"
            preserveRatio: true
            width: 150
            }
        effect:  GaussianBlur { radius: 33 }
      }, 

      ImageView {
        x: 560
        y: 500
        image: tree2
      },
      ImageView {
        x: 460
        y: 470
        image: tree2
      }, // JavaFX Sample code http://www.javafxgame.com
      ImageView {
        x: 60
        y: 500
        image: tree2
      },
      ImageView {
        x: 190
        y: 470
        image: tree2
      },
      tree,
      ImageView {
        x: 120
        y: 360
        image: Image {
          url: "{__DIR__}images/sign.png"
          width: 180
          preserveRatio: true
        }
      },
      ImageView {
        x: 20
        y: 60
        image: Image {
          url: "{__DIR__}images/cloud2.png"
          preserveRatio: true
          width: 250
        }
        effect: GaussianBlur { radius: 40 }
      }, // United States American Citizenship Test
      ImageView {
        x: 520
        y: 90
        image: Image {
          url: "{__DIR__}images/cloud2.png"
          preserveRatio: true
          width: 100
        }
        effect:  GaussianBlur { radius: 20}
      }, // United States Citizenship Application
      ImageView {
        x: 620
        y: 190
        image: Image {
          url: "{__DIR__}images/cloud2.png"
          preserveRatio: true
          width: 180
        }
        effect:  GaussianBlur { radius: 25}
      },
      ImageView {
        x: 600
        y: 380
        image: Image {
          url: "{__DIR__}images/cloud2.png"
          preserveRatio: true
          width: 150
        }
        effect:  GaussianBlur { radius: 33 }
      },
      ImageView {
        x: 0
        y: 490
        image: Image {
          url: "{__DIR__}images/cloud.png"
        }
        effect:  GaussianBlur { radius: 30 }
      },
      for ( i in [1..5] ) Bubble { },
      Text {
        x:170
        y: 450
        content: "许愿树"
        fill: Color.YELLOW
        font: Font.font ( null, FontWeight.BOLD, 30);
        effect: PerspectiveTransform {
                  ulx: xx    uly: yy
                  urx: xx+80 ury: yy-10
                  llx: xx-2  lly: yy+40
                  lrx: xx+80 lry: yy+38
                }
        }
      ]
    }
}

//用JavaFX的Effect功能编写许愿树程序
var idx =
  for ( n in stage.scene.content )
    if ( n == tree ) indexof n
    else [] ;

currentIndex = idx[0];

现在代码基本完整了,每次点击愿望树,都会生成一个五彩的星星,快来点击下面点击下面截图挂颗愿望星吧(JDK 1.5以上的环境,最好是JDK1.6 U10以上):



点击启动许愿树程序


点击启动许愿树程序



在下一篇文章中,我们介绍如何把愿望写在星星上。

( 未完待续, 完整代码可在下一篇文章中下载 )

评论 (0) 2009年05月15日

JavaFX许愿树程序:Effect功能的应用(1)

分类: JAVAFX技术, 许愿树.
标签: ,

看了同事用写了个许愿树程序(C/S架构的),其中client端的图形界面是由flash来实现。那么如果这个界面用JavaFX来写会怎样呢?我想这一定是很有趣的事情,于是就决定动手写个程序,比较一下。


JavaFX博客:http://www.javafxblogs.com/


首先写个主程序,把画面的Scene做出来。在这个画面中,蓝天背景和白云都需要使用图形效果(effect),在JavaFX中支持了多种图形效果,Lighting,Blur,Shadow等等,可以大大丰富我们的用户界面。我们的程序采用线性渐变(LinearGradient)效果来画蓝天,用高斯模糊(GaussianBlur)效果来画白云,程序如下:

/*
 * Main.fx
 *
 * http://www.javafxblogs.com
 *
 */
package wishtree;

import javafx.scene.effect.GaussianBlur;
import javafx.scene.effect.PerspectiveTransform;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import javafx.scene.paint.LinearGradient;
import javafx.scene.paint.Stop;
import javafx.scene.Scene;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
import javafx.scene.text.Text;
import javafx.stage.Stage;

/**
 * @author Henry Zhang
 * JavaFX编程  http://developers.sun.com.cn/blog/henry
 * JavaFX技术交流应用  http://www.javafxblogs.com
 */

var xx = 170;
var yy = 430;

var tree : ImageView = ImageView {
   x: 80
   y: 0
   image: Image {
            url: "{__DIR__}images/tree.png"
            width: 640
            preserveRatio: true
          }
   };

var tree2 =
  Image {
    url: "{__DIR__}images/tree2.png"
    width: 130
    preserveRatio: true
 };

var stage =
  Stage {
    title: "Wish Tree"
    width: 830
    height: 620
    resizable: false

    scene: Scene {
           fill: LinearGradient {
                  startX: 0,
                  startY: 0.0,
                  endX: 0,
                  endY: 1.0
                  proportional: true
                  stops: [
                    Stop { offset: 0.0
                           color: Color.web("#14acf8") },
                    Stop { offset: 1.0
                           color: Color.web("#a4e6f8") }
                         ]
                   }

    content: [
      ImageView {
        x: 50
        y: 280
        image: Image {
                 url: "{__DIR__}images/cloud2.png"
                 preserveRatio: true
                 width: 160
               }
        effect: GaussianBlur { radius: 25 }
      },
      ImageView {
        x: 520
        y: 300
        image: Image {
            url: "{__DIR__}images/cloud2.png"
            preserveRatio: true
            width: 150
            }
        effect:  GaussianBlur { radius: 33 }
      }, // http://www.javafxgame.com  JavaFX Demo Game

      ImageView {
        x: 560
        y: 500
        image: tree2
      },
      ImageView {
        x: 460
        y: 470
        image: tree2
     }, // http://www.compare-review-information.com JavaFX Sample code
      ImageView {
        x: 60
        y: 500
        image: tree2
      },
      ImageView {
        x: 190
        y: 470
        image: tree2
      },

      tree,

      ImageView {
        x: 120
        y: 360
        image: Image {
          url: "{__DIR__}images/sign.png"
          width: 180
          preserveRatio: true
        }
      },
      ImageView {
        x: 20
        y: 60
        image: Image {
          url: "{__DIR__}images/cloud2.png"
          preserveRatio: true
          width: 250
        }
        effect: GaussianBlur { radius: 40 }
      },
      ImageView {
        x: 520
        y: 90
        image: Image {
          url: "{__DIR__}images/cloud2.png"
          preserveRatio: true
          width: 100
        }
        effect:  GaussianBlur { radius: 20}
      },
      ImageView {
        x: 620
        y: 190
        image: Image {
          url: "{__DIR__}images/cloud2.png"
          preserveRatio: true
          width: 180
        }
        effect:  GaussianBlur { radius: 25}
      },
      ImageView {
        x: 600
        y: 380
        image: Image {
          url: "{__DIR__}images/cloud2.png"
          preserveRatio: true
          width: 150
        }
        effect:  GaussianBlur { radius: 33 }
      },
      ImageView {
        x: 0
        y: 490
        image: Image {
          url: "{__DIR__}images/cloud.png"
        }
        effect:  GaussianBlur { radius: 30 }
      },
      Text {
        x:170
        y: 450
        content: "许愿树"
        fill: Color.YELLOW
        font: Font.font ( null, FontWeight.BOLD, 30);
        effect: PerspectiveTransform {
                  ulx: xx    uly: yy
                  urx: xx+80 ury: yy-10
                  llx: xx-2  lly: yy+40
                  lrx: xx+80 lry: yy+38
                }
        }
      ]
    }
}


在程序中,我们把Stage的scene属性用渐变效果填充,可以得到蓝天的效果。在这个渐变效果中,startX和endX的值一样,startY和endY的值不同,因此是沿着Y方向(竖直)的渐变方式。起始颜色为深蓝(”#14acf8″),结束颜色为浅蓝(”#a4e6f8″),在整个Stage的Y方向均匀变化,相关代码如下:

       fill: LinearGradient {
               startX: 0
               startY: 0
               endX: 0
               endY: 1.0
               proportional: true
               stops: [ Stop { offset: 0.0 color: Color.web("#14acf8") },
                        Stop { offset: 1.0 color: Color.web("#a4e6f8") }]
             }

白云的模糊效果是通过高斯算法来获取,例如在下面代码中,ImageView的effect属性:
GaussianBlur{ radius: 40 },radius表示模糊渐变发范围的大小,数值越大,模糊度越大。

      ImageView {
        x: 20
        y: 60
        image: Image {
          url: "{__DIR__}images/cloud2.png"
          preserveRatio: true
          width: 250
        }
        effect:  GaussianBlur { radius: 40 }
      }


由于我们需要显示几朵不同大小的白云,我们需要把白云Image(cloud2.png)作大小调整,上面码中,我们通过改变width的值,并设置preserveRatio=true来保证长宽比例不变,这样就“创造”出不同大小的云块。相关代码段如下:( 本文见:http://www.javafxblogs.com )


  preserveRatio: true
  width: 250


还有要说明的一点是,在木牌子上的“许愿树”3个字,我们采用了维度变换( PerspectiveTransform )的效果,可以把2维的文字变成具有3维感觉的字形,呈梯形状。在PerspectiveTransform需要定义梯形的4个角的坐标,从而把原来长方形的区域映射成变形的字体。相关代码如下:

 Text {
        x:170
        y: 450
        content: "许愿树"
        fill: Color.YELLOW
        font: Font.font ( null, FontWeight.BOLD, 30);
        effect: PerspectiveTransform {
                  ulx: xx    uly: yy
                  urx: xx+80 ury: yy-10
                  llx: xx-2  lly: yy+40
                  lrx: xx+80 lry: yy+38
                }
        }


好了,到这里许愿树程序的界面就完成了,在下一篇文章中会继续介绍如何在树上“悬挂”愿望星星。如果你有JDK 1.5以上的环境(JDK1.6更佳),快点击下图来看看这个JavaFX版本的“愿望树”吧。当你的浏览器首次运行JavaFX程序时,会有一些等待下载的时间。



点击启动WishTree程序

点击启动程序

参见:http://www.javafxblogs.com( 未完待续, 完整代码可在下一篇文章中下载 )

评论 (0) 2009年05月12日

JavaFX 多维数组的使用

分类: JAVAFX技术, JavaFX技巧, JavaFX编程.
标签:

JavaFX的sequence是与java中的数组类似的一种数据结构。sequence使用起来比数组灵活,例如可以支持元素的插入和删除,应该说更像Collection这样的数据结构。和数组明显不同的是,sequence不支持多维结构。因此,当我们需要使用多维数组时,可以在Java语言中定义一个多维数组,然后在JavaFX中调用。


下面是一个包含2维数组的Java程序:

/**
 *
 * @author Henry Zhang
 * JavaFX技术应用 http://www.javafxblogs.com
 *
 */
public class ArrayClass {

  public static int arr [ ][ ] = new int[2][2];

  static {
    for ( int i=0; i<2; i++)
      for ( int j=0; j<2; j++ )
        arr[i][j] = i+j;
  }
}


在JavaFX中我们可以这样调用:

var x = ArrayClass.arr;

for ( i in [0..1] )
  for ( j in [0..1] )
    println("array[{i}][{j}] = {x[i][j]}");


输出结果如下:


array[0][0] = 0
array[0][1] = 1
array[1][0] = 1
array[1][1] = 2


JavaFX 技术应用
JavaFX技术交流应用中心

评论 (0) 2009年05月09日

JavaFX 语法显示工具

分类: JAVAFX技术, JavaFX编程.
标签: , , ,

最近写一些关于JavaFX的文章,发现需要一个语法显示工具以方便读者阅读。其实常用的IDE如NetBeans、Eclipse等都可以对语法的关键字、字符串常量等语法成分进行区别加亮显示。在博客或网页上通常有一类称为Syntax Highlighter的软件,可以是client端或server端的工具,把文章中的程序代码转化为彩色字体显示出来。常见的编程语言如Java,C/C++,C#,VB,JavaScript,Php等都有语法工具的支持,但JavaFX还没有,于是我决定自己做一个。


无论用那种工具,有关JavaFX的关键字列表都是必需的。因此,我花了些时间在google上,终于在openjfx网站上找到了所有关键字(保留字)。接下来就是改写javascript和CSS,最终生成JavaFX语法显示的页面。例如下面的代码范例:

package pacman;
import java.lang.Math;
import pacman.MazeData;
import pacman.PacMan;

/**
 * @author Henry Zhang
 */

public class MoveDecision {

  // x and y of an intended move
  public var x: Number;
  public var y: Number;

  // evaluate if the move is valid and its score if it's valid
  public function evaluate(pacMan:PacMan, isHollow:Boolean): Void {
    if ( x < 1 or y < 1 or y >= MazeData.GRID_SIZE
         or x >= MazeData.GRID_SIZE){
      score = -1;
      return ;
    }
  }
 . . .
}

如果要使用这个Syntax Highlighter,可以先下个SH 1.5.1的版本 ,然后再增加我这几个文件:

shBrushJavaFX.js
SyntaxHighlighter.css


具体的使用说明可以参考该工具的说明文档。



评论 (0) 2009年05月02日