top

JavaFX 2 Charts Part 1

分享:

JavaFX UI Controls Part 2 << 前情

在一般的桌面應用程式中,通常使用表格與文字呈現應用程式的資料,如果需要使用圖表呈現圖形化的資料,Java技術開發人員也可以使用一些API來製作圖表,例如JFreeChart。JavaFX 2在設計全新圖形使用者介面的時候,它也看到這種常見的需求了,在「javafx.scene.chart」套件裡面,提供各種常用的圖表API,讓開發人員可以直接使用這些內建的API設計需要的各種圖表。介紹JavaFX 2圖表元件的文章分為三個部份:

  • Part 1:介紹條狀圖(BarChart)和圓餅圖(PieChart)的建立和資料設定
  • Part 2:介紹線條圖(LineChart)和區塊圖(AreaChart)的建立和資料設定
  • Part 3:介紹圖表元件的樣式設定,使用CSS設定圖表元件,讓它呈現完全不同的樣子

JavaFX 2 圖表元件介紹

Java技術終於在JavaFX 2開始內建製作圖表的API,它可以讓開發人員使用這些API製作像這樣的圖表:

javafx_005javafx_002

javafx_001javafx_004

在接下來的文章裡面會介紹這四種基本的圖表,分別是條狀圖(BarChart)、圓餅圖(PieChart)、線條圖(LineChart)和區塊圖(AreaChart)。在開始認識這些圖表元件之前,可以先瞭解一些JavaFX 2圖表元件的特點。

JavaFX 2 Charts API使用「XYChart」類別提供資料給圖表元件使用,「XYChart.Data」用來包裝一個二維資料,使用「xValue」和「yValue」兩個property設定X和Y座標。這種二維的資料可以設定給條狀圖(BarChart)、線條圖(LineChart)和區塊圖。剩下的圓餅圖(PieChart)只有一維的資料,所以使用「PieChart.Data」包裝一個圓餅圖的資料。

線條圖或條狀圖通常會包含一組以上的資料,需要在圖表中加入多組資料的時候,使用「XYChart.Series」類別包裝一組需要的資料。每一個分組都可以設定它的名稱、資料和樣式。

JavaFX 2的CSS也可以套用在圖表元件,可以在CSS裡面控制圖表的外觀、字形、顏色和其它各種設定,讓圖表呈現完全不同的樣式:

javafx_005 javafx_003

條狀圖(BarChart)

在JavaFX應用程式中建立條狀圖表,使用「BarChart」類別建立需要的元件後,使用「XYChart.Series」建立和設定群組資料。在Android的開發人員網站持續統計目前全世界的Android裝置的版本和硬體資訊,提供給Android開發人員一個很好的參考資料,例如裝置的螢幕大小和解析度的統計資料。這裡是官方的網頁:

http://developer.android.com/about/dashboards/index.html

這樣的統計資料就很適合使用條狀圖來呈現,這是建立裝置螢幕統計圖表的程式碼:

public class MyBarChart extends Application {
    final static String ldpi = "ldpi";
    final static String mdpi = "mdpi";
    final static String tvdpi = "tvdpi";
    final static String hdpi = "hdpi";
    final static String xhdpi = "xhdpi";
    final static String xxhdpi = "xxhdpi";

