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