javafx,拖动优化 - 各种想法

时间:2014-11-30 06:51:19

标签: java javafx

我有一个包含大量可拖动节点的应用程序,这可能会有点慢。特别是在:

  • 拖动包含其他节点的节点或
  • 在另一个IF中拖动Node会导致扩展父级的Bounds [几乎就像缓存了一些范围相关的数据一样,内部的double值很常见,如果范围发生变化则需要进行额外处理](编辑:这有现在被解释为父母的布局通行证)
问:通过对整数(首先转换为int)然后重新分配为双精度执行某些操作(少数可以控制类型)可以获得什么? (编辑:现在已经回答了)

Q1:我怎么能加快速度呢?

==========更新: 感谢到目前为止的建议,我确定我的主要问题是在Region根目录中平移Region容器,因为它触发容器Region中的布局传递,而这反过来(我认为)ping-pongs在所有中执行布局传递( ca. 40)儿童节点(它们本身很复杂 - 它们包含文本字段,按钮等)。

到目前为止,我发现最快的解决方案是在一个组中平移一个组(已经快得多),其中组被另外修改(子类,覆盖计算...方法)以确保父/ root不需要在拖动过程中调整大小(遗憾的是,不那么明显)。

class FastGroup extends Group {
    //'stop asking about size' functionality

    double widthCache;
    double heightCache;

    protected double computePrefWidth(double height) {
        return widthCache != 0 ? widthCache : super.computePrefWidth(height);
    }

    protected double computePrefHeight(double width) {
            return heightCache != 0 ? heightCache : super.computePrefHeight(width);

    }

    public void initDragging(){
    //if a child of this Group goes into drag
    //add max margins to Group's size 
        double newW = getBoundsInLocal().getWidth() + TestFXApp03.scene.getWidth()*2;
        double newH = getBoundsInLocal().getHeight() + TestFXApp03.scene.getHeight()*2;
    //cache size
        widthCache = newW;
        heightCache = newH;
    }

    public void endDragging(){
        widthCache = 0;
        heightCache = 0;
    }
}

然而,Group会产生自己的问题。

问题3:为什么我不能与Pane实现相同(尝试作为第三选项)?根据Docs,a Pane:

  

'除了将可调整大小的孩子调整为他们的大小之外,不执行布局   首选尺寸'

......当一个小组:

  

'将“管理可调整大小的孩子”自动调整为他们的首选   布局过程中的尺寸'

     

'不能直接调整大小'

...这对我来说听起来完全一样,但是用作root的Pane导致所包含的组的播放非常缓慢。

2 个答案:

答案 0 :(得分:3)

好的......我花了一些时间来检查鼠标拖动的性能有很多对象......

