簡體   English   中英

JavaFX 自定義圖表類 - 如何將節點的 layoutX 和 layoutY 屬性綁定到 NumberAxis 的顯示位置?

[英]JavaFX custom chart class - how to bind a node's layoutX and layoutY properties to the display positions of a NumberAxis?

我正在編寫一個基本的燭台圖表類,其中燭台被創建為Regions ,並通過將它們的layoutXlayoutY值設置為相關軸的getDisplayPosition()來繪制。

例如,要在 X 軸上繪制值為 3 的燭台,我這樣做:

candlestick.setLayoutX(xAxis.getDisplayPosition(3));

當舞台調整大小或軸放大或縮小時,必須重置燭台的布局值,以便圖表正確呈現。 我目前正在通過ChangeListener s 處理調整大小事件和Button.setOnAction() s 進行縮放。

但是,我寧願將燭台的布局屬性綁定到軸的顯示位置,而不是設置/重置布局值,但找不到NumberAxis的“displayPositionProperty”(或類似的)。

是否有可能做到這一點? 我將綁定到哪個NumberAxis屬性? IE。

candlestick.layoutXProperty().bind(xAxis.WHICH_PROPERTY?);

另外,綁定屬性會比重置布局位置更有效嗎? 有些圖表可能有數千個燭台,但在我弄清楚如何對綁定進行編碼之前,我無法測試資源使用情況。

我已經嘗試將燭台縮放到軸的比例,但不能使用這種方法,因為縮放Region會影響其邊框寬度。 對於某些類型的燭台,這可能會改變其含義。

我還使用了 Ensemble 燭台演示圖表。 它對我的開始很有用,但對於我的需求來說太簡單了。

這是一個 MVCE,它展示了我的方法。 任何重新綁定的指導將不勝感激。

我正在使用 OpenJFX 17。

package test023;

import javafx.application.Application;
import javafx.application.Platform;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.chart.NumberAxis;
import javafx.scene.control.Button;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.layout.Region;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class Test023 extends Application {

    @Override
    public void start(Stage stage) {    

        NumberAxis xAxis = new NumberAxis(0D, 10D, 1D);
        Pane pChart = new Pane();
        Pane pAxis = new Pane();
        VBox vb = new VBox();
        BorderPane bp = new BorderPane();

        pChart.setPrefHeight(100D);
        pAxis.getChildren().add(xAxis);
        xAxis.prefWidthProperty().bind(pAxis.widthProperty());
        xAxis.setAnimated(false);

        vb.setPadding(new Insets(10D));
        vb.getChildren().addAll(pChart, pAxis);

        Region point = new Region();
        point.setPrefSize(5D, 5D);
        point.setStyle("-fx-background-color: black;");

        pChart.getChildren().add(point);

        //Plot the point in its initial position (value 3 on the axis)
        double pointXValue = 3D;
        plotPoint(point, pointXValue, xAxis);

        //*****************************************************************
        //Can the listeners and button.setOnActions be replaced by binding
        //the point's layout value to the axis display position?
        //*****************************************************************

        //Handle resize events
        pChart.widthProperty().addListener((obs, oldVal, newVal) -> {
            plotPoint(point, pointXValue, xAxis);
        });

        stage.maximizedProperty().addListener((obs, oldVal, newVal) -> {
            plotPoint(point, pointXValue, xAxis);
        });        

        //Handle zooming (hard-coded upper and lower bounds for the 
        //sake of simplicity)
        Button btnZoomIn = new Button("Zoom in");
        btnZoomIn.setOnAction((event) -> {
            xAxis.setLowerBound(2D);
            xAxis.setUpperBound(8D);
            xAxis.layout();
            plotPoint(point, pointXValue, xAxis);
        });

        Button btnZoomOut = new Button("Zoom out");
        btnZoomOut.setOnAction((event) -> {
            xAxis.setLowerBound(0D);
            xAxis.setUpperBound(10D);
            xAxis.layout();
            plotPoint(point, pointXValue, xAxis);
        });

        bp.setCenter(vb);
        bp.setTop(new HBox(btnZoomIn, btnZoomOut));

        stage.setScene(new Scene(bp));
        stage.setTitle("Test bind layoutX");
        stage.setWidth(400D);
        stage.setHeight(200D);
        stage.show();

    }

    private void plotPoint(Region region, double axisPos, NumberAxis axis) {

        Platform.runLater(() -> {
            double posX = axis.getDisplayPosition(axisPos);
            region.setLayoutX(posX);
            region.setLayoutY(80D);
        });

    }

    public static void main(String args[]){
       launch(args);
    }

}

像這樣的東西會起作用

