2012-05-21 18 views
17

多くのカスタムペイントを含むSwing/Graphics2DアプリをJavaFX2アプリに変換しています。新しいAPIが大好きですが、マウスが動かされた場所のどこにでもマウスカーソルの下にペイントしたい楕円を描画すると、パフォーマンスに問題があるようです。私のマウスを安定したやり方で動かすと、ちょっと速いのではなく、楕円がマウスの軌跡上に数センチ後ろに描かれていて、カーソルの移動を止めるときだけ楕円が引かれます。シーングラフの中には、一握りのノードしかありません。私のSwingアプリでは、その問題はありませんでした。javafx 2をドラッグしてノードを移動する正しい方法は?

これは、マウスカーソルがある図形を描画するための正しいアプローチであると思いますか?

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ビット版の場合)にアップグレードし、しかし違いを確認していないようです。

+0

あなたのソリューション自体はあなたに感謝し、私をたくさん助けました! – Matteo

+0

それはあなたを助けてくれてうれしいです:) –

答えて

6

あなたは(あなたのマウスとドラッグ形状の間で)記述しているラグ知らJavaFXのバグです:

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

は、あなたが使用して(少なくとも、Windows上で)、それを回避することができますが、文書化されていないJVMフラグ:

-Djavafx.animation.fullspeed=true 

このフラグは、それが文書化されている理由である内部パフォーマンステストのために通常であるが、我々は数ヶ月のためにそれを使用してきたし、今のところそれで何の問題もありませんでした。

EDIT:

CPUの使用状況について少し楽かもしれないこのバグを回避するために別の、同様の方法があります。プリズムの垂直同期をオフにするだけです。

-Dprism.vsync=false 

アプリでは、これらの回避策のいずれかがラグを解決します。両方を行う必要はありません。ここ

+1

すごい、この後...このトリックは確かに –

+0

これはすごいです、ありがとう –

18

LabelPaneの中でドラッグできるようにするためのコードです。 私はそれにマウスの後ろに大きな遅れがないことに気付きません。ここ

// 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; } 

は、上記のコードを使用して小さな完全example appあります。

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

代替方法は、ドラッグされるノードのイメージ表現上に重ね合わされたMousePointerを含むImageCursorを使用して、ドラッグの開始時および終了時に実際のノードを非表示にして表示することです。これは、ノードのドラッグ・レンダリングが(ノードのイメージ表示が現在カーソルになっているので)カーソルを遅らせることはないことを意味します。しかし、このアプローチには欠点があります。> ImageCursorsのサイズとフォーマットに制限があります。ノードをImageに変換してImageCursorに配置する必要があります。 JavaFX 2.2以降で利用可能です。

+0

精巧な答えをありがとうが、あなたの方法を使用して、私はあまりにも遅れを取得します。奇妙な! –

+0

私が意味するものの完全な簡単な例を追加しました。この小さなプログラムであっても、マウスを安定して動かすと、遅れが表示されます。私は楕円をドラッグしたくないのですが、マウスを動かしてクリックしなくてもマウスカーソルの下に表示したいのです。 –

+0

OK、オブジェクトをドラッグして十分に小さいものにすると、サンプルコードに表示されているアプローチと同じ遅れに気づくことができます(ドラッグされるオブジェクトが大きくなるとマスクされただけです)。 – jewelsea

2

この「cacheHint」プロパティは、すべてのノードで使用でき、役立つかもしれませんか?そのようなレンダリングすることは非常に高価であるノードをアニメーションのような特定の状況下では

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

、キャッシュされたビットマップを再生成することなく、ノード上で変換を実行できることが望ましいです。そのような場合のオプションは、キャッシュされたビットマップ自体で変換を実行することです。

このテクニックは、アニメーションのパフォーマンスを大幅に向上させることができますが、視覚的品質も低下する可能性があります。 cacheHint変数は、そのトレードオフ(アニメーションパフォーマンスのビジュアル品質)がいつ、どのように受け入れられるかについてのヒントをシステムに提供します。

あなたの楕円は同じ時間のままですが、1ピクセルずつ移動するたびに再描画される場合、これは大きな減速のようです。

+0

ありがとう、違いはありませんが –

3

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

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

+1

うーん、あなたはこれらの主張を裏付けるための資料がありますか?あなたができる限り速くマウスをドラッグすると、マウスポインタに常に固執します。 –

+0

申し訳ありませんが、何も見つかりませんでした。私のマシン上の2つのイベントの間には約10ミリ秒間ありました。 SceneBuilderで私は同様の遅れを認めます。 –

+0

私はあなたが正しいと思います、問題はMouseEventsに関連しています。JavaFX JIRAリポジトリにこれに関連するバグがあります:https://javafx-jira.kenai.com/browse/RT-34608 – Xanatos

2

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

+0

私はこれがチャートAPIにのみ適用されると思います –

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); 
    } 
} 
1

をラベルをドラッグアンドドロップするためのコードです:Node.setCache(真)。 (私は、TextFieldのような多くの子供を持つペインでそれを使う)

0

ドラッグスフィア

@Override 
public void initialize(URL location, ResourceBundle resources) { 
    super.initialize(location, resources); 
    labelTableName.setText("Table Categories"); 

    final PhongMaterial blueMaterial = new PhongMaterial(); 
    blueMaterial.setDiffuseColor(Color.BLUE); 
    blueMaterial.setSpecularColor(Color.LIGHTBLUE); 

    final Sphere sphere = new Sphere(50); 
    sphere.setMaterial(blueMaterial); 

    final Measure dragMeasure = new Measure(); 
    final Measure position = new Measure(); 
    sphere.setOnMousePressed(mouseEvent -> { 
     dragMeasure.x = mouseEvent.getSceneX() - position.x; 
     dragMeasure.y = mouseEvent.getSceneY() - position.y; 
     sphere.setCursor(Cursor.MOVE); 
    }); 
    sphere.setOnMouseDragged(mouseEvent -> { 
     position.x = mouseEvent.getSceneX() - dragMeasure.x; 
     position.y = mouseEvent.getSceneY() - dragMeasure.y; 
     sphere.setTranslateX(position.x); 
     sphere.setTranslateY(position.y); 
    }); 
    sphere.setOnMouseReleased(mouseEvent -> sphere.setCursor(Cursor.HAND)); 
    sphere.setOnMouseEntered(mouseEvent -> sphere.setCursor(Cursor.HAND)); 

    bottomHeader.getChildren().addAll(sphere); 

} 

class Measure { 
    double x, y; 

    public Measure() { 
     x = 0; y = 0; 
    } 
} 
関連する問題