为什么点击按钮时 3D 对象的位置没有改变?

问题描述 投票:0回答:1

我是一名学生,正在研究过程的物理建模。我是 GUI 新手。我有两个进程。第一个过程将球随机散布到圆柱体的表面上。这是它的代码

public class Generation {
    private static final Color[] COLORS = new Color[] { RED, YELLOW, GREEN, BROWN, BLUE, PINK, BLACK };
    private final Tube tube;
    private final int numberOfParticle;
    private final double radius;
    public Generation(Tube tube, int numberOfParticle) {
        this.tube = tube;
        this.numberOfParticle = numberOfParticle;
        radius = Math.sqrt(tube.getRadius()*tube.getHeight()/(2*numberOfParticle));
    }
    private Particle RandomParticle (Color color) {
        double phi = 2*Math.PI*Math.random();
        double z = GetRandomNumberUsingNextDouble(-tube.getHeight()/2,tube.getHeight()/2);
        Particle particle = new Particle(phi,tube.getRadius(),z,radius,color);
        return particle;
    }
    private static double GetRandomNumberUsingNextDouble(double min, double max){
        Random r = new Random();
        return min + (max - min) * r.nextDouble();
    }
    public ObservableList<Particle> ParticlesGeneration() {
        ObservableList<Particle> particlesList = FXCollections.observableArrayList()
        for (int i = 0; i < numberOfParticle; i++) {
            Particle particle = RandomParticle(COLORS[i % COLORS.length]);
            particlesList.add(particle);
        }
        return particlesList;
    }
}

粒子类

public class Particle {
   private final double radius;
   private double phi, rho, z;
   private final Sphere particle;
   public Particle(double phi, double rho, double z, double radius, Color color) {
       this.particle = new Sphere(radius);
       this.radius = radius;
       this.phi = phi;
       this.rho = rho;
       this.z = z;
       particle.setMaterial(new PhongMaterial(color));
       particle.setTranslateX(rho * Math.cos(phi));
       particle.setTranslateY(z);
       particle.setTranslateZ(rho * Math.sin(phi));
   }
   private static double distance(double x1, double y1, double x2, double y2) {
       x2 -= x1;
       y2 -= y1;
       return Math.sqrt(x2 * x2 + y2 * y2);
   }
   public double distance(Particle p) { return distance(getPhi()*getRho(), getZ(), p.getPhi()*p.getRho(),p.getZ());}
   public double getRadius() { return radius; }
    public double getPhi() { return phi; }
    public void setPhi(double phi) { this.phi = phi; }
    public double getRho() { return rho; }
    public void setRho(double rho) { this.rho = rho; }
    public double getZ() { return z; }
    public void setZ(double z) { this.z = z; }
    public Sphere getParticle() { return particle; }
}

气缸类

public class Tube {
    private double radius, height;
    private final Cylinder tube;
    private final Color color;
    public Tube(double radius, double height, Color color) {
        this.height = height;
        this.color = color;
        this.radius = radius;
        this.tube = new Cylinder(radius,height);
        tube.setMaterial(new PhongMaterial(color));
    }
    public Color getColor() { return color; }
    public double getRadius() { return radius; }
    public double getHeight() { return height; }
    public Cylinder getTube() { return tube; }
    public void setRadius(double radius) { this.radius = radius; }
    public void setHeight(double height) { this.height = height; }
}

第二个过程是创建随机分散颗粒的致密堆积

