Я внес программные c изменения в Java Линейную диаграмму FX, и мне нужен программный c способ заставить перепланировку JavaFX Chart произойти. Этот вопрос задавался / отвечался ранее, но не в моем контексте.
Я попробовал типичные методы, которые были представлены в качестве ответов на этот вопрос (см. Полный, минимальный пример кода ниже со встроенными попытками решения проблемы). Ни одно из типичных решений этой проблемы не работает.
В частности (sp является StackPane):
sp.requestLayout(); // does not work
и
sp.applyCss();
sp.layout(); // does not work
, помещая вышеуказанный код в .runLater()
не работает.
Я знаю, что мои изменения присутствуют в диаграмме, потому что (1) Когда я вручную изменяю размер диаграммы, внезапно появляются мои изменения (2) Когда я использую метод "изменения размера" программно, мой появляются изменения, НО есть другая ошибка (плюс предполагается, что метод «изменить размер» должны использовать только родительские узлы, а не мы, программисты).
Ниже приведен минимальный полный набор кода, который воспроизводит проблему. Когда вы запускаете код, я программно изменяю одну из точек данных на большую, когда отображается диаграмма. Этот размер работает правильно. Когда вы щелкаете правой кнопкой мыши на графике, появляется контекстное меню с одним выбором («Изменить все точки»). Когда вы выбираете эту единственную опцию, мой код изменяет размеры всех точек - НО - ни одна из точек данных не изменяется визуально. Если я вручную изменяю размер диаграммы путем перетаскивания стороны, диаграмма выполняет повторную компоновку, и все размеры узлов данных немедленно визуально изменяются на правильный размер (размер, который я программно установил для них).
Как я могу заставить перепланировку произойти программно, что я могу сделать вручную? Я не хотел бы делать взлом (например, программно установить размер сцены на 1 пиксель меньше, а затем установить его на один пиксель больше).
Примечание: я читал, что попытки сделать requestLayout()
во время разработки макета будут игнорироваться, поэтому возможно что-то подобное происходит. Я думаю, что requestLayout()
внутри runLater()
решит проблему текущего Layout (), но это тоже не сработало.
Обновление: В качестве альтернативы было предложено масштабирование изменение размера StackPane. Это решение может быть полезно для некоторых, но не для меня. Внешний вид и масштабирование символа отличаются от внешнего вида, когда вы меняете размер областей и позволяете «символу» увеличиваться в этом размере.
В завершение это мой первый пост stackoverflow. Поэтому спасибо за все предыдущие примеры, которые я использовал на этом форуме в прошлом, и заранее благодарю за ответ на эту проблему.
import java.util.Random;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.LineChart.SortingPolicy;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart.Data;
import javafx.scene.chart.XYChart.Series;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.MenuItem;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class dummy extends Application {
@Override
public void start(Stage primaryStage) {
Random random = new Random();
final NumberAxis xAxis = new NumberAxis();
final NumberAxis yAxis = new NumberAxis();
xAxis.setLabel("X");
yAxis.setLabel("Y");
final LineChart<Number,Number> lineChart = new LineChart<Number,Number>(xAxis,yAxis);
Series<Number,Number> series = new Series<Number,Number>();
series.setName("Dummy Data");
// Generate data
double x = 0.0;
double y = 0.0;
for (int i = 0; i < 10; i++) {
Data<Number,Number> data = new Data(x += random.nextDouble(), y+=random.nextDouble());
series.getData().add(data);
}
lineChart.getData().add(series);
lineChart.setTitle("Random Data");
lineChart.setAxisSortingPolicy(SortingPolicy.NONE);
Scene scene = new Scene(lineChart,1200,600);
Stage stage = new Stage();
stage.setScene(scene);
stage.show();
// This resizes the first data point directly (this resize is displayed correctly when program is run)
Node node = series.getData().get(0).getNode();
setSize((StackPane)node,20);
// The context menu is invoked by a right click on the line Chart. It will resize the data point based on a context menu pick
// this resize does not work....unless I resize the window manually which causes a refresh/re-layout of the chart).
lineChart.setOnMouseClicked(new EventHandler<MouseEvent>() {
@Override public void handle(MouseEvent mouseEvent) {
if (MouseButton.SECONDARY.equals(mouseEvent.getButton())) {
Scene scene = ((Node)mouseEvent.getSource()).getScene();
ContextMenu menu = createMenu(lineChart);
menu.show(scene.getWindow(), mouseEvent.getScreenX(), mouseEvent.getScreenY());
}
}
});
}
private void setSize(StackPane sp, int size) {
sp.setMinSize(size, size);
sp.setMaxSize(size, size);
sp.setPrefSize(size, size);
}
// this creates a context menu that will allow you to resize all the data point nodes
private ContextMenu createMenu(LineChart<Number,Number> lineChart) {
final ContextMenu contextMenu = new ContextMenu();
final MenuItem resize = new MenuItem("Resize ALL the points");
resize.setOnAction(new EventHandler<ActionEvent>() {
@Override public void handle(ActionEvent event) {
for (Series<Number, Number> series : lineChart.getData()) {
for (Data<Number, Number> data : series.getData()) {
StackPane sp = (StackPane)data.getNode();
setSize (sp, 20);
// The above resizes do not take effect unless/until I manually resize the chart.
// the following two calls do not do anything;
sp.applyCss();
sp.layout();
// The request to layout the node does nothing
sp.requestLayout();
// Doing both of the above as runLaters does nothing
Platform.runLater(()->{sp.applyCss();sp.layout();});
Platform.runLater(()->{sp.requestLayout();});
// Going after the parent does nothing either
Group group = (Group)sp.getParent();
group.applyCss();
group.layout();
group.requestLayout();
// Going after the parent in a run later does nothing
Platform.runLater(()->{
group.applyCss();
group.layout();
group.requestLayout();
});
// note... doing a resize [commented out below] will work-ish.
// The documentation says NOT to use it thought that as it is for internal use only.
// By work-ish, the data points are enlarged BUT they are no longer centered on the data point
// When I resize the stage they get centered again - so this "solves" my original problem but causes a different problem
////////////////////////////////////
// sp.resize(20, 20); // Uncomment this line to see how it mostly works but introduces a new issue
////////////////////////////////////
}
}
}
});
contextMenu.getItems().add(resize);
return contextMenu;
}
public static void main(String[] args) {
Application.launch(args);
}
}