我是在Mac Pro(4核,8GB RAM)上完成的。

  1. 使用setOnMouseDragged()处理函数中的setTranslateX()和setTranslateY()进行鼠标拖动,间隔为17ms(60Hz)。
  2. 如果我向拖拽组添加小圆圈,则拖拽的速度会一直拖到25.000圈。
  3. 在100.000圈中,拖动间隔约为50毫秒(并在拖动过程中显示一些停止)
  4. 在1.000.000圈处,阻力间隔约为500毫秒
  5. 如果我使用snapshot()函数将拖动实现为图像拖动,则1.000.000圈的快照需要600毫秒。然后拖动平稳而快速。

    这里是在拖动过程中使用和不使用图像的完整代码:

    public class DragMany extends Application {
        Point2D lastXY = null;
        Scene myScene;
        long lastDrag;
        ImageView dragImage; 
    
    
        void fill(Group box) {
            Color colors[] = new Color[]{Color.RED, Color.BLUE, Color.GREEN, Color.YELLOW, Color.PINK, Color.MAGENTA };
            for (int i = 0; i < 100000; i++) {
                Circle c = new Circle(2);
                box.getChildren().add(c);
                c.setFill(colors[(i/17) % colors.length]);
                c.setLayoutX(i % 30 * 3);
                c.setLayoutY((i/20) % 30*3);
            }
            box.setLayoutX(40);
            box.setLayoutY(40);
    
        }
        void drag1(Pane pane, Group box) {
            box.setOnMousePressed(event -> {
                lastXY = new Point2D(event.getSceneX(), event.getSceneY());
                lastDrag = System.currentTimeMillis();
            });
            box.setOnMouseDragged(event -> {
                event.setDragDetect(false);
                Node on = box;
                double dx = event.getSceneX() - lastXY.getX();
                double dy = event.getSceneY() - lastXY.getY();
                on.setLayoutX(on.getLayoutX()+dx);
                on.setLayoutY(on.getLayoutY()+dy);
                lastXY = new Point2D(event.getSceneX(), event.getSceneY());
                event.consume();
            });
    
            box.setOnMouseReleased(d ->  lastXY = null);
        }
    
        void drag3(Pane pane, Group box) {
            box.setOnMousePressed(event -> {
                long now = System.currentTimeMillis();
    
                lastXY = new Point2D(event.getSceneX(), event.getSceneY());
                SnapshotParameters params = new SnapshotParameters();
                params.setFill(Color.TRANSPARENT);
                WritableImage image = box.snapshot(params, null);
                dragImage = new ImageView(image);
                dragImage.setLayoutX(box.getLayoutX());
                dragImage.setLayoutY(box.getLayoutY());
                dragImage.setTranslateX(box.getTranslateX());
                dragImage.setTranslateY(box.getTranslateY());
                pane.getChildren().add(dragImage);
                dragImage.setOpacity(0.5);
                box.setVisible(false);
                System.out.println("Snap "+(System.currentTimeMillis()-now)+"ms");
    
                pane.setOnMouseDragged(e -> {
                    if (dragImage == null) return;
                    Node on = dragImage;
                    double dx = e.getSceneX() - lastXY.getX();
                    double dy = e.getSceneY() - lastXY.getY();
                    on.setTranslateX(on.getTranslateX()+dx);
                    on.setTranslateY(on.getTranslateY()+dy);
                    lastXY = new Point2D(e.getSceneX(), e.getSceneY());
                    e.consume();
                });
                pane.setOnMouseReleased(e -> {
                    if (dragImage != null) {
                        box.setTranslateX(dragImage.getTranslateX());
                        box.setTranslateY(dragImage.getTranslateY());
                        pane.getChildren().remove(dragImage);
                        box.setVisible(true);
                        dragImage = null;
                    }
                    lastXY = null;
                    e.consume();
                });
    
                lastDrag = System.currentTimeMillis();
                event.consume();
            });
        }
    
        public void start(Stage primaryStage) {
            Pane mainPane = new Pane(); 
            myScene = new Scene(mainPane, 500, 500);
            primaryStage.setScene(myScene);
            primaryStage.show();
    
            Group all = new Group();
            fill(all);
            mainPane.getChildren().add(all);
            drag3(mainPane, all);
        }
    
        public static void main(String[] args) {
            launch(args);
        }
    

答案 1 :(得分:1)

使用整数或浮点数代替双打不会给你带来太多的性能提升。

相反,您应该在更改节点位置时尝试优化。例如,在拖动时,您可以只渲染在偏移处拖动的所有节点,而只是更改一个节点的位置,而不是更改所有节点的位置。完成拖动后,您可以重新计算拖动的所有节点的位置。

以下是我对你现在如何做的猜测:

void drag(float x, float y) {
    setPosition(x, y); // I'm gueessing this is where your bottle neck is 
    for (Node node : nodes) {
        node.drag(x, y);
    }
}

void render() {
    screen.draw(this.x, this.y);
    for (Node node : nodes) {
        node.render();
    }
}

以下是我将如何通过引入渲染偏移来优化它,以便您在完成拖动时仅设置所有节点的位置:

float xo, yo; // render offsets

void drag(float x, float y) {
    xo = x;
    yo = y;
}

void dragEnd(float x, float y) {
    setPosition(x, y);
    for (Node node : nodes) {
        node.dragEnd(x, y);
    }
}

void render(float xo, float yo) {
    xo += this.xo;
    yo += this.yo;

    screen.draw(this.x + xo, this.y + yo); // render with at offset
    for (Node node : nodes) {
        node.render(xo, yo);
    }
}