人生、気合いと具合 - blog

2012年12月

This post is written as 23rd in irof Advent Calendar and JavaFX Advent Calendar.

Regardless of the Mayan calendar, I'm glad you are safe.
We are not interested in it, however, irof-san saved the Earth.

unzip and double click irof.jar



irof_screen_shot


When hold down the left mouse button, the balloon(?) is fired towards the mouse cursor, using the balloon to destroy the meteor.
Boss will appear over time, shoot and destroy it. Done right, you can save the Earth.
Meter at the bottom will be green to destroy the meteor, be red meteor reaches the Earth. If the meter is red all, game is over.

This is a sample that making a game with ScalaFX is easy.

Incidentally, game screen is using Canvas, and start button, text and meter are using Label and Rectangle in BorderPane.

This post is written as 6th in JavaFX Advent Calendar 2012.

JavaFX application runs also as Java applet and java web start.
With javafxpackager, you can make executable jar, applet, java web start.

However, there was a small trap, I was trapped, I write about it.

Since I made presentation document for the 8th JavaFX workshop, I was trying to publish it as an applet.
However, the applet did not run. I look at the Java console, the error seems to have occurred in the load method of FXMLLoader.

I think I will look at the source of OpenJFX, but there was no FXMLLoader.java.
Is not been publishing all the source of OpenJFX?

Since it can not be helped, I was looking closely at the stack trace once more, getDeclaredFields method have failed due to security.
When I look further, which line of FXML file is invalid, it was written to the error message. So when I try to check inside FXML, "fx:id" attribute is doubtful.

It seems to be an error because it uses the getDeclaredFields method in the process of setting a field of the controller class, an instance of the Control that has the fx:id attribute.
I think so, the application using FXML would not be able to run most of the time.I have heard it is okay that @FXML field is private.
However, if @FXML field is public, can access it by getFields method, and no problem in terms of security.That means, I think this is a bug.
If the applet is signed, then it probably runs. But I think the signature is required is not good.

When I examine, it seemed to be registered as a bug in JIRA. RT-23622
However, Fix Version/s is "Lombard", they won't fix it until JavaSE8?

