javafx形状、绑定坐标值、性能问题、如何从场景中删除

javafx形状、绑定坐标值、性能问题、如何从场景中删除,javafx,Javafx,这是我预期应用程序的简化版本。在JavaFX15.0.1上运行此代码,您将看到一个窗口,其中显示一组蓝色的线和点,以及一个重新加载按钮。旋转鼠标滚轮以放大和缩小图片 问题是: 单击“重新加载”按钮约20次,然后旋转鼠标滚轮。观察应用程序如何冻结数秒,有时cpu活动将达到90%。如果没有可疑,请单击以重新加载 所以我认为问题在于如何从场景中删除所有的形状和绑定,这一定是性能下降的原因,对吗?我执行一个窗格。getChildren().clear()我是不是遗漏了什么 package applica

这是我预期应用程序的简化版本。在JavaFX15.0.1上运行此代码,您将看到一个窗口,其中显示一组蓝色的线和点,以及一个重新加载按钮。旋转鼠标滚轮以放大和缩小图片

问题是: 单击“重新加载”按钮约20次,然后旋转鼠标滚轮。观察应用程序如何冻结数秒,有时cpu活动将达到90%。如果没有可疑,请单击以重新加载

所以我认为问题在于如何从场景中删除所有的形状和绑定,这一定是性能下降的原因,对吗?我执行一个
窗格。getChildren().clear()我是不是遗漏了什么

package application;
    
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import javafx.application.Application;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Line;

public class Main extends Application {
    
    private DoubleProperty zoom = new SimpleDoubleProperty(1.0);
    private int w = 800;
    private int h = 500;

    @Override
    public void start(Stage stage) {
        try {
            Button reload = new Button("reload");
            Pane pane = new Pane();
            pane.setManaged(false);
            
            reload.setOnAction(event -> {
                pane.getChildren().clear();
                List<Displacement> disList = Stream.generate(Displacement::new).limit(1200).collect(Collectors.toList());;
                disList.forEach(dis -> pane.getChildren().add(new DisplacementLine(dis, w, h, pane)));
                disList.forEach(dis -> pane.getChildren().add(new DisplacementCircle(dis, w, h, pane)));
            });
            
            VBox vbox = new VBox(reload, pane);
            Pane root = new Pane();
            Scene scene = new Scene(root);
            root.getChildren().add(vbox);
            stage.setScene(scene);
            stage.setWidth(1000);
            stage.setHeight(600);
            stage.show();
            
            pane.prefWidthProperty().bind(zoom.multiply(w));
            pane.prefHeightProperty().bind(zoom.multiply(h));
            pane.layoutXProperty().bind(root.widthProperty().subtract(pane.prefWidthProperty()).divide(2.0));
            pane.layoutYProperty().bind(root.heightProperty().subtract(pane.prefHeightProperty()).divide(2.0));
            
            pane.setOnScroll(scrollEvent -> {
                double delta = 0.1;
                double f = scrollEvent.getDeltaY() > 0 ? 1+delta : 1/(1+delta);
                zoom.set(zoom.get() * f);
            });
            
            reload.fire();
            
        } catch(Exception e) {
            e.printStackTrace();
        }
    }

    
    public static void main(String[] args) {
        launch(args);
    }
}

class DisplacementLine extends Line {

    final int w, h;
    final double x1, y1, x2, y2;
    
    public DisplacementLine(Displacement dis, int w, int h, Pane pane) {
        this.w = w;
        this.h = h;
        x1 = dis.x;
        y1 = dis.y;
        x2 = dis.x + dis.u;
        y2 = dis.y + dis.v;
        startXProperty().bind(pane.prefWidthProperty().multiply(x1).divide(w));
        startYProperty().bind(pane.prefHeightProperty().multiply(y1).divide(h));
        endXProperty().bind(pane.prefWidthProperty().multiply(x2).divide(w));
        endYProperty().bind(pane.prefHeightProperty().multiply(y2).divide(h));
        setStroke(Color.BLUE);
        setVisible(dis.valid);
    }
}

class DisplacementCircle extends Circle {

    final int w, h;
    final double x, y;
    
    public DisplacementCircle(Displacement dis, int w, int h, Pane pane) {
        this.x = dis.x;
        this.y = dis.y;
        this.w = w;
        this.h = h;
        centerXProperty().bind(pane.prefWidthProperty().multiply(x).divide(w));
        centerYProperty().bind(pane.prefHeightProperty().multiply(y).divide(h));
        setRadius(1.5);
        setFill(Color.BLUE);
        setVisible(dis.valid);
    }
}

class Displacement {

    final static Random rand = new Random();
    final double x, y, u, v;
    final boolean valid;
    
