質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
JavaFX

JavaFXとは、Java仮想マシン上で動作するリッチインターネットアプリケーション (RIA) のGUIライブラリです。Swingとは異なり、FXMLと呼ばれる XMLとCSSを併用してデザインを記述します。

Q&A

解決済

2回答

4760閲覧

JavaFXでダブルバッファリングのやり方が分からない

ywotnf

総合スコア16

JavaFX

JavaFXとは、Java仮想マシン上で動作するリッチインターネットアプリケーション (RIA) のGUIライブラリです。Swingとは異なり、FXMLと呼ばれる XMLとCSSを併用してデザインを記述します。

0グッド

0クリップ

投稿2016/05/28 14:29

編集2016/05/31 09:48

JavaFXでダブルバッファリングのやりかたが分かりません。

BufferedImageクラスとImageIOクラスを使ってイメージに書き込んで
それをSwingFXUtilsで変換してキャンバスに表示すればいいのでしょうか?

ほかに方法があるなら教えてください

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

結論をいうと「ダブルバッファリングをJavaFXで意識しないほうがよいのではないか」というのが自分の意見です。

グラフィックシステムにおいて「再描画」には2つぐらいの意味があると思います。

  1. 画面の重なり具合などの状態の変化に応じて不可視エリアが可視に変化した際に再描画する
  2. 表示すべきモデルデータが変化したときに表示内容を変えるために再描画する

ダブルバッファリングは上記の1,2ともに「複雑な描画プロセスが目に見えてしまうことによる画面のちらつきなどの見づらさを防止する」目的で用いる再描画のための工夫ですね。

swingでは(計算機の搭載メモリーが大きくなってきたためか)ダブルバッファリングがデフォルトになっていると思います(少なくともWindows JREではそのような動作です)。よって意識するとしたら「あえてダブルバッファリングをさせたくない特殊なケースのみ」ともいえるでしょう。

JavaFXではどうかといえば、プログラマーの仕事は「表示すべきビューモデルの設定」であり「どのように再描画(=レンダリング)」するかを意識する機会はほぼありません。そもそも1.のケースでswingの時代にあったJComponent.update/paintというメソッドが存在しません。ゆえに「どう再描画すべきか」をコードに書く余地がないともいえましょう。

さてJavaFXのCanvasについていえば、GraphicsContextへの描画がJComponent#paintComponentでGraphicsを用いて再描画することと似てはいるものの意味合いは違っており「再描画する処理」ではなく「どのような描画内容にするかをCanvasに対して教える(=モデルの変更)処理」ということに注意する必要があります。実際の再描画はJavaFXが必要なタイミングで自動的に行います。JavaFXのCanvasのリファレンスには以下のように書かれています。

呼出しごとに、必要なパラメータがバッファにプッシュされ、その後、パルスの最後に、レンダリング・スレッドによってCanvasノードのイメージ上にそれらのパラメータがレンダリングされます。

これを文字通り読むと「GraphicsContextに書いた通りに再描画が必要な契機でレンダリングします」といっているだけでダブルバッファリングを行うかどうかははっきりしません。よってCanvasへ複数の図形を描画している処理を、わざわざ自前で用意したオフスクリーンバッファを介して行うことに意味があるかどうかはCanvasがどのように再描画をしているかの実装に依存すると考えます。試しに以下のようなコードを実行してみました。(4万円代のdesktop PC, Windows10 64bit)

java

1package sample; 2 3import javafx.application.Application; 4import javafx.application.Platform; 5import javafx.scene.Scene; 6import javafx.scene.canvas.Canvas; 7import javafx.scene.canvas.GraphicsContext; 8import javafx.scene.control.ScrollPane; 9import javafx.scene.layout.StackPane; 10import javafx.scene.paint.Color; 11import javafx.stage.Stage; 12 13import java.util.Random; 14 15import static java.lang.Thread.sleep; 16 17/** 18 * Created by KSOH on 2016/12/21. 19 */ 20public class DoubleBufferingFX extends Application { 21 Canvas canvas; 22 23 @Override 24 public void start(Stage primaryStage) throws Exception { 25 canvas = new Canvas(1000, 1000); 26 ScrollPane scroll = new ScrollPane(canvas); 27 scroll.setPrefSize(300, 300); 28 StackPane border = new StackPane(scroll); 29 Scene scene = new Scene(border); 30 primaryStage.setScene(scene); 31 primaryStage.setTitle("Double Buffering"); 32 primaryStage.show(); 33 34 Thread t = new Thread(() -> { 35 for (;;) { 36 Platform.runLater(() -> { 37 drawCanvas(); 38 }); 39 try { 40 sleep(100); 41 } catch (InterruptedException e) { 42 break; 43 } 44 } 45 }); 46 t.setDaemon(true); 47 t.start(); 48 } 49 50 Random rnd = new Random(); 51 52 void drawCanvas() { 53 int N = 10000; 54 GraphicsContext gc = canvas.getGraphicsContext2D(); 55 for (int i = 0; i < N; i++) { 56 double x = rnd.nextDouble() * 1000; 57 double y = rnd.nextDouble() * 1000; 58 float hue = rnd.nextFloat() * 360; 59 Color c = Color.hsb(hue, 1F, 1F); 60 gc.setFill(c); 61 gc.fillRect(x, y, 2, 2); 62 } 63 } 64 65 public static void main(String[] args) { 66 Application.launch(args); 67 } 68}

上記はダブルバッファリングを自分では行わず、1000x1000のCanvas上で0.1秒ごとにランダムな位置へ1万個の2x2の正方形を描画するというものです。観察した限りではスクロールバーを動かしても描画がもたつくことはなく画面の更新も一瞬で更新されるように見えます。時間経過によってスクロールが遅くなることがないところをみるとGraphicsContextへ指示した描画命令そのものを覚えているわけではなさそうな感じですね。つまりうまいことダブルバッファリング的なことをしてくれていそうに見えます。

リファレンスへのあっさりとした記述や上記のコードの結果から私が感じた印象は「画面描画メカニズムに関するハードウェアの利用や最適化については複雑すぎてプログラマーに意識させるのは最早最適なAPI設計にはできなさそうなのでプログラマーが気にしなくてもJavaFXのブラックボックスの中でほぼうまくやってくれるように設計方針が進化している」でした。

投稿2016/12/21 09:53

KSwordOfHaste

総合スコア18394

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ベストアンサー

JavaFXではダブルバッファリングの必要はありません。

Canvas の GraphicsContext に描けば、バッファに溜まっていき、pulseごとに描画されます。

Java

1GraphicsContext gc = canvas.getGraphicsContext2D(); 2gc.fillRect(0, 0, 100, 100);

https://docs.oracle.com/javase/jp/8/javafx/api/javafx/scene/canvas/GraphicsContext.html

投稿2016/11/20 22:18

MasashiKimura

総合スコア1150

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問