JavaFX 11に追加されたRobotクラスの紹介

このエントリは じゃばえふえっくす Advent Calendar 2018 の 3 日目のエントリとしてぶっ込みました。もうクリスマスは終わってますが、まだ空いていますし、 1 日目のエントリ で次のようなことを書いていたのをまだ放置していたので、それを拾うエントリとなります。

上記の Maven リポジトリをご覧になると分かりますが、Java FX 11 もリリースされました。リリースノートは次の通りです。

https://github.com/javafxports/openjdk-jfx/blob/jfx-11/doc-files/release-notes-11.md

まあ新機能は少ないのですが、 Spinner コントロールに改善が加えられていたり (詳しくは Yucchi_jp さんのこのブログエントリ を) 、新たに Robot というクラスが追加されています。この Robot クラスについては別のエントリで触れる予定です。

というわけで、JavaFX 11 になって新たに追加された Robot クラスについて触れたいと思います。

Robot クラスはプログラムから画面操作を行うために必要なメソッドが実装されたクラスです。あたかもロボットが画面操作を人の代わりに行うようなことを実現するというわけです。 AWT にも同様のクラス があります。一番のユースケースGUI の自動テストを実装することで、それを実現するために次のような操作を実行するためのメソッドが実装されています。

  • マウスの各種操作 (移動、クリック、スクロールホイール) を行う
    • マウスの現在位置を取得するためのメソッドもあります
  • キーボードをタイプする
    • タイプとは別にプレスとリリースにもメソッドが用意されています
  • 画面のスクリーンショットを撮る
  • 指定した座標の色を取得する

モジュールは javafx.graphics に、パッケージは javafx.scene.robot に入っています。

画面を操作するのに必要なものは一通りそろっているので、これで定形作業を肩代わりするプログラムを作るのに使えますね。ゲームの周回操作とかにもいいかも。

実はこのクラス、昔からあったのですが internal なクラスとなっていました。このクラスを使って自動テストフレームワークを作っていたライブラリが多く、Java のモジュール化に伴い「外に出してほしい」というリクエストが非常に多かったのですが、11 になって晴れて表に出てきてくれました。

ところで以前、自分の書いた次のエントリで、JavaFX で xeyes のクローンを作った話をしました。

aoe-tk.hatenablog.com

そこでこんなことを書いていました。

  • 以前は Mac 上で Swing の EDT を実行すると HeadlessException が飛ぶ問題があり、仕方なく Swing を土台として作っていたのですが、現在はこの問題は解消されているので、JavaFX を土台としたものに変更しています。
    • 唯一、グローバルなマウスカーソルのアドレスを取得するのに AWT に頼っていますが、JavaFX 11 で待望の Robot クラスが追加されるので、11 になれば "Pure JavaFX" なアプリケーションにできる見込みです。

てなわけで、早速この Robot を使って "Pure JavaFX" なアプリにしちゃいましょう。

まずは 10 以前のマウスポジションを取得するコード。

private void updateMousePosition() {
    SwingUtilities.invokeLater(() -> {
        final Point pointerLocation = MouseInfo.getPointerInfo().getLocation();
        Platform.runLater(() -> updateEye(pointerLocation.x, pointerLocation.y));
    });
}

Swing の EDT と JavaFX のアプリケーションスレッドを行ったり来たりして見通しが悪いですね。これを 11 の Robot クラスを使うように変更します。使い方は簡単で、普通にインスタンスを取得すればいいです。Controller の初期化処理で取得しておきます。

private Robot robot;

