英文:
JavaFX 14, Stacked Bar chart does not display negative values
问题
import javafx.application.Application;
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.stage.Stage;
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
// Start the JavaFX application
@Override
public void start(Stage stage) {
CategoryAxis xAxis = new CategoryAxis();
NumberAxis yAxis = new NumberAxis();
XYChart.Series<String, Number> series = new XYChart.Series<String, Number>();
series.getData().add(new XYChart.Data<String, Number>(0 + "", 5));
series.getData().add(new XYChart.Data<String, Number>(1 + "", -5));
series.getData().add(new XYChart.Data<String, Number>(2 + "", 3));
series.getData().add(new XYChart.Data<String, Number>(3 + "", -2));
StackedBarChart<String, Number> weightChangeChartBar = new StackedBarChart<String, Number>(xAxis, yAxis);
weightChangeChartBar.getData().addAll(series);
Scene scene = new Scene(weightChangeChartBar, 500, 500);
stage.setScene(scene);
stage.show();
}
}
None of the previous stack overflow questions on this issue are working in JavaFX14 (for me anyway), does anyone know of a solution?
Previous Questions:
- https://stackoverflow.com/questions/58426539/javafx13-stacked-bar-chart-negative-values-not-showing
- https://stackoverflow.com/questions/15410153/javafx-stackedbar-chart-issue
- https://stackoverflow.com/questions/32355323/javafx-stackedbarchart-bug
英文:
Example:
import javafx.application.Application;
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.stage.Stage;
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
// Start the javafx application
@Override
public void start(Stage stage) {
CategoryAxis xAxis = new CategoryAxis();
NumberAxis yAxis = new NumberAxis();
XYChart.Series<String, Number> series = new XYChart.Series<String, Number>();
series.getData().add(new XYChart.Data<String, Number>(0 + "", 5));
series.getData().add(new XYChart.Data<String, Number>(1 + "", -5));
series.getData().add(new XYChart.Data<String, Number>(2 + "", 3));
series.getData().add(new XYChart.Data<String, Number>(3 + "", -2));
StackedBarChart<String, Number> weightChangeChartBar = new StackedBarChart<String, Number>(xAxis, yAxis);
weightChangeChartBar.getData().addAll(series);
Scene scene = new Scene(weightChangeChartBar, 500, 500);
stage.setScene(scene);
stage.show();
}
}
Outcome:
None of the previous stack overflow questions on this issue are working in JavaFX14 (for me anyway), does anyone know of a solution?
Previous Questions:
答案1
得分: 1
**已解决:**
必须覆盖 Bar Charts 行为以解决此错误,必须将系列添加到 Bar Chart,然后才能将数据添加到系列。
package example;
import javafx.application.Application;
import javafx.scene.Node;
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.stage.Stage;
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
// 启动 JavaFX 应用程序
@Override
public void start(Stage stage) {
CategoryAxis xAxis = new CategoryAxis();
NumberAxis yAxis = new NumberAxis();
XYChart.Series<String, Number> series = new XYChart.Series<String, Number>();
// 修改行为以解决错误
StackedBarChart<String, Number> barChart = new StackedBarChart<String, Number>(xAxis, yAxis) {
@Override
protected void dataItemAdded(XYChart.Series<String, Number> series, int itemIndex, XYChart.Data<String, Number> item) {
super.dataItemAdded(series, itemIndex, item);
Node bar = item.getNode();
double barVal = item.getYValue().doubleValue();
if (barVal < 0) {
bar.getStyleClass().add("negative");
}
}
};
// 添加系列
barChart.getData().addAll(series);
// 然后添加数据
series.getData().add(new XYChart.Data<String, Number>(0 + "", 5));
series.getData().add(new XYChart.Data<String, Number>(1 + "", -5));
series.getData().add(new XYChart.Data<String, Number>(2 + "", 3));
series.getData().add(new XYChart.Data<String, Number>(3 + "", -2));
Scene scene = new Scene(barChart, 500, 500);
stage.setScene(scene);
stage.show();
}
}
/* ====== 柱状图 =========================================================== */
/* TODO 对负值柱进行垂直翻转渐变 */
.chart-bar {
-fx-bar-fill: #22bad9;
-fx-background-color: linear-gradient(derive(-fx-bar-fill, -30%), derive(-fx-bar-fill, -40%)),
linear-gradient(derive(-fx-bar-fill, 80%), derive(-fx-bar-fill, 0%)),
linear-gradient(derive(-fx-bar-fill, 30%), derive(-fx-bar-fill, -10%));
-fx-background-insets: 0, 1, 2;
-fx-background-radius: 5 5 0 0, 4 4 0 0, 3 3 0 0;
}
.negative.chart-bar {
-fx-background-color: linear-gradient(to top, derive(-fx-bar-fill, -30%), derive(-fx-bar-fill, -40%)),
linear-gradient(to top, derive(-fx-bar-fill, 80%), derive(-fx-bar-fill, 0%)),
linear-gradient(to top, derive(-fx-bar-fill, 30%), derive(-fx-bar-fill, -10%));
-fx-background-radius: 0 0 5 5, 0 0 4 4, 0 0 3 3;
}
.bar-chart:horizontal .chart-bar, .stacked-bar-chart:horizontal .chart-bar {
-fx-background-color: linear-gradient(to left, derive(-fx-bar-fill, -30%), derive(-fx-bar-fill, -40%)),
linear-gradient(to left, derive(-fx-bar-fill, 80%), derive(-fx-bar-fill, 0%)),
linear-gradient(to left, derive(-fx-bar-fill, 30%), derive(-fx-bar-fill, -10%));
-fx-background-radius: 0 5 5 0, 0 4 4 0, 0 3 3 0;
}
.bar-chart:horizontal .negative.chart-bar, .stacked-bar-chart:horizontal .negative.chart-bar {
-fx-background-color: linear-gradient(to right, derive(-fx-bar-fill, -30%), derive(-fx-bar-fill, -40%)),
linear-gradient(to right, derive(-fx-bar-fill, 80%), derive(-fx-bar-fill, 0%)),
linear-gradient(to right, derive(-fx-bar-fill, 30%), derive(-fx-bar-fill, -10%));
-fx-background-radius: 5 0 0 5, 4 0 0 4, 3 0 0 3;
}
英文:
Solved it:
The Bar Charts behavior must be overridden to solve the bug, the series must be added to the Bar Chart, THEN data can be added to the series.
package example;
import javafx.application.Application;
import javafx.scene.Node;
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.stage.Stage;
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
// Start the javafx application
@Override
public void start(Stage stage) {
CategoryAxis xAxis = new CategoryAxis();
NumberAxis yAxis = new NumberAxis();
XYChart.Series<String, Number> series = new XYChart.Series<String, Number>();
// modify behavior to counter bug
StackedBarChart<String, Number> barChart = new StackedBarChart<String, Number>(xAxis, yAxis) {
@Override
protected void dataItemAdded(XYChart.Series<String,Number> series, int itemIndex, XYChart.Data<String,Number> item) {
super.dataItemAdded(series, itemIndex, item);
Node bar = item.getNode();
double barVal = item.getYValue().doubleValue();
if (barVal < 0) {
bar.getStyleClass().add("negative");
}
}
};
// add series
barChart.getData().addAll(series);
// THEN add data
series.getData().add(new XYChart.Data<String, Number>(0 + "", 5));
series.getData().add(new XYChart.Data<String, Number>(1 + "", -5));
series.getData().add(new XYChart.Data<String, Number>(2 + "", 3));
series.getData().add(new XYChart.Data<String, Number>(3 + "", -2));
Scene scene = new Scene(barChart, 500, 500);
stage.setScene(scene);
stage.show();
}
}
Negative nodes must also have separate CSS from the positive nodes.
/* ====== BAR CHART =========================================================== */
/* TODO flip gradient vertical for negative bars */
.chart-bar {
-fx-bar-fill: #22bad9;
-fx-background-color: linear-gradient(derive(-fx-bar-fill,-30%), derive(-fx-bar-fill,-40%)),
linear-gradient(derive(-fx-bar-fill,80%), derive(-fx-bar-fill, 0%)),
linear-gradient(derive(-fx-bar-fill,30%), derive(-fx-bar-fill,-10%));
-fx-background-insets: 0,1,2;
-fx-background-radius: 5 5 0 0, 4 4 0 0, 3 3 0 0;
}
.negative.chart-bar {
-fx-background-color: linear-gradient(to top, derive(-fx-bar-fill,-30%), derive(-fx-bar-fill,-40%)),
linear-gradient(to top, derive(-fx-bar-fill, 80%), derive(-fx-bar-fill,0%)),
linear-gradient(to top, derive(-fx-bar-fill,30%), derive(-fx-bar-fill,-10%));
-fx-background-radius: 0 0 5 5, 0 0 4 4, 0 0 3 3;
}
.bar-chart:horizontal .chart-bar, .stacked-bar-chart:horizontal .chart-bar {
-fx-background-color: linear-gradient(to left, derive(-fx-bar-fill,-30%), derive(-fx-bar-fill,-40%)),
linear-gradient(to left, derive(-fx-bar-fill,80%), derive(-fx-bar-fill, 0%)),
linear-gradient(to left, derive(-fx-bar-fill,30%), derive(-fx-bar-fill,-10%));
-fx-background-radius: 0 5 5 0, 0 4 4 0, 0 3 3 0;
}
.bar-chart:horizontal .negative.chart-bar, .stacked-bar-chart:horizontal .negative.chart-bar {
-fx-background-color: linear-gradient(to right, derive(-fx-bar-fill,-30%), derive(-fx-bar-fill,-40%)),
linear-gradient(to right, derive(-fx-bar-fill, 80%), derive(-fx-bar-fill, 0%)),
linear-gradient(to right, derive(-fx-bar-fill,30%), derive(-fx-bar-fill,-10%));
-fx-background-radius: 5 0 0 5, 4 0 0 4, 3 0 0 3;
}
答案2
得分: 0
以下是您要翻译的内容:
在 wyit's 回答 中的补丁对我不起作用,但它引导我朝着正确的方向前进;我必须覆盖 StackedBarChart 中的另一个方法。
官方实现(GitHub)使用 bar.getStyleClass().setAll(),这会从条形图中移除 negative CSS 类,导致渲染不正确。
以下 Java 类修补了 StackedBarChart 中有问题的方法。
/**
* 修复 StackedBarChart 无法显示负数。
*/
public class PatchedStackedBarChart<X, Y> extends StackedBarChart<X, Y> {
public PatchedStackedBarChart(@NamedArg("xAxis") Axis<X> xAxis, @NamedArg("yAxis") Axis<Y> yAxis) {
super(xAxis, yAxis);
}
/**
* 覆盖打破图形的方法,补丁以添加丢失的 "negative" CSS 类。
*/
@Override
protected void dataItemAdded(Series<X, Y> series, int itemIndex, Data<X, Y> item) {
super.dataItemAdded(series, itemIndex, item);
Number val = (Number) (item.getYValue() instanceof Number ? item.getYValue() : item.getXValue());
if (val.doubleValue() < 0) {
// 添加丢失的 CSS 类
item.getNode().getStyleClass().add("negative");
}
}
/**
* 覆盖打破图形的方法,补丁以不覆盖样式。
*/
@Override
protected void seriesChanged(ListChangeListener.Change<? extends Series> c) {
for (int i = 0; i < getData().size(); i++) {
List<Data<X, Y>> items = getData().get(i).getData();
for (int j = 0; j < items.size(); j++) {
Node bar = items.get(j).getNode();
// 将 .setAll 更改为 .addAll 以避免覆盖样式
bar.getStyleClass().removeIf(s -> s.matches("chart-bar|(series|data)\\d+"));
bar.getStyleClass().addAll("chart-bar", "series" + i, "data" + j);
}
}
}
}
英文:
The patch in wyit's answer didn't work for me, but it led me in the right direction; I had to override a different method in StackedBarChart.
The official implementation (GitHub) uses bar.getStyleClass().setAll(), which removes the negative CSS class from the bar, resulting in incorrect rendering.
The following Java class patches the problematic method in StackedBarChart.
/**
* Fixes StackedBarChart can't display negative numbers.
*/
public class PatchedStackedBarChart<X, Y> extends StackedBarChart<X, Y> {
public PatchedStackedBarChart(@NamedArg("xAxis") Axis<X> xAxis, @NamedArg("yAxis") Axis<Y> yAxis) {
super(xAxis, yAxis);
}
/**
* Override the method that breaks the graph, patch to add missing "negative" CSS class.
*/
@Override
protected void dataItemAdded(Series<X, Y> series, int itemIndex, Data<X, Y> item) {
super.dataItemAdded(series, itemIndex, item);
Number val = (Number) (item.getYValue() instanceof Number ? item.getYValue() : item.getXValue());
if (val.doubleValue() < 0) {
// add missing CSS class
item.getNode().getStyleClass().add("negative");
}
}
/**
* Override the method that breaks the graph, patch so it doesn't override styles.
*/
@Override
protected void seriesChanged(ListChangeListener.Change<? extends Series> c) {
for (int i = 0; i < getData().size(); i++) {
List<Data<X, Y>> items = getData().get(i).getData();
for (int j = 0; j < items.size(); j++) {
Node bar = items.get(j).getNode();
// change .setAll to .addAll to avoid overriding styles
bar.getStyleClass().removeIf(s -> s.matches("chart-bar|(series|data)\\d+"));
bar.getStyleClass().addAll("chart-bar", "series" + i, "data" + j);
}
}
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。



评论