public class Minimization {
    private double COEFFICIENT_FOR_ANGLE = 1;
    private double COEFFICIENT_FOR_Z = 1;
    @SuppressWarnings("FieldCanBeLocal")
    private final double ACCEPTABLE_COEFFICIENT_VALUE_K_ANGEL = 0.0001;
    @SuppressWarnings("FieldCanBeLocal")
    private final double ACCEPTABLE_COEFFICIENT_VALUE_K_Z = 0.0001;
    @SuppressWarnings("FieldCanBeLocal")
    private final double ACCEPTABLE_VALUE_OF_ENERGY_DIFFERENCE = 0.0001;
    @SuppressWarnings("FieldCanBeLocal")
    public static final double MAX_VALUE = 1.7976931348623157E308;
    private final ObservableList<Particle> poissonDiskCoordinatesParticles;
    private final int numberOfParticle, degree;
    private final double heightTube;
    public Minimization(ObservableList<Particle> poissonDiskCoordinatesParticles, int degree, Tube tube) {
        this.poissonDiskCoordinatesParticles = poissonDiskCoordinatesParticles;
        this.degree = degree;
        numberOfParticle = poissonDiskCoordinatesParticles.size();
        heightTube = tube.getHeight();
    }
    public ObservableList<Particle> minimization () {
        ObservableList<Particle> list = poissonDiskCoordinatesParticles;
        double energyOld = MAX_VALUE;
        double energyNew = energyOfSystem(list);
        while (COEFFICIENT_FOR_ANGLE > ACCEPTABLE_COEFFICIENT_VALUE_K_ANGEL && COEFFICIENT_FOR_Z > ACCEPTABLE_COEFFICIENT_VALUE_K_Z && energyOld > energyNew) {
            if (energyOld - energyNew < ACCEPTABLE_VALUE_OF_ENERGY_DIFFERENCE) {
                COEFFICIENT_FOR_Z = COEFFICIENT_FOR_Z/2;
                COEFFICIENT_FOR_ANGLE = COEFFICIENT_FOR_ANGLE/2;
            }
            energyOld = energyNew;
            stepOfMinimization(list);
            energyNew = energyOfSystem(list);
        }
        return list;
    }
    private void stepOfMinimization (ObservableList<Particle> list) {
        for (int i = 0; i < numberOfParticle; i++) {
            Particle particle = newParticle(list, i);
            if (energyOfSystem(list) < energyOfSystem(list,particle,i)) {
                list.set(i, particle);
            }
        }
    }
    private Particle newParticle(ObservableList<Particle> coordinates, int i) {
        Particle particle = coordinates.get(i);
        double ForcePhi = 0.0;
        double ForceZ = 0.0;
        for (int j = 0; j < numberOfParticle; j++) {
            Particle jParticle = coordinates.get(j);
            if (i != j) {
                ForcePhi += (numberOfParticle * particle.getRho() *
                        (particle.getPhi() - jParticle.getPhi())) / pow(particle.distance(jParticle), degree + 2);
                ForceZ += (numberOfParticle *
                        (particle.getZ() - jParticle.getZ())) / pow(particle.distance(jParticle), degree + 2);
            }
        }
        ForceZ += degree / pow(particle.getZ() - heightTube / 2, degree + 1) + degree / pow(particle.getZ() + heightTube / 2, degree + 1);
        particle.setPhi(particle.getPhi() + COEFFICIENT_FOR_ANGLE * ForcePhi);
        particle.setZ(particle.getZ() + COEFFICIENT_FOR_Z * ForceZ);
        return particle;
    }
    private double energyOfSystem (ObservableList<Particle> coordinates) {
        double Energy = 0;
        for (int i = 0; i < numberOfParticle; i++) {
            for (int j = 0; j < numberOfParticle; j++) {
                if (i != j) {
                    Energy += 1/pow(coordinates.get(i).distance(coordinates.get(j)),degree);
                }
            }
            Energy += degree / pow(coordinates.get(i).getZ() - heightTube / 2, degree) +                    degree / pow(coordinates.get(i).getZ() + heightTube / 2, degree);
        }
        return Energy;
    }
    private double energyOfSystem (ObservableList<Particle> coordinates, Particle particle, int i) {
        coordinates.set(i,particle);
        return energyOfSystem(coordinates);
    }
}

类绘图粒子

public class Mapping {
    private final ObservableList<Particle> list;
    private final int numberOfParticle;
    private final Group group;
    private final Tube tube;
    public Mapping(int numberOfParticle, Group group, Tube tube, ObservableList<Particle> list) {
        this.numberOfParticle = numberOfParticle;
        this.group = group;
        this.list = list;
        this.tube = tube;
    }
    public void MappingParticle() {
        group.getChildren().clear();
        group.getChildren().add(tube.getTube());
        for (int i = 0; i < numberOfParticle; i++) {
            group.getChildren().add(list.get(i).getParticle());
        }
    }
}