    public Displacement() {
        x = rand.nextDouble() * 1000;
        y = rand.nextDouble() * 600;
        u = rand.nextDouble() * 30;
        v = rand.nextDouble() * 15;
        valid = rand.nextBoolean();
    }
}
包应用;
导入java.util.List;
导入java.util.Random;
导入java.util.stream.collector;
导入java.util.stream.stream;
导入javafx.application.application;
导入javafx.beans.property.DoubleProperty;
导入javafx.beans.property.SimpleDoubleProperty;
导入javafx.stage.stage;
导入javafx.scene.scene;
导入javafx.scene.control.Button;
导入javafx.scene.layout.Pane;
导入javafx.scene.layout.VBox;
导入javafx.scene.paint.Color;
导入javafx.scene.shape.Circle;
导入javafx.scene.shape.Line;
公共类主扩展应用程序{
private DoubleProperty zoom=新的SimpleDoubleProperty(1.0);
私人int w=800;
私有int h=500;
@凌驾
公众假期开始(阶段){
试一试{
按钮重新加载=新按钮(“重新加载”);
窗格=新窗格();
窗格。setManaged(false);
重载.setOnAction(事件->{
pane.getChildren().clear();
List disList=Stream.generate(Displacement::new).limit(1200).collect(Collectors.toList());;
forEach(dis->pane.getChildren().add(新的置换行(dis,w,h,pane));
forEach(dis->pane.getChildren().add(新置换圆(dis,w,h,pane));
});
VBox VBox=新的VBox(重新加载,窗格);
窗格根=新窗格();
场景=新场景(根);
root.getChildren().add(vbox);
舞台场景;
舞台设置宽度(1000);
舞台设置高度(600);
stage.show();
pane.prefWidthProperty().bind(zoom.multiply(w));
pane.prefHeightProperty().bind(zoom.multiply(h));
pane.layoutXProperty().bind(root.widthProperty().subtract(pane.prefWidthProperty()).divide(2.0));
pane.layoutYProperty().bind(root.heightProperty().subtract(pane.prefHeightProperty()).divide(2.0));
pane.setOnScroll(滚动事件->{
双增量=0.1;
双f=scrollEvent.getDeltaY()>0?1+delta:1/(1+delta);
zoom.set(zoom.get()*f);
});
重新加载。开火();
}捕获(例外e){
e、 printStackTrace();
}
}
公共静态void main(字符串[]args){
发射(args);
}
}
类置换线延伸线{
最终整数w,h;
最终双x1,y1,x2,y2;
公共位移线(位移分布、内部w、内部h、窗格){
这个.w=w;
这个,h=h;
x1=dis.x;
y1=dis.y;
x2=dis.x+dis.u;
y2=直径y+直径v;
startXProperty().bind(pane.prefWidthProperty().multiply(x1)、divide(w));
startYProperty().bind(pane.prefHeightProperty().multiply(y1).divide(h));
endXProperty().bind(pane.prefWidthProperty().multiply(x2).divide(w));
endYProperty().bind(pane.prefHeightProperty().multiply(y2).divide(h));
设定行程(颜色:蓝色);
设置可见(无效);
}
}
类位移圆延伸圆{
最终整数w,h;
最终双x,y;
公共置换圆(置换图、int w、int h、窗格){
这个.x=dis.x;
这个.y=dis.y;
这个.w=w;
这个,h=h;
centerXProperty().bind(pane.prefWidthProperty().multiply(x)、divide(w));
centerYProperty().bind(pane.prefHeightProperty().multiply(y).divide(h));
设定半径(1.5);
设置填充(颜色:蓝色);
设置可见(无效);
}
}
类位移{
最终静态随机兰德=新随机();
最后的双x,y,u,v;
最终布尔值有效;
公众流离失所(){
x=rand.nextDouble()*1000;
y=rand.nextDouble()*600;
u=rand.nextDouble()*30;
v=rand.nextDouble()*15;
valid=rand.nextBoolean();
}
}

为了避免GUI冻结,将长进程从应用程序线程中移除。要演示它,请尝试以下内容(仅演示,而不是最佳实现):

根据我的评论,我把这个变体放在一起。这看起来很不错,我可以用这种方式拥有不可变的对象

在这里,我引入了一些函数来侦听窗格宽度/高度属性的更改,然后设置每个形状的坐标,这样就不会创建数千个绑定

这将适应我的最终项目

public class Main extends Application {
    
    private DoubleProperty zoom = new SimpleDoubleProperty(1.0);
    private int w = 800;
    private int h = 500;

    @Override
    public void start(Stage stage) {
        try {
            Button reload = new Button("reload");
            Pane pane = new Pane();
            pane.setManaged(false);
            
            Consumer<Number> setX = value -> {
                double pw = value.doubleValue();
                for (Node node : pane.getChildren()) {
                    if (node instanceof DisplacementLine) {
                        DisplacementLine dl = (DisplacementLine) node;
                        dl.setStartX(pw * dl.x1 / w);
                        dl.setEndX(pw * dl.x2 / w);
                    }
                    if (node instanceof DisplacementCircle) {
                        DisplacementCircle dc = (DisplacementCircle) node;
                        dc.setCenterX(pw * dc.x / w);
                    }
                }
            };
            Consumer<Number> setY = value -> {
                double ph = value.doubleValue();
                for (Node node : pane.getChildren()) {
                    if (node instanceof DisplacementLine) {
                        DisplacementLine dl = (DisplacementLine) node;
                        dl.setStartY(ph * dl.y1 / h);
                        dl.setEndY(ph * dl.y2 / h);
                    }
                    if (node instanceof DisplacementCircle) {
                        DisplacementCircle dc = (DisplacementCircle) node;
                        dc.setCenterY(ph * dc.y / h);
                    }
                }
            };
            pane.prefWidthProperty().addListener((obs, oldval, newval) -> setX.accept(newval));
            pane.prefHeightProperty().addListener((obs, oldval, newval) -> setY.accept(newval));
            
            reload.setOnAction(event -> {
                pane.getChildren().clear();
                List<Displacement> disList = Stream.generate(Displacement::new).limit(1200).collect(Collectors.toList());;
                disList.forEach(dis -> pane.getChildren().add(new DisplacementLine(dis, pane)));
                disList.forEach(dis -> pane.getChildren().add(new DisplacementCircle(dis, pane)));
                setX.accept(pane.getPrefWidth());
                setY.accept(pane.getPrefHeight());
            });
            
            VBox vbox = new VBox(reload, pane);
            Pane root = new Pane();
            Scene scene = new Scene(root);
            root.getChildren().add(vbox);
            stage.setScene(scene);
            stage.setWidth(1000);
            stage.setHeight(600);
            stage.show();
            
            pane.prefWidthProperty().bind(zoom.multiply(w));
            pane.prefHeightProperty().bind(zoom.multiply(h));
            pane.layoutXProperty().bind(root.widthProperty().subtract(pane.prefWidthProperty()).divide(2.0));
            pane.layoutYProperty().bind(root.heightProperty().subtract(pane.prefHeightProperty()).divide(2.0));
            
            pane.setOnScroll(scrollEvent -> {
                double delta = 0.1;
                double f = scrollEvent.getDeltaY() > 0 ? 1+delta : 1/(1+delta);
                zoom.set(zoom.get() * f);
            });
            
            reload.fire();
            
        } catch(Exception e) {
            e.printStackTrace();
        }
    }

    
    public static void main(String[] args) {
        launch(args);
    }
}

class DisplacementLine extends Line {

    final double x1, y1, x2, y2;
    
    public DisplacementLine(Displacement dis, Pane pane) {
        x1 = dis.x;
        y1 = dis.y;
        x2 = dis.x + dis.u;
        y2 = dis.y + dis.v;
        setStroke(Color.BLUE);
        setVisible(dis.valid);
    }
}

class DisplacementCircle extends Circle {

    final double x, y;
    
    public DisplacementCircle(Displacement dis, Pane pane) {
        this.x = dis.x;
        this.y = dis.y;
        setRadius(1.5);
        setFill(Color.BLUE);
        setVisible(dis.valid);
    }
}

class Displacement {

    final static Random rand = new Random();
    final double x, y, u, v;
    final boolean valid;
    
    public Displacement() {
        x = rand.nextDouble() * 1000;
        y = rand.nextDouble() * 600;
        u = rand.nextDouble() * 30;
        v = rand.nextDouble() * 15;
        valid = rand.nextBoolean();
    }
}
public类主扩展应用程序{
private DoubleProperty zoom=新的SimpleDoubleProperty(1.0);
私人int w=800;
私有int h=500;
@凌驾
公众假期开始(阶段){
试一试{
按钮重新加载=新按钮(“重新加载”);
窗格=新窗格();
窗格。setManaged(false);
消费者setX=值->{
double pw=value.doubleValue();
对于(节点:pane.getChildren()){
if(位移线的节点实例){
位移线dl=(位移线)节点;
dl.setStartX(pw*dl.x1/w);
dl.set
class DisplacementLine extends Line {

    private final SimpleDoubleProperty x1, y1, x2, y2;

    public DisplacementLine(Displacement dis, int w, int h, Pane pane) {

        x1 = new SimpleDoubleProperty();     y1 = new SimpleDoubleProperty();
        x2 = new SimpleDoubleProperty();     y2 = new SimpleDoubleProperty();
        setDisplacement(dis);
        startXProperty().bind(pane.prefWidthProperty().multiply(x1).divide(w));
        startYProperty().bind(pane.prefHeightProperty().multiply(y1).divide(h));
        endXProperty().bind(pane.prefWidthProperty().multiply(x2).divide(w));
        endYProperty().bind(pane.prefHeightProperty().multiply(y2).divide(h));
        setStroke(Color.BLUE);
        setVisible(dis.valid);
    }

    public void setDisplacement(Displacement dis) {
        x1.set(dis.x);
        y1.set(dis.y);
        x2.set(dis.x + dis.u);
        y2.set(dis.y + dis.v);
    }
}
public class Main extends Application {
    
    private DoubleProperty zoom = new SimpleDoubleProperty(1.0);
    private int w = 800;
    private int h = 500;

    @Override
    public void start(Stage stage) {
        try {
            Button reload = new Button("reload");
            Pane pane = new Pane();
            pane.setManaged(false);
            
            Consumer<Number> setX = value -> {
                double pw = value.doubleValue();
                for (Node node : pane.getChildren()) {
                    if (node instanceof DisplacementLine) {
                        DisplacementLine dl = (DisplacementLine) node;
                        dl.setStartX(pw * dl.x1 / w);
                        dl.setEndX(pw * dl.x2 / w);
                    }
                    if (node instanceof DisplacementCircle) {
                        DisplacementCircle dc = (DisplacementCircle) node;
                        dc.setCenterX(pw * dc.x / w);
                    }
                }
            };
            Consumer<Number> setY = value -> {
                double ph = value.doubleValue();
                for (Node node : pane.getChildren()) {
                    if (node instanceof DisplacementLine) {
                        DisplacementLine dl = (DisplacementLine) node;
                        dl.setStartY(ph * dl.y1 / h);
                        dl.setEndY(ph * dl.y2 / h);
                    }
                    if (node instanceof DisplacementCircle) {
                        DisplacementCircle dc = (DisplacementCircle) node;
                        dc.setCenterY(ph * dc.y / h);
                    }
                }
            };
            pane.prefWidthProperty().addListener((obs, oldval, newval) -> setX.accept(newval));
            pane.prefHeightProperty().addListener((obs, oldval, newval) -> setY.accept(newval));
            
            reload.setOnAction(event -> {
                pane.getChildren().clear();
                List<Displacement> disList = Stream.generate(Displacement::new).limit(1200).collect(Collectors.toList());;
                disList.forEach(dis -> pane.getChildren().add(new DisplacementLine(dis, pane)));
                disList.forEach(dis -> pane.getChildren().add(new DisplacementCircle(dis, pane)));
                setX.accept(pane.getPrefWidth());
                setY.accept(pane.getPrefHeight());
            });
            
            VBox vbox = new VBox(reload, pane);
            Pane root = new Pane();
            Scene scene = new Scene(root);
            root.getChildren().add(vbox);
            stage.setScene(scene);
            stage.setWidth(1000);
            stage.setHeight(600);
            stage.show();
            
            pane.prefWidthProperty().bind(zoom.multiply(w));
            pane.prefHeightProperty().bind(zoom.multiply(h));
            pane.layoutXProperty().bind(root.widthProperty().subtract(pane.prefWidthProperty()).divide(2.0));
            pane.layoutYProperty().bind(root.heightProperty().subtract(pane.prefHeightProperty()).divide(2.0));
            
            pane.setOnScroll(scrollEvent -> {
                double delta = 0.1;
                double f = scrollEvent.getDeltaY() > 0 ? 1+delta : 1/(1+delta);
                zoom.set(zoom.get() * f);
            });
            
            reload.fire();
            
        } catch(Exception e) {
            e.printStackTrace();
        }
    }

    
    public static void main(String[] args) {
        launch(args);
    }
}

class DisplacementLine extends Line {

    final double x1, y1, x2, y2;
    
    public DisplacementLine(Displacement dis, Pane pane) {
        x1 = dis.x;
        y1 = dis.y;
        x2 = dis.x + dis.u;
        y2 = dis.y + dis.v;
        setStroke(Color.BLUE);
        setVisible(dis.valid);
    }
}

class DisplacementCircle extends Circle {

    final double x, y;
    
    public DisplacementCircle(Displacement dis, Pane pane) {
        this.x = dis.x;
        this.y = dis.y;
        setRadius(1.5);
        setFill(Color.BLUE);
        setVisible(dis.valid);
    }
}

class Displacement {

    final static Random rand = new Random();
    final double x, y, u, v;
    final boolean valid;
    
    public Displacement() {
        x = rand.nextDouble() * 1000;
        y = rand.nextDouble() * 600;
        u = rand.nextDouble() * 30;
        v = rand.nextDouble() * 15;
        valid = rand.nextBoolean();
    }
}