JavaFX 图表自动缩放错误的低数字
JavaFX Chart Auto-Scaling Wrong with Low Numbers
我正在使用 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 个额外部分,这些部分在动画完成时消失。有没有办法在动画过程中去掉那些多余的部分?
问题源于两件事。
- 在 'same time' 添加和删除数据(在任何动画开始之前)
- y 轴自动缩放以适合动画数据
通过同时删除旧数据 sbc.getData().clear()
和添加新数据 sbc.getData().addAll(series1, series2);
可以使两组动画同时启动。
我修改了您的代码(在 post 末尾),将更新功能分为清除功能和更新功能,并为它们添加了各种按钮。
- 清除
- 更新
- 清除并更新
- 清除并稍后更新
- 清除(无动画)和更新
运行程序并排两次,一个值小,一个值大。
如果您点击更新,您会看到两者的数据下降。
如果您清除该数据,您会看到删除动画,但会注意到 y 轴刻度。两个数据集都是一样的。即使您使用数百万的值,它也保持不变。
现在,如果您正在执行清除和更新,则 yAxis 将适合较大的动画值。
使用小值旧数据占主导地位,因为它在动画期间增长并保持大于新数据。
对于大值,新数据占主导地位,因为它大于旧数据的最终终点。
然后在删除动画结束时,旧数据被清除,但 y 轴保持不变,在小值的情况下看起来完全 FUBARd。
我个人认为这是 JavaFX 的一个错误。几乎感觉动画以 y 在 650 处开始和停止。我这样说是因为当添加具有小值的数据时,条形图似乎下降到位但具有大值时它们似乎长大到位。我不能肯定地说,因为我没有做过代码潜水。
我想到的第一个解决方案是在所有动画完成后让y轴再次自动缩放。但是,我认为目前没有一种方法可以在图表完成动画时得到通知。这可能是错误的,但我认为这并不重要。条形图会缩放到非常小的尺寸,然后再次变大。最终结果很好,但用户体验奇怪且延迟。
编辑:正如罗兰在下面评论的那样,下一段中的方法有点代码味。我把它留在这里是因为它有效但不要使用它。要么使用我最后的建议,要么使用 Roland 在他的回答中提供的方式。
解决方法是不要同时启动两个动画。最后一个运行动画需要是添加数据的动画。这可以在 Clear & Update Later 按钮的代码中看到。
然而,这对我来说仍然看起来有点奇怪。
我认为我在视觉上更喜欢的方式也解决了奖金问题;不要动画数据删除。如果您在之前将其关闭并在之后重新启用它,您将获得很好的新数据动画,而旧数据就会消失。
使用清除(无动画)和更新按钮查看。
import java.util.Arrays;
import java.util.Timer;
import java.util.TimerTask;
import javafx.application.Application;
import javafx.application.Platform;
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(final Stage stage)
{
stage.setTitle("Bar Chart Sample");
sbc.setAnimated(true);
final Button updateButton = new Button("update");
updateButton.setOnAction(new EventHandler<ActionEvent>()
{
@Override
public void handle(final ActionEvent arg0)
{
updateChart();
}
});
final Button clearButton = new Button("Clear");
clearButton.setOnAction(new EventHandler<ActionEvent>()
{
@Override
public void handle(final ActionEvent arg0)
{
clearChart(true);
}
});
final Button clearAndUpdateButton = new Button("Clear & Update");
clearAndUpdateButton.setOnAction(new EventHandler<ActionEvent>()
{
@Override
public void handle(final ActionEvent evt)
{
clearChart(true);
updateChart();
}
});
final Button clearAndUpdateLaterButton = new Button("Clear & Update Later");
clearAndUpdateLaterButton.setOnAction(new EventHandler<ActionEvent>()
{
@Override
public void handle(final ActionEvent evt)
{
clearChart(true);
new Timer(true).schedule(new TimerTask()
{
@Override
public void run()
{
Platform.runLater(() -> updateChart());
}
}, 1000);
}
});
final Button clearNoAnimAndUpdateButton = new Button("Clear (no anim) & Update");
clearNoAnimAndUpdateButton.setOnAction(new EventHandler<ActionEvent>()
{
@Override
public void handle(final ActionEvent evt)
{
clearChart(false);
updateChart();
}
});
final VBox contentPane = new VBox();
contentPane.getChildren().addAll(sbc, clearButton, updateButton, clearAndUpdateButton, clearAndUpdateLaterButton,
clearNoAnimAndUpdateButton);
final Scene scene = new Scene(contentPane, 800, 600);
stage.setScene(scene);
stage.show();
xAxis.setCategories(FXCollections.<String> observableArrayList(Arrays.asList("one", "two", "three")));
}
private void clearChart(final boolean animate)
{
System.out.println("Clear");
final boolean wasAnimated = sbc.getAnimated();
if (!animate) {
sbc.setAnimated(false);
}
sbc.getData().clear();
if (!animate) {
sbc.setAnimated(wasAnimated);
}
}
private void updateChart()
{
System.out.println("Update");
final int m = 1; // change this to 100 and autoscaling works!
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.getData().addAll(series1, series2);
}
public static void main(final String[] args)
{
launch(args);
}
}
您正在使用图表、动画和可观察列表的修改方式,这似乎并不意味着要完成。好吧,我最初也是。我 运行 遇到过这样的问题,其中包括 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 添加了随机性,以便查看条形中的变化。
但真正的问题是您使用图表的方式。您不应该修改列表,而应该修改列表项的数据。然后图表动画按预期工作,条形随数据上升和下降。
带有 "create"(创建新图表列表)和 "modify"(修改列表数据,但不创建新列表)按钮的示例:
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 构建 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 个额外部分,这些部分在动画完成时消失。有没有办法在动画过程中去掉那些多余的部分?
问题源于两件事。
- 在 'same time' 添加和删除数据(在任何动画开始之前)
- y 轴自动缩放以适合动画数据
通过同时删除旧数据 sbc.getData().clear()
和添加新数据 sbc.getData().addAll(series1, series2);
可以使两组动画同时启动。
我修改了您的代码(在 post 末尾),将更新功能分为清除功能和更新功能,并为它们添加了各种按钮。
- 清除
- 更新
- 清除并更新
- 清除并稍后更新
- 清除(无动画)和更新
运行程序并排两次,一个值小,一个值大。
如果您点击更新,您会看到两者的数据下降。 如果您清除该数据,您会看到删除动画,但会注意到 y 轴刻度。两个数据集都是一样的。即使您使用数百万的值,它也保持不变。
现在,如果您正在执行清除和更新,则 yAxis 将适合较大的动画值。 使用小值旧数据占主导地位,因为它在动画期间增长并保持大于新数据。 对于大值,新数据占主导地位,因为它大于旧数据的最终终点。
然后在删除动画结束时,旧数据被清除,但 y 轴保持不变,在小值的情况下看起来完全 FUBARd。
我个人认为这是 JavaFX 的一个错误。几乎感觉动画以 y 在 650 处开始和停止。我这样说是因为当添加具有小值的数据时,条形图似乎下降到位但具有大值时它们似乎长大到位。我不能肯定地说,因为我没有做过代码潜水。
我想到的第一个解决方案是在所有动画完成后让y轴再次自动缩放。但是,我认为目前没有一种方法可以在图表完成动画时得到通知。这可能是错误的,但我认为这并不重要。条形图会缩放到非常小的尺寸,然后再次变大。最终结果很好,但用户体验奇怪且延迟。
编辑:正如罗兰在下面评论的那样,下一段中的方法有点代码味。我把它留在这里是因为它有效但不要使用它。要么使用我最后的建议,要么使用 Roland 在他的回答中提供的方式。
解决方法是不要同时启动两个动画。最后一个运行动画需要是添加数据的动画。这可以在 Clear & Update Later 按钮的代码中看到。 然而,这对我来说仍然看起来有点奇怪。
我认为我在视觉上更喜欢的方式也解决了奖金问题;不要动画数据删除。如果您在之前将其关闭并在之后重新启用它,您将获得很好的新数据动画,而旧数据就会消失。 使用清除(无动画)和更新按钮查看。
import java.util.Arrays;
import java.util.Timer;
import java.util.TimerTask;
import javafx.application.Application;
import javafx.application.Platform;
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(final Stage stage)
{
stage.setTitle("Bar Chart Sample");
sbc.setAnimated(true);
final Button updateButton = new Button("update");
updateButton.setOnAction(new EventHandler<ActionEvent>()
{
@Override
public void handle(final ActionEvent arg0)
{
updateChart();
}
});
final Button clearButton = new Button("Clear");
clearButton.setOnAction(new EventHandler<ActionEvent>()
{
@Override
public void handle(final ActionEvent arg0)
{
clearChart(true);
}
});
final Button clearAndUpdateButton = new Button("Clear & Update");
clearAndUpdateButton.setOnAction(new EventHandler<ActionEvent>()
{
@Override
public void handle(final ActionEvent evt)
{
clearChart(true);
updateChart();
}
});
final Button clearAndUpdateLaterButton = new Button("Clear & Update Later");
clearAndUpdateLaterButton.setOnAction(new EventHandler<ActionEvent>()
{
@Override
public void handle(final ActionEvent evt)
{
clearChart(true);
new Timer(true).schedule(new TimerTask()
{
@Override
public void run()
{
Platform.runLater(() -> updateChart());
}
}, 1000);
}
});
final Button clearNoAnimAndUpdateButton = new Button("Clear (no anim) & Update");
clearNoAnimAndUpdateButton.setOnAction(new EventHandler<ActionEvent>()
{
@Override
public void handle(final ActionEvent evt)
{
clearChart(false);
updateChart();
}
});
final VBox contentPane = new VBox();
contentPane.getChildren().addAll(sbc, clearButton, updateButton, clearAndUpdateButton, clearAndUpdateLaterButton,
clearNoAnimAndUpdateButton);
final Scene scene = new Scene(contentPane, 800, 600);
stage.setScene(scene);
stage.show();
xAxis.setCategories(FXCollections.<String> observableArrayList(Arrays.asList("one", "two", "three")));
}
private void clearChart(final boolean animate)
{
System.out.println("Clear");
final boolean wasAnimated = sbc.getAnimated();
if (!animate) {
sbc.setAnimated(false);
}
sbc.getData().clear();
if (!animate) {
sbc.setAnimated(wasAnimated);
}
}
private void updateChart()
{
System.out.println("Update");
final int m = 1; // change this to 100 and autoscaling works!
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.getData().addAll(series1, series2);
}
public static void main(final String[] args)
{
launch(args);
}
}
您正在使用图表、动画和可观察列表的修改方式,这似乎并不意味着要完成。好吧,我最初也是。我 运行 遇到过这样的问题,其中包括 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 添加了随机性,以便查看条形中的变化。
但真正的问题是您使用图表的方式。您不应该修改列表,而应该修改列表项的数据。然后图表动画按预期工作,条形随数据上升和下降。
带有 "create"(创建新图表列表)和 "modify"(修改列表数据,但不创建新列表)按钮的示例:
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);
}
}