@Override
public void start(Stage stage) {    

    NumberAxis xAxis = new NumberAxis(0D, 10D, 1D);
    Pane pChart = new Pane();
    Pane pAxis = new Pane();
    VBox vb = new VBox();
    BorderPane bp = new BorderPane();

    pChart.setPrefHeight(100D);
    pAxis.getChildren().add(xAxis);
    xAxis.prefWidthProperty().bind(pAxis.widthProperty());
    xAxis.setAnimated(false);

    vb.setPadding(new Insets(10D));
    vb.getChildren().addAll(pChart, pAxis);

    Region point = new Region();
    point.setPrefSize(5D, 5D);
    point.setStyle("-fx-background-color: black;");

    pChart.getChildren().add(point);

    //Plot the point in its initial position (value 3 on the axis)
    double pointXValue = 3D;

    point.setLayoutY(80D);
    
    point.layoutXProperty().bind(Bindings.createDoubleBinding(()-> {
        return xAxis.getDisplayPosition(pointXValue);
    }, xAxis.lowerBoundProperty(), xAxis.upperBoundProperty(), pChart.widthProperty()));
        
    //Handle zooming (hard-coded upper and lower bounds for the 
    //sake of simplicity)
    Button btnZoomIn = new Button("Zoom in");
    btnZoomIn.setOnAction((event) -> {
        xAxis.setLowerBound(2D);
        xAxis.setUpperBound(8D);
        xAxis.layout();
    });

    Button btnZoomOut = new Button("Zoom out");
    btnZoomOut.setOnAction((event) -> {
        xAxis.setLowerBound(0D);
        xAxis.setUpperBound(10D);
        xAxis.layout();
    });

    bp.setCenter(vb);
    bp.setTop(new HBox(btnZoomIn, btnZoomOut));

    stage.setScene(new Scene(bp));
    stage.setTitle("Test bind layoutX");
    stage.setWidth(400D);
    stage.setHeight(200D);
    stage.show();

}

這將創建一個定制的雙用計算的每一個依賴關系發生變化時綁定,請參閱值的函數結合createDoubleBinding獲取更多信息。

+1 @LukasOwen 答案實際上是您與綁定相關的實際問題。

但正如您所知,每個問題都有不止一種方法,我建議我考慮可擴展性(添加很多點)和太多綁定(對於每個點)。

這種方法的關鍵是:

  • 您將所有點數及其節點添加到地圖中。
  • 每次渲染 xAxis 時,都會更新所有點的位置。 因此,如果您調整大小、更改范圍或最大化窗口,這將隱式完成。

以下是該方法的示例:

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.chart.NumberAxis;
import javafx.scene.control.Button;
import javafx.scene.layout.*;
import javafx.stage.Stage;
import java.util.HashMap;
import java.util.Map;

public class Test023 extends Application {

    Map<Double, Region> plotPoints = new HashMap<>();
    double yOffset = 80D;
    Pane pChart;

    @Override
    public void start(Stage stage) {
        NumberAxis xAxis = new NumberAxis(0D, 10D, 1D);
        xAxis.needsLayoutProperty().addListener((obs, old, needsLayout) -> {
            if(!needsLayout) {
                plotPoints.forEach((num, point) -> {
                    double posX = xAxis.getDisplayPosition(num);
                    point.setLayoutX(posX);
                    point.setLayoutY(yOffset);
                });
            }
        });
        pChart = new Pane();
        Pane pAxis = new Pane();
        VBox vb = new VBox();
        BorderPane root = new BorderPane();

        pChart.setPrefHeight(100D);
        pAxis.getChildren().add(xAxis);
        xAxis.prefWidthProperty().bind(pAxis.widthProperty());
        xAxis.setAnimated(false);

        vb.setPadding(new Insets(10D));
        vb.getChildren().addAll(pChart, pAxis);

        addPoint(3D, "black");
        addPoint(4D, "red");
        addPoint(5D, "blue");

        //Handle zooming (hard-coded upper and lower bounds for the sake of simplicity)
        Button btnZoomIn = new Button("Zoom in");
        btnZoomIn.setOnAction((event) -> {
            xAxis.setLowerBound(2D);
            xAxis.setUpperBound(8D);
        });

        Button btnZoomOut = new Button("Zoom out");
        btnZoomOut.setOnAction((event) -> {
            xAxis.setLowerBound(0D);
            xAxis.setUpperBound(10D);
        });

        root.setCenter(vb);
        root.setTop(new HBox(btnZoomIn, btnZoomOut));

        stage.setScene(new Scene(root));
        stage.setTitle("Test bind layoutX");
        stage.setWidth(400D);
        stage.setHeight(200D);
        stage.show();
    }

    private void addPoint(double num, String color) {
        Region point = new Region();
        point.setPrefSize(5D, 5D);
        point.setStyle("-fx-background-color: " + color);
        plotPoints.put(num, point);
        pChart.getChildren().add(point);
    }

    public static void main(String args[]) {
        launch(args);
    }
}

在此處輸入圖片說明

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM