2012-05-21 40 views
17

我正在将大量自定义绘制的Swing/Graphics2D应用转换为JavaFX2应用。虽然我非常喜欢新的API,但在绘制椭圆时,如果在鼠标移动的任何位置都要绘制鼠标光标,我似乎遇到性能问题。当我以稳定的方式移动我的鼠标时,并不是快速滑动,我注意到椭圆总是在鼠标轨迹后面画几厘米,并且只有当我停止移动光标时才捕捉到。这在只有少数节点的场景图中。在我的Swing应用程序中,我没有这个问题。通过在javafx 2中拖动来移动节点的正确方法?

我想知道如果这是正确的方法来绘制一个形状的mousecursor是?

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 

这个标志通常是内部性能测试,这就是为什么它是未公开的,但我们已经用了几个月了,并没有任何问题,它至今。

编辑:

还有另一个类似的方式来解决此错误,可能是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使用上述代码。

更新 上面的例子仍然滞后于被拖动的对象很小时被拖动的对象。

另一种方法是使用ImageCursor,该ImageCursor包含一个叠加在正在拖动的节点的图像表示上的MousePointer,然后在拖动的开始和完成时隐藏并显示实际节点。这意味着节点拖动渲染不会滞后游标(因为节点的图像表示现在是游标)。然而,这种方法有一些缺点=> ImageCursors的大小和格式受到限制,另外您需要将节点转换为图像以将其放置在ImageCursor中,为此,您可能需要高级Node => Image转换操作可用于JavaFX 2.2+。

+0

感谢您的精心解答,但使用您的方法我也得到了滞后。奇怪的! –

+0

我已经添加了我的意思的完整简单示例。即使这个小程序以稳定的方式移动鼠标时也会显示滞后。请注意,我不想拖动椭圆,但即使只是移动鼠标而不点击,我也想将其显示在鼠标光标下方。 –

+0

好的,当我将对象拖动得足够小时,我可以注意到与我在示例代码中看到的方法相同的延迟(当被拖动的对象较大时,它只会被遮罩)。 – jewelsea

2

有这个“cacheHint”属性,可用于所有节点,这可能有帮助吗?

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

在某些情况下,诸如动画是呈现非常昂贵的节点,期望的是能够执行的节点上的变换,而不需要重新生成缓存的位图。在这种情况下的选项是在缓存的位图本身上执行转换。

该技术可以对动画性能进行戏剧性改进,但也可能导致视觉质量下降。 cacheHint变量向系统提供关于如何以及何时进行折衷(动画性能的视觉质量)可接受的提示。

如果您的椭圆在整个时间保持不变,但每次移动一个像素时都会重绘,这似乎是一个巨大的放缓。

+0

谢谢,似乎没有区别,虽然 –

3

对我来说,它看起来不像绘画性能的问题,但是如何生成鼠标事件序列。事件不是实时生成的,有些会在鼠标移动快时跳过。对于大多数应用来说,这将是充分的方式。鼠标指针实时移动,没有任何时间滞后。

如果您不想要这种效果,您将不得不直接听鼠标指针或找到一种方法来获得更高密度的事件。我不知道自己如何。

+1

嗯,你有任何文件来支持这些索赔?我觉得这很奇怪,考虑到你可以在SceneBuilder中使用一个元素,尽可能快地拖动鼠标,它会一直粘在鼠标指针上。 –

+0

对不起,找不到任何东西。写了一个测试,我的机器上两个事件之间大约有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(真); (我用面板使用了许多儿童像一个文本字段)

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; 
    } 
} 
相关问题