最后是界面

public class NanoTube extends Application {
    private double anchorX, anchorY;
    @SuppressWarnings("FieldCanBeLocal")
    private final int WIDTH = 800;
    @SuppressWarnings("FieldCanBeLocal")
    private final int HEIGHT = 670;
    private final int RADIUS = 100;
    private final Rotate rotateX = new Rotate(0, Rotate.X_AXIS);
    private final Rotate rotateY = new Rotate(0, Rotate.Y_AXIS);
    @Override
    public void start(Stage stage) {
        var buttonEnter = new Button("Enter");
        var buttonEnergyMinimization = new Button("Minimization");
        var buttonEnergyMinimizationStress = new Button("Minimization Stress");
        var labelRadius = new Label("Cylinder's radius");
        var labelHeight = new Label("Cylinder's height");
        var labelNumber = new Label("Number Particle");
        var textFieldRadius = new TextField();
        var textFieldHeight = new TextField();
        var textNumber = new TextField();
        GridPane Top = new GridPane();
        for (int i : new int[]{120, 100, 70, 90, 60, 140, 150, 65}) {
            Top.getColumnConstraints().add(new ColumnConstraints(i));
        }
        for (int i = 0; i < 3; i++) {
            Top.getRowConstraints().add(new RowConstraints(30));
        }
        Top.getRowConstraints().add(new RowConstraints(560));

        Arrays.asList(labelRadius, labelHeight, labelNumber).forEach(label -> {
            GridPane.setHalignment(label, HPos.CENTER);
            GridPane.setValignment(label, VPos.CENTER);
        });
        Arrays.asList(buttonEnter, buttonEnergyMinimization).forEach(button -> {
            GridPane.setHalignment(button, HPos.CENTER);
            GridPane.setValignment(button, VPos.CENTER);
        });
        Top.add(labelRadius, 0, 0);
        Top.add(labelHeight, 0, 1);
        Top.add(labelNumber, 0, 2);
        Top.add(textFieldRadius, 1, 0);
        Top.add(textFieldHeight, 1, 1);
        Top.add(textNumber, 1, 2);
        Top.add(buttonEnter,2,0,1,3);
        Top.add(buttonEnergyMinimization,3,0,1,3);
        PerspectiveCamera camera = new PerspectiveCamera(true);
        camera.setNearClip(0.1);
        camera.setFarClip(10000.0);
        camera.setFieldOfView(20);
        camera.getTransforms().addAll (rotateX, rotateY, new Translate(0, 0, -500));
        Tube tube = new Tube(80,80,Color.rgb(225,225,0));
        Group group = new Group(tube.getTube());
        SubScene subScene = new SubScene(group, 750, 550, true, SceneAntialiasing.BALANCED);
        subScene.setFill (Color.rgb (129, 129, 129));
        subScene.setCamera(camera);
        var root3d = new Group(subScene);
        initMouseControl(subScene);
        Top.add(root3d,0,3,8,1);
        GridPane.setHalignment(root3d, HPos.CENTER);
        GridPane.setValignment(root3d, VPos.CENTER);
        buttonEnter.setOnAction(e -> {
            int n = Integer.parseInt(textNumber.getText());
            tube.setHeight(Double.parseDouble(textFieldHeight.getText()));
            tube.setRadius(Double.parseDouble(textFieldRadius.getText()));
            ObservableList<Particle> particles = new Generation(tube, n).ParticlesGeneration();
            new Mapping(n,group,tube,particles).MappingParticle();
            buttonEnergyMinimization.setOnAction(actionEvent -> {
                ObservableList<Particle> list = new Minimization(particles,2,tube).minimization();
                new Mapping(n,group,tube,list).MappingParticle();
            });
        });
        var scene = new Scene(Top, WIDTH,HEIGHT);
        stage.setScene(scene);
        stage.show();
        stage.setTitle("NanoTube Student Project");
    }
    public static void main(String[] args) {launch();}
    private void initMouseControl(SubScene scene) {
        scene.setOnMousePressed(event -> {
            anchorX = event.getSceneX();
            anchorY = event.getSceneY();
        });
        scene.setOnMouseDragged(event -> {
            double dx = (anchorX - event.getSceneX());
            double dy = (anchorY - event.getSceneY());
            if (event.isPrimaryButtonDown()) {
                rotateX.setAngle(rotateX.getAngle() -
                        (dy /RADIUS  * 360) * (Math.PI / 180));
                rotateY.setAngle(rotateY.getAngle() -
                        (dx /RADIUS * -360) * (Math.PI / 180));
            }
            anchorX = event.getSceneX();
            anchorY = event.getSceneY();
        });
    }
}

