我有一个包含大量可拖动节点的应用程序,这可能会有点慢。特别是在:
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导致所包含的组的播放非常缓慢。
答案 0 :(得分:3)
好的......我花了一些时间来检查鼠标拖动的性能有很多对象......
我是在Mac Pro(4核,8GB RAM)上完成的。
如果我使用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);
}
}