我正在使用 JavaFX 构建 StackedBarChart。图表将随着新数据的进入而改变。我正在使用更新图表的按钮对此进行模拟。
它大部分工作正常,但我注意到当我第一次更新图表时,对于较低的值(值小于 ~100),Y 轴标签似乎有点偏离:
更奇怪的是,如果我第二次(或第三次、第四次...)更新图表,Y 轴的自动缩放功能就会关闭:
如果我使用较大的值(值 > ~1000),那么自动缩放工作正常。如果我停用图表动画,那么自动缩放就可以正常工作。自动缩放在我第一次更新图表时工作正常,但之后就不行了。
这是我使用的代码,与 this 中的代码几乎相同JavaFX 教程。
import java.util.Arrays;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.chart.CategoryAxis;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.StackedBarChart;
import javafx.scene.chart.XYChart;
import javafx.scene.control.Button;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class StackedBarChartSample extends Application {
final CategoryAxis xAxis = new CategoryAxis();
final NumberAxis yAxis = new NumberAxis();
final StackedBarChart<String, Number> sbc = new StackedBarChart<String, Number>(xAxis, yAxis);
@Override
public void start(Stage stage) {
stage.setTitle("Bar Chart Sample");
sbc.setAnimated(true); //change this to false and autoscaling works!
Button button = new Button("update");
button.setOnAction(new EventHandler<ActionEvent>(){
@Override
public void handle(ActionEvent arg0) {
updateChart();
}
});
VBox contentPane = new VBox();
contentPane.getChildren().addAll(sbc, button);
Scene scene = new Scene(contentPane, 800, 600);
stage.setScene(scene);
stage.show();
}
private void updateChart(){
int m = 1; //change this to 100 and autoscaling works!
xAxis.setCategories(FXCollections.<String>observableArrayList());
sbc.getData().clear();
final XYChart.Series<String, Number> series1 = new XYChart.Series<String, Number>();
final XYChart.Series<String, Number> series2 = new XYChart.Series<String, Number>();
series1.setName("ABC");
series1.getData().add(new XYChart.Data<String, Number>("one", 25*m));
series1.getData().add(new XYChart.Data<String, Number>("two", 20*m));
series1.getData().add(new XYChart.Data<String, Number>("three", 10*m));
series2.setName("XYZ");
series2.getData().add(new XYChart.Data<String, Number>("one", 25*m));
series2.getData().add(new XYChart.Data<String, Number>("two", 20*m));
series2.getData().add(new XYChart.Data<String, Number>("three", 10*m));
xAxis.setCategories(FXCollections.<String>observableArrayList(Arrays.asList("one", "two", "three")));
sbc.getData().addAll(series1, series2);
}
public static void main(String[] args) {
launch(args);
}
}
奖励问题:动画即使有效,也会显示每个堆叠条的 2 个额外部分,这些部分在动画完成时消失。有没有办法在动画期间去掉那些多余的部分?
最佳答案
您正在使用图表、动画和可观察列表的修改方式,这似乎并不意味着要完成。好吧,我最初也是。我遇到过这样的问题,其中包括 ArrayIndexOutOfBounds 异常。简而言之:JavaFX 图表的动画非常破损,或者看起来如此。当您直接修改列表时,它似乎不可靠,因此无法使用。
我不再使用列表的动画或修改,而是在每次更改时设置列表。这两种方法中的任何一种都解决了问题。
通过使用 sbc.setData() 而不是 sbc.getData().clear() 和 sbc.getData().addAll() 来修改示例。这行得通,我。 e.动画还在:
public class StackedBarChartSample extends Application {
final CategoryAxis xAxis = new CategoryAxis();
final NumberAxis yAxis = new NumberAxis();
final StackedBarChart<String, Number> sbc = new StackedBarChart<String, Number>(xAxis, yAxis);
Random rnd = new Random();
@Override
public void start(Stage stage) {
stage.setTitle("Bar Chart Sample");
sbc.setAnimated(true); //change this to false and autoscaling works!
Button button = new Button("update");
button.setOnAction(new EventHandler<ActionEvent>(){
@Override
public void handle(ActionEvent arg0) {
updateChart();
}
});
VBox contentPane = new VBox();
contentPane.getChildren().addAll(sbc, button);
Scene scene = new Scene(contentPane, 800, 600);
stage.setScene(scene);
stage.show();
}
private void updateChart(){
int m = 1; //change this to 100 and autoscaling works!
m = rnd.nextInt(100) + 1; // just some random value to see changes in the chart
System.out.println( "m = " + m);
final XYChart.Series<String, Number> series1 = new XYChart.Series<String, Number>();
final XYChart.Series<String, Number> series2 = new XYChart.Series<String, Number>();
series1.setName("ABC");
series1.getData().add(new XYChart.Data<String, Number>("one", 25*m));
series1.getData().add(new XYChart.Data<String, Number>("two", 20*m));
series1.getData().add(new XYChart.Data<String, Number>("three", 10*m));
series2.setName("XYZ");
series2.getData().add(new XYChart.Data<String, Number>("one", 25*m));
series2.getData().add(new XYChart.Data<String, Number>("two", 20*m));
series2.getData().add(new XYChart.Data<String, Number>("three", 10*m));
sbc.setData( FXCollections.observableArrayList(series1, series2));
}
public static void main(String[] args) {
launch(args);
}
}
我为您的 m 添加了随机性,以便查看条形中的变化。
但真正的问题是您使用图表的方式。您不应该修改列表,而应该修改列表项的数据。然后图表动画按预期工作,条形随数据上升和下降。
带有“创建”(创建新图表列表)和“修改”(修改列表数据,但不创建新列表)按钮的示例:
public class StackedBarChartSample extends Application {
final CategoryAxis xAxis = new CategoryAxis();
final NumberAxis yAxis = new NumberAxis();
final StackedBarChart<String, Number> sbc = new StackedBarChart<String, Number>(xAxis, yAxis);
Random rnd = new Random();
final XYChart.Series<String, Number> series1 = new XYChart.Series<String, Number>();
final XYChart.Series<String, Number> series2 = new XYChart.Series<String, Number>();
@Override
public void start(Stage stage) {
stage.setTitle("Bar Chart Sample");
sbc.setAnimated(true); //change this to false and autoscaling works!
Button createButton = new Button("Create");
createButton.setOnAction(new EventHandler<ActionEvent>(){
@Override
public void handle(ActionEvent arg0) {
createChartData();
}
});
Button modifyButton = new Button("Modify");
modifyButton.setOnAction(new EventHandler<ActionEvent>(){
@Override
public void handle(ActionEvent arg0) {
modifyChartData();
}
});
VBox contentPane = new VBox();
contentPane.getChildren().addAll(sbc, createButton, modifyButton);
Scene scene = new Scene(contentPane, 800, 600);
stage.setScene(scene);
stage.show();
}
private void createChartData(){
int m = 1; //change this to 100 and autoscaling works!
m = rnd.nextInt(100) + 1; // just some random value to see changes in the chart
System.out.println( "m = " + m);
series1.setName("ABC");
series1.getData().add(new XYChart.Data<String, Number>("one", 25*m));
series1.getData().add(new XYChart.Data<String, Number>("two", 20*m));
series1.getData().add(new XYChart.Data<String, Number>("three", 10*m));
series2.setName("XYZ");
series2.getData().add(new XYChart.Data<String, Number>("one", 25*m));
series2.getData().add(new XYChart.Data<String, Number>("two", 20*m));
series2.getData().add(new XYChart.Data<String, Number>("three", 10*m));
sbc.setData( FXCollections.observableArrayList(series1, series2));
}
private void modifyChartData() {
int m = 1; //change this to 100 and autoscaling works!
m = rnd.nextInt(100) + 1; // just some random value to see changes in the chart
System.out.println( "m = " + m);
for( XYChart.Data<String,Number> data: series1.getData()) {
data.setYValue(rnd.nextInt(30) * m);
}
for( XYChart.Data<String,Number> data: series2.getData()) {
data.setYValue(rnd.nextInt(30) * m);
}
}
public static void main(String[] args) {
launch(args);
}
}
关于JavaFX 图表自动缩放错误的低数字,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29124723/