如果单击“Enter”按钮,则会绘制粒子,但如果单击“最小化”按钮,图像不会改变。我不明白为什么会这样。

有人建议我尽可能简短地写一个非工作区域的示例。但是这些例子可以工作,但我的程序却不能。我不明白为什么第二个按钮在使用“最小化”类时会忽略绘制粒子。最后,单独来看一切都工作正常。 我使用 javafx 但不使用 fxml。如果您有时间帮助我,我将不胜感激。

java button javafx observablelist
1个回答
0
投票

代码中的任何内容都不会更新 UI。

您的

Tube
类包含对 UI 对象的引用(
Cylinder
)。当您创建
Tube
实例时,您可以根据
Cylinder
height
radius
设置
Tube
的高度和半径。

但是,如果您稍后通过

Tube
setHeight(...)
方法更改
setRadius(...)
的高度或半径,则不会更新
Cylinder
的属性。所以用户界面永远不会改变。

您需要:

public class Tube {

    private final Cylinder tube;

    // ...


    public void setRadius(double radius) {
        this.radius = radius;
        tube.setRadius(radius);
    }
    public void setHeight(double height) {
        this.height = height;
        tube.setHeight(height);
    }

}

Particle
类类似,如果
Particle
的属性发生更改,则需要更新UI对象(
Sphere
)的属性:

public class Particle {

    private final Sphere particle;

    // ...

    public void setPhi(double phi) {
        this.phi = phi;
        particle.setTranslateX(rho * Math.cos(phi));
        particle.setTranslateZ(rho * Math.sin(phi));
    }

    public void setRho(double rho) {
        this.rho = rho;
        particle.setTranslateX(rho * Math.cos(phi));
        particle.setTranslateZ(rho * Math.sin(phi));
    }

    public void setZ(double z) {
        this.z = z;
        particle.setTranslateY(z);
    }

}

(两个类中都省略了未更改的代码。)


更“JavaFX”的方法是将数据类与数据视图分开,并使用 JavaFX 属性来保持所有内容同步。为了让您对此有一个简单的了解,

Tube
的实现看起来像这样:

public class Tube {

    private final DoubleProperty height = new SimpleDoubleProperty();

    public DoubleProperty heightProperty() {
        return height ;
    }

    public final double getHeight() {
        return heightProperty().get();
    }

    public final void setHeight(double height) {
        heightProperty().set(height);
    }

    private final DoubleProperty radius = new SimpleDoubleProperty();

    public DoubleProperty radiusProperty() {
        return radius;
    }

    public final double getRadius() {
        return radiusProperty().get();
    }

    public final void setRadius(double radius) {
        radiusProperty().set(radius);
    }

    public Tube(double radius, double height) {
        setRadius(radius);
        setHeight(height);
    }
}
public class TubeView {

    private final Tube tube ;
    private final Cylinder view ;
    private Color color;

    public TubeView(Tube tube, Color color) {
        this.tube = tube;
        this.view = new Cylinder();
        this.color = color;
        view.setMaterial(new PhongMaterial(color));
        view.heightProperty().bind(tube.heightProperty());
        view.radiusProperty().bind(tube.radiusProperty());
    }

    public Node asNode() {
        return view;
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.