我正在使用JavaFX来构建StackedBarChart.随着新数据的出现,图表会发生变化.我正在用一个更新图表的按钮来模拟这个.
它主要工作正常,但我注意到,当值较低(值小于~100)时,Y轴标签在我第一次更新图表时似乎有点偏差:

更奇怪的是,如果我第二次(或第三次,第四次......)更新图表,Y轴的自动缩放是远离的:

如果我使用更大的值(值> ~1000),则自动缩放工作正常.如果我停用图表动画,那么自动缩放工作正常.第一次更新图表时自动缩放工作正常,但之后没有.
这是我正在使用的代码,它与此 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);
}
}
Run Code Online (Sandbox Code Playgroud)
奖励问题:即使动画有效,动画也会显示每个堆叠条形图的2个额外部分,这些部分会在动画完成时消失.有没有办法在动画期间摆脱那些额外的部分?
您正在使用图表,动画和可观察列表的修改,似乎不应该这样做.好吧,我最初也是.我遇到过像这样的问题,其中包括ArrayIndexOutOfBounds Exceptions.简而言之:JavaFX图表的动画非常破碎,或者看起来如此.它似乎不可靠,因此当您直接修改列表时无法使用.
我停止使用动画或修改列表,而是在每次更改时设置列表.这两种方法都解决了这个问题.
使用sbc.setData()而不是sbc.getData().clear()和sbc.getData().addAll()修改示例.这有效,即动画仍在运行:
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);
}
}
Run Code Online (Sandbox Code Playgroud)
我为你的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);
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2784 次 |
| 最近记录: |