@Override
public void initialize(URL location, ResourceBundle resources) {
    robot = new Robot();
    // (以下略)

後はこのインスタンスを使ってマウスカーソルのグローバルポジションを取得するだけです。 updateMousePosition() メソッドの内容が次のように変わりました。

private void updateMousePosition() {
    updateEye(robot.getMouseX(), robot.getMouseY());
}

はい、これで複数スレッドを行き来する必要がなくなりました。しかも java.desktop モジュールへの依存も無くなるので、配布 JRE のイメージサイズも小さくすることができますね。 *1

少し付け加えると、 Robot から取得するマウス座標の値は AWT と違って double 型になります。なので updateEye() メソッドの引数の型を変える必要がありました。

というわけで JavaFX 11 の新機能である Robot クラスの紹介でした。さすがに今年の Advent Calendar への投稿はこれで終わりかな。皆様良いお年を。

*1:AWT、Java2D、Swing を全部雑に java.desktop モジュールにぶち込んでるんですよね...。お陰でサーバーサイドアプリケーションでも JavaBeans 関連の API を使うだけなのにこのモジュールへの依存が必要がだったり。

IntelliJ形式のJavaFXプロジェクトをJavaFX 11にアップグレードしたら色々ハマった話

このエントリは じゃばえふえっくす Advent Calendar 2018 の 2 日目のエントリとして作成しました。場所がたくさん空いてるので、みんなも気軽に参加してねー。

さて今回は 1 日目 として書いた記事で次の様なことを書いていたのですが、その内容について触れたいと思います。

Java 11 から JavaFXJava の 1 ライブラリになりましたが、Mavenリポジトリにも "org.openjfx" というグループ名でアーティファクトが登録されました。

https://mvnrepository.com/artifact/org.openjfx

モジュール別にアーティファクトが登録されています (実はこれを利用する際にちょっとした罠にはまったのですが、それは別のエントリで) 。

IntelliJ プロジェクトからこの Maven リポジトリを利用しようとした際に罠にはまりました。まあ、純粋な IntelliJ 形式のプロジェクトで開発している人は少ないと思うのですが、OpenJFX の Maven リポジトリの解説にもなるので、独立したエントリとしました。

IntelliJ プロジェクトを JDK11 にアップする

まず、既存の JDK10 を利用するプロジェクトとして作成した IntelliJ プロジェクトを JDK11 にアップしてみます。 f:id:aoe-tk:20181223231936p:plain

JDK11 には JavaFX は入っていません。当然このように JavaFX 関連の API が赤くなってしまいます。悲しい。 f:id:aoe-tk:20181223232110p:plain

IntelliJ から Maven を利用したライブラリ設定を行う

嘆いていても仕方ないので、JavaFX のライブラリ設定を行うことにします。IntelliJ には依存するライブラリを Maven リポジトリから取ってくる機能があるので、これを利用して MavenCentral に登録された OpenJFX のライブラリを取ってくることにします。 f:id:aoe-tk:20181223232358p:plain

次のように MavenCentral からアーティファクトを検索してくれます。 f:id:aoe-tk:20181223232733p:plain

これでエディタから赤色が無くなる...と期待したのですが無くなりませんでした! Maven からダウンロードした OpenJFX の JAR の中身を見ると MANIFEST ファイルしか置いていないのです!

Maven リポジトリへの OpenJFX JAR の配置について

どうしてこうなったのかは Mavenリポジトリの内容を見て分かりました。OpenJFX は OS 別のネイティブ実装を含むため、OS 別に JAR ファイルが用意されていたのです。例えば javafx-controls モジュールのリポジトリ を覗いてみると次のようになっています。 f:id:aoe-tk:20181223233303p:plain

WindowsMacLinux 向けに artifact classifier を使って JAR が分けられています。色々調べましたが、IntelliJ では artifact classifier で細分化された JAR を取ってくることができませんでした。しくしく。

普通に OpenJFX SDK をダウンロードして利用する

仕方が無いので古き良きライブラリ直接ダウンロードという方法を採ることにします。なお、今回対象としたプロジェクトは一応 GitHub に公開しており、また自分自身 WindowsMac の両方で使うようにしていたので、環境依存的な設定が入ることを避けるようにします。

ダウンロードは前回のエントリで紹介した かっこいい Web サイト からできます。実行する環境に利用する OS のものを選んでダウンロードして解凍します。なお、IntelliJ はホームディレクトリ以下のパス設定は自身の環境変数を使って設定に記述するので、どの OS でもホームディレクトリの下のディレクトリに解凍すると環境依存が無くなるのでお勧めです。

ダウンロード、解凍が終わったら IntelliJ からこれを利用するように設定します。プロジェクト設定の [Libraries] から普通に [Java] を選んで、先ほどダウンロードした OpenJFX SKD ディレクトリの lib サブディレクトリを選択します。 f:id:aoe-tk:20181223234407p:plain f:id:aoe-tk:20181223234430p:plain

これでエディタから赤色が消えました。が、これで終わりではありませんでした。OpenJFX SKD の lib ディレクトリの下にはソースコードアーカイブした src.zip が置かれています。そのままでは IntelliJ がこれもコンパイル対象にしようとして、ビルド時にエラーになってしまいました...。

そこで、lib ディレクトリの下にある src.zip ファイルを別の場所に移動し、さらに IntelliJ のライブラリ設定からソース参照の設定 (次の図で赤色で囲っている部分) を除去します。 f:id:aoe-tk:20181223234818p:plain

これで無事にビルドもできるようになりました。やれやれ。

忘れてはいけない実行時の注意点

さて、実際に実行する際にも注意点があります。これは IntelliJ 固有の話では無く、Java 11 以降の JavaFX アプリケーション実行時の共通した注意点です。

詳細については id:torutk さんの次のエントリで解説されていますが、Main クラスが javafx.application.Application を継承している場合、実行時に --add-modules による JavaFX モジュールの指定が必須です。

torutk.hatenablog.jp

また、アプリケーション自体をモジュール化している場合は実行時にモジュールパスの指定も必要になります。次のように実行設定を編集して、必要なパスの設定を忘れないでください。 f:id:aoe-tk:20181223235428p:plain f:id:aoe-tk:20181223235621p:plain

以上です。えっと結論としては素直に Maven か Gradle で開発プロジェクトを作りましょう、ですw 今はどの IDE もこれらのツールで作ったプロジェクトならそのまま取り込めるので *1 、一見面倒そうに見えても後がすごく楽です。

*1:NetBeans の最新版だけ Gradle プラグインの対応が遅れていたかも...

2018年のJavaFXに関するできごと

このエントリは じゃばえふえっくす Advent Calendar 2018 の 1 日目のエントリとして作成しました。今年は無いかと思っていたのですが、@Yucchi_jp さんが立ててくださったので、まずは 1 日目を埋めることにしました。

とりあえず初日分と言うことで 2018 年に JavaFX に関して起こった出来事をまとめます。大きな出来事はこんなところでしょうか (最後だけは個人的に注目していた小ネタかな) 。今年は激動の 1 年でしたね。

  1. Oracle による Client Roadmap の発表とそれに伴う JavaFXJDK からの分離
  2. OpenJFX コミュニティ環境の整備が進む
  3. JavaFX 11 のリリース
  4. OpenJDK ディストリビュータによる JavaFX サポート表明が相次ぐ
  5. 生きていた JSR-377

以降、順番にその詳細について記載していきます。

Oracle による Client Roadmap の発表とそれに伴う JavaFXJDK からの分離

はい、2018 年の前半に出た衝撃の発表です。詳細については私自身が 2 回に分けてポエムを書いたので、そちらをご覧になってください。

aoe-tk.hatenablog.com

aoe-tk.hatenablog.com

これにより、Oracle JDK からも JavaFX は分離され、Java 標準の GUI ツールキットとしての地位は失いました。しかしながら、結果として OpenJFX プロジェクトはより独立して自由に動けるようになりました。

OpenJFX コミュニティ環境の整備が進む

OpenJDK と OpenJFX のつながりが小さくなったので、OpenJFX プロジェクトはより自由に動けるようになりました。これまではどうしても Oracle の動向に縛られることが多かったのですが、JavaFX をビジネスの中心に据えている Gluon 社主導でより外部の人が自由に参加できるような環境が急速に整えられました。

まず、リポジトリのクローンが GitHub に作成されました。

github.com

プルリクエストを出すためには OCA へのサインが必要ですが、Issue の報告などがこれまでよりもずっとやりやすくなりました。何しろ OpenJDK の JIRA は誰もが参加できるものでは無かったですから (ただし、メインのバグトラッカは依然としてここです) 。

そしてかっこいい Web サイトもできあがりました。

https://openjfx.io/

f:id:aoe-tk:20181216183219p:plain

この Web サイトからドキュメントの閲覧やライブラリのダウンロード、GitHub リポジトリへのジャンプなどができます。今後は JavaFX の動向をチェックする際はこの Web サイトを拠点にするといいでしょう。

Java 11 から JavaFXJava の 1 ライブラリになりましたが、Mavenリポジトリにも "org.openjfx" というグループ名でアーティファクトが登録されました。

https://mvnrepository.com/artifact/org.openjfx

モジュール別にアーティファクトが登録されています (実はこれを利用する際にちょっとした罠にはまったのですが、それは別のエントリで) 。Maven や Gradle 用のプラグインも用意され、それらと併用することで簡単にOpenJFX のライブラリが利用できるようになります。

このように Gluon が旗振り役となり、急速に環境が整えられました。「主体が Oracle から Gluon に変わっただけ?」みたいな言われ方をすることもありますが、やる気があるところが引っ張るようになっただけでも大きいと思います。

JavaFX 11 のリリース

上記の Maven リポジトリをご覧になると分かりますが、Java FX 11 もリリースされました。リリースノートは次の通りです。

https://github.com/javafxports/openjdk-jfx/blob/jfx-11/doc-files/release-notes-11.md

まあ新機能は少ないのですが、 Spinner コントロールに改善が加えられていたり (詳しくは Yucchi_jp さんのこのブログエントリ を) 、新たに Robot というクラスが追加されています。この Robot クラスについては別のエントリで触れる予定です。

OpenJDK ディストリビュータによる JavaFX サポート表明が相次ぐ

Oracle JDK の有償化に伴い、Linux 黎明期を彷彿とさせるような OpenJDK ディストリビューションの戦国時代に突入した感のある Java 界ですが、次の OpenJDK ディストリビューションJavaFX の同梱を表明しました。

Amazon の Correto については、AWS が提供しているサービスの中に JavaFX を利用したツール (AWS Schema Conversion ToolJavaFX で作られています) が存在することが一番大きな理由でしょうね。

Zulu については Azul 社の顧客に JavaFX を利用しているところが多かったのが理由だそうです。CTO が JavaFX と関わりの深かった Simon Ritter 氏であることも大きかったでしょうね。

生きていた JSR-377

最後は割と小ネタです。以前、自分のブログでも取り上げたことのある JSR-377 がまだ生きていましたw Java のデスクトップ、組み込み GUI アプリケーションのフレームワークを作ろうというもので、JavaFX に限ったものではないですが、ほぼ JavaFX をターゲットとしたものです。

aoe-tk.hatenablog.com

この JSR 引っ張っていた方が Oracle の発表を受けて こんなツイート をしていたので、てっきりもうやめるのかと思いましたが、GitHub を見ると、再び更新が行われるようになっています。

ただこの JSR、Renewal Ballot が 3 回も行われており、 3 度目 では Oracle から「もう次はないぞ」と言われ、JetBrains からは「もっと真剣に取り組めよ」といった旨のコメントをチクリと言われる始末ですが。ですが、とても価値のあるものだと思っているので個人的には進めてほしいと思っています。

Pixel 3 XLを購入しました

これまで 10 年以上スマートフォンとしては iPhone を使っていました。日本に最初に上陸したバージョンである 3G からです。3G→4→5c→7 と使い続けていたのですが、この度遂に iPhone やめて Google の純正ブランドである Pixel 3 XL に機種変しちゃいました。

長年連れ添った iPhone に別れを告げて、Android の参照実装機とも言える Pixel に乗り換えたのは次のような理由です。

  • 単純に iPhone というか Apple ブランド全般に飽きたw
    • 流石に 10 年以上も使っていると飽きてきました
    • Mac も飽きてきて、新しい持ち運び用のノートには Windows 機を選びましたし、仕事場のマシンも新しくするときは Windows にしようと考えています
  • iPhone XS シリーズがクソ高い
    • Pixel も結構高いですが、それでも iPhone XSシリーズよりは安いです

無印か XL かはちょっと迷ったのですが、実機を触ってみて、XL でも辛うじて片手でも扱えるぎりぎりの大きさに絞られており、個人的にもファブレットを使いたかった(スマートフォンタブレットを統一したかった)ので、XL を選択しました。

良かった点

  • 最近のスマートフォン界で流行のナローベゼルのお陰で、片手で使えるファブレットになっている
    • ちょっと重いですがほぼ片手で操作できます
    • 大きい画面がほしいときは安物の Android タブレットを使っていたのですが、これでさよならできそうです
  • 最新の Android の機能が使える
    • 自分が今まで使ったことがある Android 機は Huaweiタブレットだったのですが、メーカーが色々手を入れまくっていたので古い Android のままでした
    • こちらは Google 純正機なので最新のアップデートがやってくることが保証されます
    • 仕事場でも GSuite を使い、家でも GMail を使っているし、ブラウザは Chrome だしと、何だかんだで Google のサービスへの依存度が高いので、シームレスにそれらのサービスへアクセスできる Android の方が iOS よりも有利でした
    • 一番面白かったのが Google アシスタントによる画像検索機能で、次のように写真に写っている動植物や物品が何であるかを調べてくれたりします f:id:aoe-tk:20181209225737p:plain
  • カメラが暗所に強い
    • これはメディアでもよく話題にされていたので知ってる人も多いと思いますが、Google の AI 技術による補正で、暗いところでも中々くっきりとした写真を撮ってくれます f:id:aoe-tk:20181204204024j:plain
  • iPhone からの移行が楽だった
    • 移行はちょっと大変になるかな? と思ったのですが、セットアップ時に次のようにケーブルでつなぐだけで iPhone 内の住所力や MMS メッセージ、写真、音楽などのデータをまるっと移してくれました! f:id:aoe-tk:20181201223853j:plain
    • ソフトウェアについても Play ストアに同じものがあるときはそれをダウンロードできるようにリストアップしてくれます
    • 壁紙設定まで移行されたのには驚きました
    • なお、このセットアップを行うに当たっては注意点があるので、それは後述します
  • 背面指紋認証は意外と使い易い
    • 実は iPhone が顔認証のみになってしまったのも Pixel に乗り換える要因だったりします
    • 片手で持ったときに丁度人差し指で触れやすいポジションにあって、iPhone のそれよりも使い易いと感じました
    • iPhone指紋認証は指の状態によってはうまく働かないことがありましたが、Pixel はまず大丈夫です

イマイチな点

  • Google Pay はまだまだ発展途上
    • 現状 Suica のようなプリペイド系のカードしか純正の Google Pay ソフトでは扱えないものと思った方がいいです
      • JCB のクレジットカードだけは非接触決済に使えると出ましたが、そもそも対応している店舗を見かけない...
      • コンビニでも「対応している」と書いていても小さな字で「一部の店舗です」との注意書きがあり、実際使えないw
    • クレジットカードは登録から実際に使えるようになるまで少し時間が掛かります
      • 確か Apple Pay は即座に使えるようになったはず
      • お陰で Suica にすぐにチャージができずに困り、結局モバイル Suica アプリを別途インストールしました
        • 各種メニューページに入ると、いきなりガラケー向け UI が表示されるアレですw
    • そのこともあってか、最初からおサイフケータイアプリが別途インストールされているので、QUICPay とか iD とかを使いたい場合はこちらを使いましょう
      • これはキャリア側 (自分は SoftBank で契約しました) が入れているんだと思います
  • 自分の手に馴染ませるには色々設定が必要
    • デフォルトの動きでは自分に合わないところが結構あり、設定画面を隅々まで探検して色々設定を変える必要がありました
    • 逆に言うと細かくカスタマイズできるので、うまく設定すればものすごく馴染みます
      • そういう意味でも Android はやっぱりコンピューターに詳しい人向けの OS だと思います (詳しくない人には間違いなく iPhone を奨めますね)
  • メッセージアプリはいわゆるガラケーメール向きではない
    • 登録した連絡先から送信する場合は電話番号の選択のみで、メールアドレスの場合は直打ちが必要です
    • SoftBank が別途専用アプリを入れてくれているのでそれを使いましょう
  • そこまで爆速ではない
    • これはメディアでも言われていましたが、最高クラスのチップが積まれているわけではないので、とにかくスピードを求める人には向かないかもです
    • Geekbench でスコアを取ってみてたところ (左が iPhone7、右が Pixel3XL) 、iPhone7 と比べてシングルコアでは負けており、マルチコアの総合性能では勝っているという結果でした f:id:aoe-tk:20181209231711p:plain
    • まあでも十分速いのも確かで、ストレスは全く感じません
      • 具体的な例を挙げるとアズレン弾幕が激しく飛び交う画面でもコマ落ちせずスムーズに動く

注意点

最初のセットアップで、iPhone からの移行はケーブルでつなぐだけで OK と上に書きましたが、実際には iPhone 側で事前に次のような準備が必要です (この点は紙のセットアップガイドには書いておらず、Web を見る必要があるんだな、これが) 。

  • バックアップの暗号化を解除する
    • これを解除しないとほとんどのデータを転送できません
    • デフォルトで暗号化設定になっているので、ほとんどの人は解除が必要です
  • iMessage、FaceTime を「使用しない」という設定に変更する
    • これをしないと MMS が iMessage に紐づけられたままになり、MMS が全部そっちに転送されてしまいます

Java 11ではPublic JREが本当になくなりました

Java 11 の登場で Java を取り巻く環境は様々な転換点を迎えることになりました。散々言われている Oracle からのリリース方法の変更の話もありますが、もう1つ、Public JRE の消滅があります。

実際に JDK11 をインストールして色々変化があったので、このエントリではその情報を共有したいと思います。と言っても Twitter ではこの件に関して頻繁につぶやいていたので、それを引用しながらの内容になります。

そもそも Public JRE って何?

一言で言うと「 あなたとJAVA, 今すぐダウンロード 」からダウンロードしてインストールするソフトウェアのことですw

JDK と異なり、Java アプリケーションの実行に必要なモジュールだけを OS のシステムレベルでインストールします。開発者ではなくエンドユーザー向けのソフトウェアです。次のような役割を担います。

  • Executable JAR ファイルの実行
    • Explorer や Finder といったファイラーから JAR ファイルをダブルクリックすることで Java アプリケーションを起動できるようにします
  • ブラウザ Java Plug-in 経由で起動される Java Applet、Java Web Start アプリケーションの実行
  • デスクトップ上での Java Web Start アプリケーションの実行
    • これもファイラーから JNLP ファイルをダブルクリックすることでアプリケーションの起動が可能になります
    • クライアント側に実行に必要な JAR のキャッシングも行い、バージョンが変わったときだけネットワークから差分データを取得するようなこともします

JDK11 でどう変わったか

そして、Java 11 ではこれが無くなりました。Oracle JDK 11 をインストールしたときのつぶやきを引用します。

こんな感じで本当に Public JRE のインストールがなくなりました。しかし、この時点では前のバージョンは残っており、今後 Public JRE の無償サポート (Java 8 の JRE については個人向けに対しては 2020 年までサポートを継続) が終了したときにはどうするのかという疑問点が残っていました。

Java 定期アップデート時の JRE 10 の扱い

その答えは先日の定期アップデートの時に判明しました。Public JRE をインストールしている場合、自動でアップデートチェックが走り、更新があった場合はインストールダイアログが表示されます。今回の場合、自分のマシン環境には Java 10 の Public JRE しか入っていませんでした。これは Java 11 のリリースと共に無償サポートは終了しました。

以下、そのときのつぶやきを引用します。

そうです、自動アップデートのタイミングで無償サポート対象外の JRE のインストールを検出した場合はそれをクリーンアップするように促されます。このようにして古い JRE が放置されないようにちゃんと考えていたのですね。

こうして私の環境では JAR をダブルクリックしても何も起きなくなり、当然のことながら Java Applet は実行できなくなりました。

今後の Java アプリケーションの配布はどうするのか?

このようにして、システムレベルでインストールする JRE は今後無くなっていきます。では、どうやって Java アプリケーションをエンドユーザーに届けるのかというと、アプリケーション開発者が JRE と共にアプリケーションを配布することになります。

Java 9 からは配布用の JRE を生成するための jlink というツールが付属しています。アプリケーション側がちゃんとモジュラー化していれば、アプリケーションの実行に必要なモジュールだけを含んだ JRE を生成することができます。今後はこれを利用しましょう。

ただこの jlink、コマンドライン起動を想定していて、起動はシェルスクリプト (Windows 向けには bat ファイル) の形になっており、GUI アプリケーション向きではありません。そのためには javapackager と言うツールがあったのですが (過去の私の このエントリこのエントリ で取り扱っています) 、このツールは JavaFX に付属していたものであり、 Java 11 で JavaFX が切り離された ため、JDK から無くなってしまいました。

そこで、OpenJDK では JDK 向けに javapackager 相当のものを作ろうという JEP が起案されました。

http://openjdk.java.net/jeps/343

名前は jpackager にするつもりみたいです。早く出てきて欲しいですね。

Bean Validationの日本語メッセージリソースのドラフトをQiitaにアップしました

ここではお知らせのみ。Bean Validation (Hibernate Validator) の日本語メッセージリソースのドラフトを考えたので、Qiita にアップして皆さんの意見を募ることにしました。

qiita.com

みんなから意見を聞くタイプのものは Qiita の方がいいかなあと思い、初めて Qiita を利用してみました。こういうの他には何がいいのだろう?

JavaFXの非矩形ウィンドウにおけるWindowsとMacでのマウスイベントの違い

しばらく blog を書いていなかったので先日気がついた小ネタでも書きます。

かなり昔に JavaFX で xeyes のクローンを作ってみた話 を書いたことがあったのですが、最近あれをイチから作り直してみました。コードも GitHub にアップしています。 *1

github.com

以前のブログエントリからは次のようにかなり作りが変わっています。

  • 以前は Mac 上で Swing の EDT を実行すると HeadlessException が飛ぶ問題があり、仕方なく Swing を土台として作っていたのですが、現在はこの問題は解消されているので、JavaFX を土台としたものに変更しています。
    • 唯一、グローバルなマウスカーソルのアドレスを取得するのに AWT に頼っていますが、JavaFX 11 で待望の Robot クラスが追加されるので、11 になれば "Pure JavaFX" なアプリケーションにできる見込みです。
  • マウスカーソルの座標を取得するタイミングを以前は Swing の Timer で起こしていたのですが、これを JavaFXAnimationTimer を利用するように変更し、より滑らかに目玉が動くようになっています。
  • Stage のスタイルを StageStyle.TRANSPARENT に変更し、本家 xeyes のように背景を透過するようにしました。

f:id:aoe-tk:20180825210949p:plain

最後のポイントに書いたように、Stage のスタイルを StageStyle.TRANSPARENT に変更したため、ウィンドウのタイトルバーやウィンドウ枠がなくなるため、ウィンドウの移動やリサイズを自力で実装する必要があります。

その際に気が付いたことがありました。リサイズや移動が可能であることをが分かるように、アプリケーション上でのマウスカーソルの位置によってマウスカーソルの形状を変えるようにしました。ところが Windows 上で動かした場合と Mac 上で動かした場合に次のような違いが見られたのです。

  • Mac 上で動かした場合、マウスカーソルが (透明になっている) ウィンドウの端や隅に到達してもちゃんとカーソル形状が変わる。
  • Windows 上で動かした場合、「目」の上でしかマウスカーソルの形状が変更しない。
    • と言うか、マウスイベントが全て「目」の上でしか発生しない。

この動きの違いに悩んで色々調べてみたのですが、どうも JavaFX 側の考え方としては Windows 版の動きが正 のようです。Mac 版の動きについて次のようなバグチケットが作られていました。

https://bugs.openjdk.java.net/browse/JDK-8088104

まあ考えてみれば理屈は分かります。非矩形に作ったのにマウスが矩形に沿って反応するのは確かに不自然です。自分が作ったこの xeyes については Windows 版ではウィンドウの四隅からリサイズが行えないという不便な点がありますが、縦方向と横方向のリサイズは可能なので、まあこれでいっかーとそのままにしましたw

というわけで小ネタでした。

*1:完全に自分用に作ったので IntelliJ 形式のプロジェクトそのままでアップしてます。まあ特殊なライブラリは一切使っていないので、他の IDE やエディタでも普通に扱えるはずです。