在图表加载期间显示圆形进度条

时间:2015-08-30 16:13:16

标签: javafx javafx-2 javafx-8

我正在使用Barchart和Piechart处理此代码。

import java.sql.Timestamp;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.application.Platform;
import javafx.beans.binding.Bindings;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableObjectValue;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.concurrent.Task;
import javafx.geometry.Bounds;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.chart.BarChart;
import javafx.scene.chart.CategoryAxis;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.PieChart;
import javafx.scene.chart.XYChart;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import javafx.stage.Stage;

public class MainApp extends Application
{

    @Override
    public void start(Stage stage) throws Exception
    {
        Scene scene = new Scene(initGeneralAgentsData(), 800, 800);
        stage.setScene(scene);
        stage.show();
    }

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

    private final StackPane stackPane = new StackPane();
    private List<DownloadTrafficObj> obj = new LinkedList<>();

    public StackPane initGeneralAgentsData() throws Exception
    {
        stackPane.setAlignment(Pos.TOP_RIGHT);
        stackPane.setStyle("-fx-background-color: white;");

        SQLSelect(30);
        stackPane.getChildren().addAll(chartChoose());
        return stackPane;
    }

    private List<DownloadTrafficObj> SQLSelect(int history_value)
    {
        for (int i = 0; i < history_value; i++)
        {
            obj.add(new DownloadTrafficObj(String.valueOf(randomDate()), Long.valueOf(randomNumber())));
        }

        return obj;
    }






    private Timestamp randomDate()
    {
        long offset = Timestamp.valueOf("2012-01-01 00:00:00").getTime();
        long end = Timestamp.valueOf("2013-01-01 00:00:00").getTime();
        long diff = end - offset + 1;
        Timestamp rand = new Timestamp(offset + (long) (Math.random() * diff));

        return rand;
    }

    private int randomNumber()
    {
        Random rand = new Random();
        int n = rand.nextInt(50) + 1;
        return n;
    }

    public StackPane chartChoose()
    {
        final ComboBox comboBox = new ComboBox();
        comboBox.getItems().addAll("Bar Chart", "Pie Chart");

        ComboBox cb = new ComboBox();
        cb.getItems().addAll(10, 20, 30, 60);
        cb.setValue(30);

        final StackPane stack = new StackPane();

        comboBox.getSelectionModel().selectedIndexProperty()
            .addListener((ObservableValue<? extends Number> observable,
                    Number oldValue, Number newValue)
                -> setVisibility(stack, comboBox)
            );

        cb.getSelectionModel().selectedIndexProperty()
            .addListener((ObservableValue<? extends Number> observable,
                    Number oldValue, Number newValue)
                ->
                {
                    SQLSelect((int) cb.getSelectionModel().getSelectedItem());
                    bc.getData().clear();
                    generateBarChartData();
            }
            );

        stack.getChildren().add(generateBarChart());
        stack.getChildren().add(generatePieChart());

        // Placing it after adding rectangle to stack
        // will trigger the changelistener to show default rectangle
        comboBox.setValue("Bar Chart");

        VBox vBox = new VBox();
        vBox.setPadding(new Insets(10, 10, 10, 10));
        vBox.setSpacing(5);

        Label labelon = new Label("Chart type");
        Label label = new Label("Days history");
        HBox hBossx = new HBox(15, labelon, comboBox, label, cb);
        hBossx.setAlignment(Pos.CENTER_RIGHT);



        ProgressIndicator progress = new ProgressIndicator();
        progress.setMaxSize(90, 90);
        Task<ObservableList<DownloadTrafficObj>> task = new Task<ObservableList<DownloadTrafficObj>>()
        {
            @Override
            protected ObservableList<DownloadTrafficObj> call() throws Exception
            {
                for (int i = 0; i < 99; i++)
                {
                    Thread.sleep(20);
                 }
                 return (FXCollections.observableArrayList(obj));
            }
        };

        progress.progressProperty().bind(task.progressProperty());
        task.setOnSucceeded(ev ->
        {

        });
        new Thread(task).start();


        BorderPane bp = new BorderPane();

        bp.centerProperty().bind(
            Bindings
            .when(task.runningProperty())
            .then(progress)
            .otherwise((ObservableObjectValue<ProgressIndicator>) stack));


        vBox.getChildren().addAll(hBossx, bp);

        StackPane root = new StackPane();
        root.getChildren().add(vBox);

        return root;
    }

    public void setVisibility(Pane pane, ComboBox comboBox)
    {
        // Make all children invisible
        pane.getChildren().stream().forEach((node) ->
        {
            node.setVisible(false);
        });
        // make the selected rectangle visible
        int selectedIndex = comboBox.getSelectionModel()
            .selectedIndexProperty().getValue();
        pane.getChildren().get(selectedIndex).setVisible(true);
    }

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

