簡體   English   中英

JavaFX中的象限散點圖?

[英]Quadrant Scatter Chart in JavaFX?

感謝您閱讀我的問題。

我目前正在使用JavaFX-8,SceneBuilder和Eclipse。

我想用四個象限制作一個散點圖,它有兩個固定的數字軸(數據位置無關緊要,我只需要在每個象限上顯示點...只關系點在哪個象限中)。 每個象限必須具有特定顏色的背景。

我找到了這個問題 ,因此我嘗試擴展ScatterChart,以覆蓋方法layoutPlotChildren() 我嘗試了一個最小的實現,看它是否可以與我的FXML一起運行(我確實將新組件導入到FXML中)。 這是我的最低要求:

public class ScatterQuadrantChart<X,Y> extends ScatterChart<X,Y> {
  public ScatterQuadrantChart(Axis<X> xAxis, Axis<Y> yAxis) {
      super(xAxis, yAxis);
} }

然后,我收到NotSuchMethodError初始化錯誤。 我發現了一個類似的錯誤,但是有人從這里擴展了LineChart,但是我不太確定自己需要在自己的課上做什么。

我嘗試添加一個無參數的構造函數,但是我需要調用super和cant,因為我也不能調用“ getXAxis()”方法。 我該怎么辦?

另外,剩下的另一個問題是,一旦我解決了這個問題, layoutPlotChildren()方法應該做什么?

謝謝閱讀。

之所以出現此問題,是因為FXMLLoader實例化類的默認機制是調用無參數構造函數。 您的ScatterQuadrantChart沒有無參數構造函數,因此沒有NoSuchMethodError

在Java 8之前,解決此問題的唯一方法是為您的類創建一個構建器類,如您所鏈接的文章中所述。 JavaFX 8引入了一種機制(但未提供文檔),該機制使用@NamedArg批注為FXMLLoader識別的構造函數參數指定值。

因此,在Java 8中,您可以修改ScatterQuadrantChart

public class ScatterQuadrantChart<X,Y> extends ScatterChart<X,Y> {
  public ScatterQuadrantChart(@NamedArg("xAxis")Axis<X> xAxis, 
         @NamedArg("yAxis)Axis<Y> yAxis) {
      super(xAxis, yAxis);
  } 
}

然后您的FXML看起來像

<ScatterQuadrantChart>
    <xAxis>
        <NumberAxis ... />
    </xAxis>
    <yAxis>
        <NumberAxis ... />
    </yAxis>
</ScatterQuadrantChart>

我不知道SceneBuilder是否或如何與之交互,但是FXML將起作用。

對於實現,您將需要向圖中添加一些節點以表示您的象限。 我可能只將這些用於普通區域。 在構造函數中創建它們,然后調用getPlotChildren().add(...)添加它們。 然后在layoutPlotChildren()方法中,首先調用超類方法(它將對散布圖節點進行布局),然后調整象限的大小和位置。 您可以使用getXAxis().getDisplayPosition(...)從實際除法器值中找出位置。

在現實生活中,應將樣式類添加到象限中,以便可以使用CSS等外部樣式,但是一個非常基本的實現可能看起來像

import javafx.beans.NamedArg;
import javafx.beans.property.Property;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ChangeListener;
import javafx.scene.chart.Axis;
import javafx.scene.chart.ScatterChart;
import javafx.scene.layout.Region;

public class ScatterQuadrantChart<X,Y> extends ScatterChart<X,Y> {

    private final Property<X> xQuadrantDivider = new SimpleObjectProperty<>();
    private final Property<Y> yQuadrantDivider = new SimpleObjectProperty<>();

    private final Region nwQuad ;
    private final Region neQuad ;
    private final Region swQuad ;
    private final Region seQuad ;

    public ScatterQuadrantChart(@NamedArg("xAxis") Axis<X> xAxis, 
            @NamedArg("yAxis") Axis<Y> yAxis) {
        super(xAxis, yAxis);
        nwQuad = new Region();
        neQuad = new Region();
        swQuad = new Region();
        seQuad = new Region();
        nwQuad.setStyle("-fx-background-color: lightsalmon ;");
        neQuad.setStyle("-fx-background-color: antiquewhite ;");
        swQuad.setStyle("-fx-background-color: aqua ;");
        seQuad.setStyle("-fx-background-color: lightskyblue ;");
        getPlotChildren().addAll(nwQuad, neQuad, swQuad, seQuad);

        ChangeListener<Object> quadListener = (obs, oldValue, newValue) -> layoutPlotChildren();
        xQuadrantDivider.addListener(quadListener);
        yQuadrantDivider.addListener(quadListener);
    }

    @Override
    public void layoutPlotChildren() {
        super.layoutPlotChildren();
        X x = xQuadrantDivider.getValue();
        Y y = yQuadrantDivider.getValue();
        if (x != null && y != null) {
            Axis<X> xAxis = getXAxis();
            Axis<Y> yAxis = getYAxis();
            double xPixels = xAxis.getDisplayPosition(x);
            double yPixels = yAxis.getDisplayPosition(y);
            double totalWidth = xAxis.getWidth();
            double totalHeight = yAxis.getHeight();
            nwQuad.resizeRelocate(0, 0, xPixels, yPixels);
            swQuad.resizeRelocate(0, yPixels, xPixels, totalHeight - yPixels);
            neQuad.resizeRelocate(xPixels, 0, totalWidth - xPixels, yPixels);
            seQuad.resizeRelocate(xPixels, yPixels, totalWidth - xPixels, totalHeight - yPixels);
        }
    }

    public final Property<X> xQuadrantDividerProperty() {
        return this.xQuadrantDivider;
    }

    public final X getXQuadrantDivider() {
        return this.xQuadrantDividerProperty().getValue();
    }

    public final void setXQuadrantDivider(final X xQuadrantDivider) {
        this.xQuadrantDividerProperty().setValue(xQuadrantDivider);
    }

    public final Property<Y> yQuadrantDividerProperty() {
        return this.yQuadrantDivider;
    }

    public final Y getYQuadrantDivider() {
        return this.yQuadrantDividerProperty().getValue();
    }

    public final void setYQuadrantDivider(final Y yQuadrantDivider) {
        this.yQuadrantDividerProperty().setValue(yQuadrantDivider);
    }


}

測試代碼:

import java.util.Random;
import java.util.stream.Stream;

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart.Data;
import javafx.scene.chart.XYChart.Series;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;

public class ScatterQuadrantChartTest extends Application {

    @Override
    public void start(Stage primaryStage) {

        final Random rng = new Random();

        ScatterQuadrantChart<Number, Number> chart = new ScatterQuadrantChart<>(new NumberAxis(), new NumberAxis());
        Series<Number, Number> series = new Series<>();
        for (int i=0; i<20; i++) {
            series.getData().add(new Data<>(rng.nextDouble() * 100, rng.nextDouble() * 100));
        }
        chart.getData().add(series);

        chart.setXQuadrantDivider(50);
        chart.setYQuadrantDivider(50);

        BorderPane root = new BorderPane(chart);
        Scene scene = new Scene(root, 600, 600);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

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

}

暫無
暫無

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

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