JavaFX BarChart切换ComboBox选项出现数据异常问题求助
Hey, I see the issue you're facing here! Let's break down what's going wrong and how to fix it.
The core problem is that JavaFX's XYChart.Series and XYChart.Data objects have an ownership relationship—they can't be added to the same chart instance more than once.
When you first add a Series to your testChart, the chart internally tracks references to these series and their data points. When you call testChart.getData().clear(), you're removing the series from the chart's visible data, but you aren't resetting the internal state of the Series objects themselves. These objects still hold references related to their previous association with the chart, so when you add them back again, the chart's internal logic gets confused, leading to the broken data display you're seeing.
In your code, you're storing pre-built XYChart.Series instances in costMap and reusing them every time the combo box selection changes. That's exactly what's triggering this unexpected behavior.
There are two solid approaches to fix this, with the second being the more robust option:
Option 1: Create Copies of Series Before Readding
Instead of reusing the exact same Series objects, you could create deep copies of them each time you switch selections. But this requires extra code to duplicate the series and data points, which can get messy quickly.
Option 2: Store Raw Data Instead of Prebuilt Series
A cleaner approach is to store only the raw numerical data in your map, then create brand-new Series and Data objects every time the combo box selection changes. This completely avoids the reuse issue since you're always adding fresh, unassociated objects to the chart.
Here's the revised TestController code implementing this approach:
import javafx.scene.chart.XYChart; import javafx.scene.control.ComboBox; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Random; public class TestController { @FXML private BarChart<String, Float> testChart; @FXML private ComboBox<String> cmb1; @FXML protected void initialize() { Random random = new Random(); // Store raw values instead of pre-built Series Map<String, List<Float>> costMap = new HashMap<>(); for (int i = 0; i < 10; i++) { List<Float> values = new ArrayList<>(2); values.add(random.nextFloat()); // Value for Cost values.add(random.nextFloat()); // Value for Bill costMap.put(String.valueOf(i), values); } cmb1.getItems().addAll(costMap.keySet()); cmb1.valueProperty().addListener((observable, oldValue, newValue) -> { testChart.getData().clear(); // Create new Series and Data objects every time List<Float> selectedValues = costMap.get(newValue); XYChart.Series<String, Float> costSeries = new XYChart.Series<>(); costSeries.setName("Cost"); costSeries.getData().add(new XYChart.Data<>("Cost", selectedValues.get(0))); XYChart.Series<String, Float> billSeries = new XYChart.Series<>(); billSeries.setName("Bill"); billSeries.getData().add(new XYChart.Data<>("Bill", selectedValues.get(1))); testChart.getData().addAll(costSeries, billSeries); }); } }
Bonus: Fixing Unspecified Generics
I also added explicit generic types to BarChart and ComboBox in the code above. Your original code had raw types, which can lead to compiler warnings and potential type-related bugs—this makes the code more type-safe and readable.
内容的提问来源于stack exchange,提问作者Thusitha Thilina Dayaratne

