26

多くのカスタム ペイントを含む Swing/Graphics2D アプリを JavaFX2 アプリに変換しています。私は新しい API をとても気に入っていますが、マウスが移動する場所にマウス カーソルの下に描画したい楕円を描画すると、パフォーマンスの問題が発生するようです。マウスをばかげた速さではなく安定した方法で動かすと、楕円が常にマウスの軌跡の数センチメートル後ろに描画され、カーソルの移動を停止したときにのみ追いつくことに気付きます。これは、ほんの一握りのノードを持つシーングラフにあります。私のSwingアプリでは、その問題はありませんでした。

マウスカーソルがある場所に図形を描画するための正しいアプローチであるかどうか疑問に思っていますか?

import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.SceneBuilder;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Ellipse;
import javafx.scene.shape.EllipseBuilder;
import javafx.stage.Stage;

public class TestApp extends Application {
public static void main(String[] args) {
    launch(args);
}

@Override
public void start(Stage primaryStage) throws Exception {
    Pane p = new Pane();

    final Ellipse ellipse = EllipseBuilder.create().radiusX(10).radiusY(10).fill(Color.RED).build();
    p.getChildren().add(ellipse);

    p.setOnMouseMoved(new EventHandler<MouseEvent>() {
        public void handle(MouseEvent event) {
            ellipse.setCenterX(event.getX());
            ellipse.setCenterY(event.getY());
        }
    });

    Scene scene = SceneBuilder.create().root(p).width(1024d).height(768d).build();
    primaryStage.setScene(scene);

    primaryStage.show();
}
}

小さな更新: JavaFX 2.2 と Java7u6 (Windows 7 64 ビット) にアップグレードしましたが、違いはないようです。

4

9 に答える 9

25

これは、ラベルをペイン内でドラッグできるようにするために使用するコードです。マウストレイルの後ろに大きな遅れはありません。

// allow the label to be dragged around.
final Delta dragDelta = new Delta();
label.setOnMousePressed(new EventHandler<MouseEvent>() {
  @Override public void handle(MouseEvent mouseEvent) {
    // record a delta distance for the drag and drop operation.
    dragDelta.x = label.getLayoutX() - mouseEvent.getSceneX();
    dragDelta.y = label.getLayoutY() - mouseEvent.getSceneY();
    label.setCursor(Cursor.MOVE);
  }
});
label.setOnMouseReleased(new EventHandler<MouseEvent>() {
  @Override public void handle(MouseEvent mouseEvent) {
    label.setCursor(Cursor.HAND);
  }
});
label.setOnMouseDragged(new EventHandler<MouseEvent>() {
  @Override public void handle(MouseEvent mouseEvent) {
    label.setLayoutX(mouseEvent.getSceneX() + dragDelta.x);
    label.setLayoutY(mouseEvent.getSceneY() + dragDelta.y);
  }
});
label.setOnMouseEntered(new EventHandler<MouseEvent>() {
  @Override public void handle(MouseEvent mouseEvent) {
    label.setCursor(Cursor.HAND);
  }
});

. . .

// records relative x and y co-ordinates.
class Delta { double x, y; }

上記のコードを使用した小さな完全なサンプルアプリを次に示します。

更新 上記の例では、ドラッグされているオブジェクトが小さい場合でも、ドラッグされているオブジェクトがカーソルの後ろに遅れます。

別のアプローチは、ドラッグされているノードの画像表現に重ねられたMousePointerで構成されるImageCursorを使用し、ドラッグの開始時と終了時に実際のノードを非表示にして表示することです。これは、ノードのドラッグレンダリングがカーソルに遅れをとらないことを意味します(ノードの画像表現がカーソルになっているため)。ただし、このアプローチには欠点があります=> ImageCursorのサイズと形式に制限があり、さらにノードをImageに変換してImageCursorに配置する必要があります。そのためには、高度なノード=>画像変換操作のみが必要になる場合があります。 JavaFX2.2以降で使用できます。

于 2012-05-21T17:05:26.740 に答える
4

私には、ペイントのパフォーマンスの問題ではなく、一連のマウス イベントがどのように生成されるかという問題のように見えます。マウスが速く動くと、イベントはリアルタイムで生成されず、一部はスキップされます。ほとんどのアプリケーションでは、これで十分です。マウスポインタはタイムラグなくリアルタイムに移動します。

この効果が必要ない場合は、マウス ポインターを直接リッスンするか、より高密度でイベントを取得する方法を見つける必要があります。私は自分自身の方法を知りません。

于 2012-08-25T08:02:28.333 に答える
2

この「cacheHint」プロパティがあり、すべてのノードで利用できます。

http://docs.oracle.com/javafx/2/api/javafx/scene/Node.html#cacheHintProperty

レンダリングに非常にコストがかかるノードをアニメーション化するなど、特定の状況では、キャッシュされたビットマップを再生成することなく、ノードで変換を実行できることが望ましいです。このような場合のオプションは、キャッシュされたビットマップ自体で変換を実行することです。

この手法により、アニメーションのパフォーマンスが大幅に向上しますが、視覚的な品質が低下する可能性もあります。cacheHint 変数は、そのトレードオフ (アニメーション パフォーマンスに対する視覚的品質) が許容される方法とタイミングに関するヒントをシステムに提供します。

楕円がずっと同じままで、1 ピクセルずつ移動するたびに再描画される場合、これは大幅な速度低下のようです。

于 2012-07-17T15:16:03.517 に答える
2

チャート上のノードをドラッグ可能にしようとしているときに、同じ問題が発生していました。私は呼び出すことでそれを修正しましたchart.setAnimated(false);私の場合、私のコードが行っていた変更に素敵な滑らかなアニメーションを適用する JavaFX によって遅延が引き起こされていました。

于 2012-09-30T15:58:47.170 に答える
1

使用できます: Node.setCache(true); (私は TextField のような多くの子を持つペインで使用します)

于 2015-07-23T12:35:21.523 に答える
1

javafxでマウスを使用してラベルをドラッグアンドドロップするコードは次のとおりです

@FXML
public void lblDragMousePressed(MouseEvent m)
{
    System.out.println("Mouse is pressed");

    prevLblCordX= (int) lblDragTest.getLayoutX();
    prevLblCordY= (int) lblDragTest.getLayoutY();
    prevMouseCordX= (int) m.getX();
    prevMouseCordY= (int) m.getY();     
}
//set this method on mouse released event for lblDrag
@FXML
public void lblDragMouseReleased(MouseEvent m)
{       
    System.out.println("Label Dragged");    
}
// set this method on Mouse Drag event for lblDrag
@FXML
public void lblDragMouseDragged(MouseEvent m)
{   
    diffX= (int) (m.getX()- prevMouseCordX);
    diffY= (int) (m.getY()-prevMouseCordY );        
    int x = (int) (diffX+lblDragTest.getLayoutX()-rootAnchorPane.getLayoutX());
    int y = (int) (diffY+lblDragTest.getLayoutY()-rootAnchorPane.getLayoutY());     
    if (y > 0 && x > 0 && y < rootAnchorPane.getHeight() && x < rootAnchorPane.getWidth()) 
    { 
     lblDragTest.setLayoutX(x);
     lblDragTest.setLayoutY(y);
    }
}
于 2014-09-18T08:55:34.310 に答える