    public BarChart<String, Number> generateBarChart()
    {
        bc.setTitle("Network Download");
        xAxis.setLabel("Groups");
        yAxis.setLabel("Value");

        series1.setName("Network Download");

        generateBarChartData();

        // TO DO... Very quick fix.
        bc.widthProperty().addListener((obs, b, b1) ->
        {
            // Chart Bar column is not automatically resized. We need to wait for next JavaFX releases to fix this.
            Platform.runLater(() -> setMaxBarWidth(bc, xAxis, 40, 10));
        });

        bc.getData().addAll(series1);
        return bc;
    }

    private void generateBarChartData()
    {
        obj.stream().map((get) -> new XYChart.Data(get.getDate(), get.getDownloadTraffic())).map((data) ->
        {
            data.nodeProperty().addListener(new ChangeListener<Node>()
            {
                @Override
                public void changed(ObservableValue<? extends Node> ov, Node oldNode, final Node node)
                {
                    if (node != null)
                    {
                        //setNodeStyle(data);
                        displayLabelForData(data);
                    }
                }
            });
            return data;
        }).forEach((data) ->
        {
            series1.getData().add(data);
        });
    }

    private void setMaxBarWidth(BarChart<String, Number> bc, CategoryAxis xAxis, double maxBarWidth, double minCategoryGap)
    {
        double barWidth = 0;
        do
        {
            double catSpace = xAxis.getCategorySpacing();
            double avilableBarSpace = catSpace - (bc.getCategoryGap() + bc.getBarGap());
            barWidth = (avilableBarSpace / bc.getData().size()) - bc.getBarGap();
            if (barWidth > maxBarWidth)
            {
                avilableBarSpace = (maxBarWidth + bc.getBarGap()) * bc.getData().size();
                bc.setCategoryGap(catSpace - avilableBarSpace - bc.getBarGap());
            }
        }
        while (barWidth > maxBarWidth);

        do
        {
            double catSpace = xAxis.getCategorySpacing();
            double avilableBarSpace = catSpace - (minCategoryGap + bc.getBarGap());
            barWidth = Math.min(maxBarWidth, (avilableBarSpace / bc.getData().size()) - bc.getBarGap());
            avilableBarSpace = (barWidth + bc.getBarGap()) * bc.getData().size();
            bc.setCategoryGap(catSpace - avilableBarSpace - bc.getBarGap());
        }
        while (barWidth < maxBarWidth && bc.getCategoryGap() > minCategoryGap);
    }

    public PieChart generatePieChart()
    {
        ObservableList<PieChart.Data> pieChartData = FXCollections.observableArrayList();

        obj.stream().forEach((activeAgentGroup) ->
        {
            pieChartData.add(new PieChart.Data(activeAgentGroup.getDate(), activeAgentGroup.getDownloadTraffic()));
        });

        final PieChart chart = new PieChart(pieChartData);

        chart.setTitle("Label");

        return chart;
    }

    private void displayLabelForData(XYChart.Data<String, Number> data)
    {
        final Node node = data.getNode();
        final Text dataText = new Text(data.getYValue().toString());
        node.parentProperty().addListener(new ChangeListener<Parent>()
        {
            @Override
            public void changed(ObservableValue<? extends Parent> ov, Parent oldParent, Parent parent)
            {
                Group parentGroup = (Group) parent;
                parentGroup.getChildren().add(dataText);
            }
        });

        node.boundsInParentProperty().addListener(new ChangeListener<Bounds>()
        {
            @Override
            public void changed(ObservableValue<? extends Bounds> ov, Bounds oldBounds, Bounds bounds)
            {
                dataText.setLayoutX(
                    Math.round(
                        bounds.getMinX() + bounds.getWidth() / 2 - dataText.prefWidth(-1) / 2
                    )
                );
                dataText.setLayoutY(
                    Math.round(
                        bounds.getMinY() - dataText.prefHeight(-1) * 0.5
                    )
                );
            }
        });
    }
}

我想在切换图表和加载数据期间添加循环进度条。通常从数据库加载数据需要2-3秒,因此我需要一种方法来显示进度托架,因为图表是堆叠的。 还有什么简单的方法来实现图表的切换?

1 个答案:

答案 0 :(得分:2)

短而甜蜜:

  1. 使用BorderPane作为图表的父容器。
  2. 使用BindingsTask.runningProperty()BorderPane.centerProperty()
  3. 例如:

    myBorderPane.centerProperty().bind(
      Bindings
        .when(myLongTask.runningProperty())
        .then(myProggressIndicator)
        .otherwise(myChart));