JavaFX 9 で FontMetrics を取得する

Java JavaFX NetBeans

このエントリーは、JavaFX Advent Calendar 2017 の 20 日目です。

現時点でもエントリーが無いので急遽先日遭遇した問題に解決策を教えていただいたのでそれを記事にしました。

昨日は @aoetk さんの「Bean ValidationのJavaFX対応」でした。

明日も、この記事を書いている現時点ではまだ空いてます。(^_^; きっと誰かが素敵な記事を投稿してくれると楽しみにしています。

11 月から IBM Cloud (Bluemix)ライト・アカウントが気楽に使えるようになり Watson Personality Insights を利用した人格診断プログラムを組んで楽しんでいました。

pi 

その際に Canvas に文字を描くときの位置決めに難儀したので FontMetrics を取得する方法をφ(..)メモメモ

まず、Java で FontMetrics を取得するとしたら java.awt.FontMetrics クラスを使うことができます。

Abstract Window Toolkit を使って下記のようなプログラムを組んでみました。

懐かしいコードですね。

83 行目で FontMetrics を Graphics コンテキストより取得してフォントの構造データをそれぞれの取得メソッドで取得しています。

原点の X, Y 座標に薄いグレーでラインをひいてます。

フォントの高さ関するデータもそれぞれラインをひいてみました。

awt

awt2

Abstract Window Toolkit を使って FontMetrics を得ることは簡単にできることが確認できました。

それでは JavaFX 9 ではどうでしょうか?

同じようなプログラムを組んでしました。

残念ながらコンパイルエラーです。

error

「名前のないモジュールにエクスポートされていません」ってなんのことですか?

JavaFX 9 では java.awt.FontMetrics クラスは使えないようなので com.sun.javafx.tk.FontMetrics, com.sun.javafx.tk.Toolkit を使用しました。

確か、JavaFX 8 では使えていたような記憶があるんだけど・・・

そう言えば、Project Jigsaw の影響で com.sun ではじまるパッケージが使えないものがあるようです。

このプログラムで使っている com.sun.javafx.tk.FontMetrics, com.sun.javafx.tk.Toolkit も JDK 内部(モジュール)にちゃんとあるのにデフォルトで使えなくしてあります。

困りました!

Windows 環境なら JavaFX 9 だったら HiDPI 対応の恩恵を享受することが可能なのに。

ちなみに JavaFX 8 だったら問題なく動きました。

さて、どうしたものか。。。

以前 Twitter で 「hoge は fuga ができないからクソッ!」もしくは女子高生を装ってヘルプをつぶやくと優秀なプログラマが解決策を提案してくれるという法則を学んだ。

私には役者の才能も無いし、小賢しいことをするのは面倒なので素直に Twitter でつぶやいたところ心優しい Java プログラマーが助けてくれました。

ありがとうございます!

早速 NetBeans に javacとjavaのオプションを設定してコンパイル、実行をしたところ無事に動きました。(^_^)

s

s2

fx

fx2

ちなみに、テキストの挿入位置の Y 座標の位置はデフォルトでは VPos.BASELINE となっています。

gc.setTextBaseline(VPos.BASELINE);

これは次のように変更することができます。

gc.setTextBaseline(VPos.TOP);

top

gc.setTextBaseline(VPos.CENTER);

center

gc.setTextBaseline(VPos.BOTTOM);

bottom

ああっ・・・ しまった。(>_<) 左のテキストの位置の修正忘れた。見なかったことにしてください。(ごめんなさい)

ついでに Leading が無いフォントの表示も見ておきます。

awt3

awt4

fx3

fx4

AWT と JavaFX では FontMetrics の扱い方に違いがあるので注意が必要ですね。

 

まとめ

さて、ここで JavaFX で FontMetrics を扱うために com.sun.javafx.tk.FontMetrics, com.sun.javafx.tk.Toolkit を使用します。

これを JavaFX 9 で使うためには javacとjavaのオプションに –add-exports=javafx.graphics/com.sun.javafx.tk=ALL-UNNAMED の設定が必要です。

参考

JEP 261: Module System

カプセル化を破る

モジュールシステムによって定義されたアクセス制御境界に違反し、コンパイラと仮想マシンによって強制されて、
あるモジュールが別のモジュールの一部の非通知タイプにアクセスできるようにする必要があることがあります。
これは、例えば、内部型のホワイトボックステストを可能にするため、
またはサポートされていない内部APIをそれらに依存するようになったコードに公開するために望ましいことがある。
これを行うには、コンパイル時と実行時の両方で–add-exportsオプションを使用できます。
構文は次のとおりです。

–add-exports <source-module>/<package>=<target-module>(,<target-module>)*

<source-module>と<target-module>はモジュール名で、<package>はパッケージ名です。

–add-exportsオプションは、複数回使用できますが、ソースモジュールとパッケージ名の特定の組み合わせに対して最大で1回使用できます。
各インスタンスの効果は、指定されたパッケージの修飾されたエクスポートをソースモジュールからターゲットモジュールに追加することです。
これは基本的に、モジュール宣言内のエクスポート句のコマンドライン形式、またはModule :: addExportsメソッドの無制限な形式の呼び出しです。
結果として、ターゲットモジュールがソースモジュールの名前付きパッケージ内のパブリックタイプにアクセスできるようになります。
ターゲットモジュールはソースモジュールをモジュール宣言のrequires節、Module :: addReadsメソッド、または–add-readsオプションのインスタンスです。
たとえば、jmx.wbtestモジュールに、java.managementモジュールの非エクスポートcom.sun.jmx.remote.internalパッケージのホワイトボックス・テストが含まれている場合、それが必要とするアクセスはオプションを使用して許可することができます。

–add-exports java.management/com.sun.jmx.remote.internal=jmx.wbtest

特殊なケースとして、<target-module>がALL-UNNAMEDの場合、ソースパッケージは、最初に存在するか、後で作成されるかに関係なく、名前のないすべてのモジュールにエクスポートされます。
したがって、java.managementモジュールのsun.managementパッケージへのアクセスは、オプションを介してクラスパス上のすべてのコードに与えることができます。

–add-exports java.management/sun.management=ALL-UNNAMED

–add-exportsオプションを使用すると、指定されたパッケージのパブリックタイプにアクセスできます。
コアリフレクションAPIのsetAccessibleメソッドを使用して、非公開のすべての要素にさらにアクセスしてアクセスできるようにする必要があることがあります。
これを行うには、実行時に–add-opensオプションを使用することができます。
–add-exportsオプションと同じ構文です:

–add-opens <source-module>/<package>=<target-module>(,<target-module>)*

<source-module>と<target-module>はモジュール名で、<package>はパッケージ名です。
–add-opensオプションは複数回使用できますが、ソースモジュールとパッケージ名の特定の組み合わせに対して最大で1回使用できます。
各インスタンスの効果は、名前付きパッケージの修飾されたオープンをソースモジュールからターゲットモジュールに追加することです。
これは基本的に、モジュール宣言のopens節のコマンドライン形式、またはModule :: addOpensメソッドの無制限な形式の呼び出しです。
結果として、ターゲットモジュール内のコードは、ターゲットモジュールがソースモジュールを読み取る限り、
ソースリフレクションAPIを使用して、ソースモジュールの名前付きパッケージ内のパブリックなどのすべてのタイプにアクセスできます。
オープンパッケージは、コンパイル時にエクスポートされていないパッケージと区別できないため、
–add-opensオプションはそのフェーズでは使用できません。

–add-exportsと–add-opensオプションは、細心の注意を払って使用する必要があります。
それらを使用して、ライブラリモジュールの内部API、またはJDK自体のアクセス権を取得することはできますが、自己責任で行ってください。
内部APIが変更または削除された場合、ライブラリまたはアプリケーションは失敗します

 

((((;゚Д゚)))))))

I wish you a Merry Christmas.

Hatena タグ: ,,

« »

Leave a Reply

* が付いている項目は、必須項目です!

次の HTML タグと属性を利用できます: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">

*

Trackback URL