So, (it isn't much sense) I tried to display only Label, but there was a further trap.

Using SceneBuilder, I operated

Put Label -> Change Font -> Copy & Paste

then, same error occured.
When I look at FXML, Label tag which was copied had font attribute like font="$x1", and original Label tag has fx:id attribute like fx:id="x1".
If JavaFX Control having a child tag is copied, the child tag automatically create fx:id attribute?
Then, Although I am not supposed to create fx:id attribute, same error occured.

In conclusion, if you want to run the application using FXML as Applet, we seem to be (almost) the signature is a requirement. (And perhaps JavaWebStart)
I hope that they fix this bug at JavaFX2.2 minor version up...

このエントリは、いろふ Advent Calendar、およびJavaFX Advent Calendarの23日目のエントリです。

さて、マヤ暦がどーのこーので地球が滅亡するのしないの、なんて話がありましたが、みなさま無事でなによりです。
しかし、我々が「滅びるわけねーだろ、ふふーん」とか余裕ぶっこいてる裏で、実はいろふさんが地球を守ってくれたのです!!!

ダウンロード
解凍してirof.jarをダブルクリックで起動するはず?

アプレット/Web Start


ソースとかはこちらで


irof_screen_shot


マウスの左ボタンを押しっぱなしにすると、マウスカーソルに向かってふきだし(?)が発射されるので、迫りくる隕石(うめぼしではない)を破壊しましょう。
一定時間耐えると、ボスが出現するので目いっぱい打ち込んでください。うまくいけば地球は救われるでしょう。
画面下のメーターは隕石を破壊すると増えて、隕石が地球に到達すると減っていきます。オールレッドになるとゲームオーバーです。
また、ボスが地球に到達した場合、無条件にゲームオーバーです。

まあ、要はScalaFXでゲームっぽいものを実装してみたというわけですが、ゲームとして成立はしてないですな。バランスもなにもないw
これくらいなら結構簡単にできますよーというサンプル的なものと思ってもらえば。

ちなみに、ゲームのメイン画面はCanvasにイメージを描画しています。
スタートボタンやゲームオーバーなどの文字とメーターはBorderPaneにLabelやRectangleを設定して使用。

てか、もうちょっと改良したいよ!
 

※これはAdvent Calendar向けのエントリではありません

さくらばさんのいろふさん絵描き歌 by JavaFXを、ScalaFXにしてみただけです。
ていうか、ゆきーんさんのエントリを見て、「おー、じゃあScalaFXで書いてみたら23日のエントリに使えっかな~」と思っていたら、意外な方面からJavaFXで先を越されたというか潰されたというか。
JavaとScalaで違うといったって、結局JavaFXだからねぇ。これではネタ被りとみなされそうなので23日は何か考えないと。
とはいえせっかくなのでやってみるだけやってみた。

基本的にさくらばさんと同じですが、FXMLを使わずにプログラムだけでやる場合、やはりScalaFXはかなり見やすくなっていると思います。

こんな感じ。

import scalafx.stage.Stage
import scalafx.stage.Stage._
import scalafx.scene._
import scalafx.scene.input._
import scalafx.scene.shape._
import scalafx.scene.paint._
import scalafx.scene.shape._
import scalafx.Includes._
import javafx.application.Application

object IrofShape{
  def main(args : Array[String]) = Application.launch(classOf[IrofShape])
}
class IrofShape extends Application {
  def start(stage: javafx.stage.Stage): Unit = {
    val irof = new Group{
      children = Seq(
        //枠
        new Rectangle{
          strokeWidth = 5
          stroke = Color.BLACK
          fill = Color.WHITE
          translateX = 0
          translateY = 0
          width = 300
          height = 300
        },
        //輪郭
        new Path{
          strokeWidth = 10
          stroke = Color.BLACK
          fill.value = null
          elements = Seq(
            MoveTo(126.5, 267),
            ArcTo(117, 117, 0, 146, 184.5, true, false),
            LineTo(210, 255),
            new ClosePath
          )
          clip = Rectangle(0, 0, 300, 300)
        },
        //ふき出し
        new Path{
          strokeWidth = 10
          stroke = Color.BLACK
          fill = Color.WHITE
          elements = Seq(
            MoveTo(50, 30),
            LineTo(153, 30),
            ArcTo(30, 30, 0, 153, 90, false, true),
            LineTo(105, 90),
            CubicCurveTo(105, 90, 90, 105, 129, 142),
            CubicCurveTo(90, 135, 66, 120, 81, 90),
            LineTo(57, 90),
            ArcTo(30, 30, 0, 50, 30, false, true)
          )
        },
        //目
        new Circle{
          centerX = 255
          centerY = 204
          radius = 15
          fill = Color.WHITE
          stroke = Color.BLACK
          strokeWidth = 10
        }
      //ふき出しの中の点
      ) ++ (for(x <- Seq(51, 84, 120, 154))yield Circle(x, 60, 5, Color.BLACK))
    }
    new Stage(stage){
      title = "irof shape by ScalaFX"
      scene = new Scene(irof, 300, 300)
    }.show
  }
}

Pathとかはだいぶ見やすいけど、CubicCurveToあたりは引数が多くてどれがどのプロパティだかわからなくなりがちなのがちょっと大変ですかね。
強いて言えば、ふき出しの中の点がfor式で書ける辺りがScalaっぽいといえばScalaっぽいかな。 (そのせいで絵描き歌としては順番かわっちゃってるけども)

irof_scalafx

このエントリは、JavaFX Advent Calendar 2012 の6日目です。

JavaFXのアプリケーションは、普通に作ればアプレットやJava Web Startとしても動作します。
そしてjavafxpackagerを使えば、実行可能jar、Applet、JavaWebStart、全部まとめて作ってくれます。

しかし微妙に罠があり、ちょっとハマったのでその件について。

先日の第8回JavaFX勉強会で発表した資料はScalaFXで作成したので、アプレットとして公開しようと思ったわけです。
しかし、なぜか動かない。Javaコンソールを見てみると、どうもFXMLLoaderのloadで落ちてる模様。

ちょっとソースでも見てみるかと思いOpenJFXのソースをのぞいてみると、なぜかFXMLLoader.javaが無い。あれー?OpenJFXってまだ全ソース公開にはなってなかったんだっけ?
しょうがないのでもう一回スタックトレースをよく見てみると、getDeclaredFieldsメソッドがセキュリティ的にはじかれている。
まあAppletだからそういうもんか、と思いながらさらに見ると、FXMLファイルのどの行がダメなのか、エラーメッセージにちゃんと出ている。そこで、FXMLの中を確認してみるとどうやら fx:id 属性があやしい。

つまりfx:idがついたコントロールのインスタンスを、コントローラクラスのフィールドに設定する処理でgetDeclaredFieldsを使っているからダメってことらしい。それってFXML使ってたら大抵ダメってことでは。
そういえば@FXMLをつけるフィールドはprivateでもいいよーというのを聞いた事があるような気が。
とはいえ、publicにしておけばたぶんgetFieldsで取れて、セキュリティ的にも大丈夫なんじゃないかなーと考えると、これバグなんじゃね?という気もする。
署名してやればできそうな感じだけど、署名が必須ってのもどうかという。

というわけでいろいろ調べてみたら、OpenJFXのJIRAにそれらしきものが。 RT-23622
やはりそういうことらしく、バグとして登録されているようだ。しかしFix Version/sが"Lombard"になっているということは、Java8まで修正するつもりは無いってこと?
※英語力がアレなので気になる人は自分でちゃんと読んでください...

じゃあ、(あまり意味はないけど)単純にLabelだけ表示するとかなら大丈夫かな?と試してみると...さらに罠。

単にLabelを並べるだけなら確かに大丈夫。しかしSceneBuilderで、
  Label置く → フォント変更 → コピペ
とやって複数Labelを作ると、やはり同じ現象で失敗。
FXMLを見てみると、コピーして作った方のフォント指定は、font="$x1"という属性なっていて、コピー元のfontタグに fx:id="x1" という属性が。
子タグがあるコントロールをコピペすると、元のコントロールの子タグに自動でfx:idがつく?ってことのようで、そうなると自分ではfx:idを設定したつもりはないけどこの現象で落ちるということに。うーん。

結論として「FXMLを使うアプリをAppletとして動かす場合、(ほぼ)署名が必須」ということになるらしい。(たぶんJavaWebStartも)
2.2のマイナーバージョンアップとかで直してくれないかなぁ...

このページのトップヘ