    @Override
    public void start(Stage primaryStage) {
        primaryStage.setTitle("Bar Chart Sample");

        final CategoryAxis xAxis = new CategoryAxis();
        final NumberAxis yAxis = new NumberAxis();
        final BarChart<String, Number> bc =
               new BarChart<String, Number>(xAxis, yAxis);

        bc.setTitle("Screen sizes and Densities");

        xAxis.setLabel("Screen Sizes");
        yAxis.setLabel("Value");

        XYChart.Series seriesSmall = new XYChart.Series();
        seriesSmall.setName("Small");

        seriesSmall.getData().add(new XYChart.Data(ldpi, 9.4));
        seriesSmall.getData().add(new XYChart.Data(mdpi, 0.0));
        seriesSmall.getData().add(new XYChart.Data(tvdpi, 0.0));
        seriesSmall.getData().add(new XYChart.Data(hdpi, 0.0));
        seriesSmall.getData().add(new XYChart.Data(xhdpi, 0.0));
        seriesSmall.getData().add(new XYChart.Data(xxhdpi, 0.0));

        XYChart.Series seriesNormal = new XYChart.Series();
        seriesNormal.setName("Normal");

        seriesNormal.getData().add(new XYChart.Data(ldpi, 0.1));
        seriesNormal.getData().add(new XYChart.Data(mdpi, 15.3));
        seriesNormal.getData().add(new XYChart.Data(tvdpi, 0.0));
        seriesNormal.getData().add(new XYChart.Data(hdpi, 33.5));
        seriesNormal.getData().add(new XYChart.Data(xhdpi, 22.8));
        seriesNormal.getData().add(new XYChart.Data(xxhdpi, 7.7));  

        XYChart.Series seriesLarge = new XYChart.Series();
        seriesLarge.setName("Large");

        seriesLarge.getData().add(new XYChart.Data(ldpi, 0.6));
        seriesLarge.getData().add(new XYChart.Data(mdpi, 3.5));
        seriesLarge.getData().add(new XYChart.Data(tvdpi, 1.2));
        seriesLarge.getData().add(new XYChart.Data(hdpi, 0.5));
        seriesLarge.getData().add(new XYChart.Data(xhdpi, 0.6));
        seriesLarge.getData().add(new XYChart.Data(xxhdpi, 0.0));         

        XYChart.Series seriesXlarge = new XYChart.Series();
        seriesXlarge.setName("Xlarge");

        seriesXlarge.getData().add(new XYChart.Data(ldpi, 0.0));
        seriesXlarge.getData().add(new XYChart.Data(mdpi, 4.4));
        seriesXlarge.getData().add(new XYChart.Data(tvdpi, 0.0));
        seriesXlarge.getData().add(new XYChart.Data(hdpi, 0.3));
        seriesXlarge.getData().add(new XYChart.Data(xhdpi, 0.1));
        seriesXlarge.getData().add(new XYChart.Data(xxhdpi, 0.0));        

        Scene scene = new Scene(bc, 800, 600);
        bc.getData().addAll(seriesSmall, seriesNormal, seriesLarge, seriesXlarge);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

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

這是執行這個程式以後的畫面:

javafx_006

預設的條狀圖是垂直的,如果想要把條狀圖改為水平的樣式,只要調換X和Y座標的資料就可以了。這是把條狀圖從垂直換成水平樣式的程式碼:

...
final NumberAxis xAxis = new NumberAxis();
final CategoryAxis yAxis = new CategoryAxis();
final BarChart bc =
        new BarChart(xAxis, yAxis);
...
xAxis.setLabel("Value");
xAxis.setTickLabelRotation(90);
yAxis.setLabel("Screen Sizes");
...
XYChart.Series seriesSmall = new XYChart.Series();
seriesSmall.setName("Small");

seriesSmall.getData().add(new XYChart.Data(9.4, ldpi));
seriesSmall.getData().add(new XYChart.Data(0.0, mdpi));
seriesSmall.getData().add(new XYChart.Data(0.0, tvdpi));
seriesSmall.getData().add(new XYChart.Data(0.0, hdpi));
seriesSmall.getData().add(new XYChart.Data(0.0, xhdpi));
seriesSmall.getData().add(new XYChart.Data(0.0, xxhdpi));
...
// 其它群組資料都要調換X和Y座標的資料

javafx_007

JavaFX圖表元件預設會使用動畫的方式顯示,你可以加入這段程式碼試試看圖表元件動畫的呈現方式:

Timeline timeLine = new Timeline();
timeLine.getKeyFrames().add(
        new KeyFrame(Duration.millis(500),
        new EventHandler() {
            @Override
            public void handle(ActionEvent actionEvent) {
                for (XYChart.Series series : bc.getData()) {
                    for (XYChart.Data data : series.getData()) {
                        data.setXValue(Math.random() * 120 - 20);
                    }
                }
            }
        }));

timeLine.setCycleCount(Animation.INDEFINITE);
timeLine.setAutoReverse(true);
timeLine.play();

圓餅圖(PieChart)

在JavaFX應用程式中建立圓餅圖表,使用「PieChart」類別建立需要的元件後,使用「PieChart.Data」建立和設定資料。在Android的開發人員網站提供目前所有Android裝置的版本統計資訊。這裡是官方的網頁:

http://developer.android.com/about/dashboards/index.html

跟Android的開發人員網站上一樣,使用圓餅圖來呈現這個統計資料,這是建立版本統計圖表的程式碼:

public class MyPieChart extends Application {
    @Override
    public void start(Stage primaryStage) {
        Scene scene = new Scene(new Group());
        primaryStage.setTitle("Programming Technology");
        primaryStage.setWidth(500);
        primaryStage.setHeight(500);

        ObservableList pieChartData =
                FXCollections.observableArrayList(
                new PieChart.Data("2.2", 2.2),
                new PieChart.Data("2.3.3-2.3.7", 28.5),
                new PieChart.Data("3.2", 0.1),
                new PieChart.Data("4.0.3-4.0.4", 20.6),
                new PieChart.Data("4.1.X",36.57),
                new PieChart.Data("4.2.X", 10.6),
                new PieChart.Data("4.3", 1.5));

        final PieChart chart = new PieChart(pieChartData);
        chart.setTitle("Platform Versions");

        ((Group) scene.getRoot()).getChildren().addAll(chart, caption);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

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

這是執行這個程式以後的畫面:

javafx_008

在這個圓餅圖表的範例程式,可以試著加入與使用者互動的功能,讓圖表元件可以在應用程式中提供更靈活的運用。在這個圓餅圖表元件中加入滑鼠點擊的事件,使用者點擊某一個區塊後,在畫面上顯示這個區塊的統計數字。這是加入的程式碼:

final Label caption = new Label("");
caption.setTextFill(Color.WHITESMOKE);
caption.setStyle("-fx-font: 24 arial;");

for (final PieChart.Data data : chart.getData()) {
    data.getNode().addEventHandler(MouseEvent.MOUSE_PRESSED,
        new EventHandler() {
            @Override
            public void handle(MouseEvent e) {
                caption.setTranslateX(e.getSceneX());
                caption.setTranslateY(e.getSceneY());
                caption.setText(String.valueOf(data.getPieValue()) + "%");
            }
        });
}

執行這個應用程式後,試試看用滑鼠點擊圓餅圖表上的區塊:
javafx_009 javafx_010

下一篇文章會繼續介紹其它兩種圖表元件,線條圖(LineChart)和區塊圖(AreaChart)。

後續 >> JavaFX 2 Charts Part 2

分享:
按讚!加入 CodeData Facebook 粉絲群

留言

留言請先。還沒帳號註冊也可以使用FacebookGoogle+登錄留言

關於作者

張益裕。目前是自由講師與作者,專長是教育訓練課程規劃、教材編製與課程推廣,技術書籍與專欄寫作。涵蓋的領域有OOAD、Java程式設計、JavaFX、Java Embedded、Android與SQL。

熱門論壇文章

熱門技術文章