JavaFX: How to add serveral series dynimically on

2019-08-21 06:54发布

问题:

I am working with Area Chart of JavaFX. I want to add series dynamically after user will enter values in text fields and press Add button. I also want to add delete and undo functionality in it. Delete functionality working would be like for instance if there are several lines on the Area Chart each line represents series, user can delete any line he want by clicking on that line and after clicking on delete button. I also want to add undo functionality so user can undo his actions.

The interface is like this:

For example user can draw line like this by filling text fields:

Now let say the user want to delete the series which is in red color what I want is user click on it and after click delete button it'll delete the red series like this:

So far I've tried this:

import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.scene.Node;
import javafx.scene.chart.AreaChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.scene.control.TextField;
import javafx.scene.input.MouseEvent;

public class SampleController {


    @FXML
    private NumberAxis xAxis;
    @FXML
    private NumberAxis yAxis;
    @FXML
    private AreaChart<Number, Number> areaChart;
    @FXML
    private TextField txtSt;
    @FXML
    private TextField txtEt;
    @FXML
    private TextField txtNb;


    public void initialize() {

            areaChart.setTitle("Chronos");
            xAxis.setLabel("Heures");
            yAxis.setLabel("Employés");

    }


        //Button add functionality
        @FXML
        private void generateGraph() {

            //double start = Double.parseDouble(txtSt.getText());
            double end = Double.parseDouble(txtEt.getText());
            int numberEmployees = Integer.parseInt(txtNb.getText());

            XYChart.Series<Number, Number> series= new XYChart.Series<>();

            for (double start = Double.parseDouble(txtSt.getText()); start<=end; start++) {
                series.getData().add(new XYChart.Data<Number, Number>(start, numberEmployees));
            }


           // Add Series to AreaChart.
           areaChart.getData().add(series);

           //Mouse click even for series
           setOnMouseEventsOnSeries(series.getNode(), 
                   areaChart, "Series is clicked");
        }


        private void setOnMouseEventsOnSeries(Node node, 
                final AreaChart chart, final String label) {

            node.setOnMouseClicked(new EventHandler<MouseEvent>() {

                @Override
                public void handle(MouseEvent t) {
                   chart.setTitle(label);
                }
            });

        }
}

FXML file:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.chart.AreaChart?>
<?import javafx.scene.chart.NumberAxis?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>

<VBox alignment="CENTER" prefHeight="800.0" prefWidth="800.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.SampleController">
   <children>
      <AreaChart fx:id="areaChart" prefHeight="799.0" prefWidth="800.0" VBox.vgrow="ALWAYS">
         <xAxis>
            <NumberAxis autoRanging="false" minorTickCount="1" minorTickLength="1.0" side="BOTTOM" tickLabelGap="1.0" tickLength="1.0" tickUnit="1.0" upperBound="24.0" fx:id="xAxis" />
         </xAxis>
         <yAxis>
            <NumberAxis fx:id="yAxis" autoRanging="false" minorTickLength="1.0" side="LEFT" tickLabelGap="1.0" tickUnit="1.0" upperBound="10.0" />
         </yAxis>
      </AreaChart>
      <HBox alignment="CENTER" prefHeight="193.0" prefWidth="800.0">
         <children>
            <TextField fx:id="txtSt" promptText="Start Value" />
            <TextField fx:id="txtEt" promptText="End Value" />
            <TextField fx:id="txtNb" promptText="Number of Employees" />
         </children>
      </HBox>
      <HBox alignment="CENTER" prefHeight="71.0" prefWidth="800.0">
         <children>
            <Button mnemonicParsing="false" onAction="#generateGraph" prefHeight="31.0" prefWidth="137.0" text="Add" />
            <Button layoutX="342.0" layoutY="12.0" mnemonicParsing="false" prefHeight="31.0" prefWidth="137.0" text="Delete" />
            <Button layoutX="410.0" layoutY="12.0" mnemonicParsing="false" prefHeight="31.0" prefWidth="137.0" text="Undo" />
         </children>
      </HBox>
   </children>
</VBox>

Please someone guide me how can I achieve these functionalities.

回答1:

This should help you get started. I added an ArrayList to keep up with Series that are added to the Chart. Comments are in the code. You can figure out how to delete/remove items from the ArrayList and/or Chart or how to remove items from the ArrayList then update the Chart.

import java.net.URL;
import java.util.ArrayList;
import java.util.ResourceBundle;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.Node;
import javafx.scene.chart.AreaChart;
import javafx.scene.chart.XYChart;
import javafx.scene.control.TextField;
import javafx.scene.input.MouseEvent;

/**
 *
 * @author blj0011
 */
public class FXMLDocumentController implements Initializable {

//    @FXML
//    private NumberAxis xAxis;
//    @FXML
//    private NumberAxis yAxis;
    @FXML
    private AreaChart<Number, Number> areaChart;
    @FXML
    private TextField txtSt;
    @FXML
    private TextField txtEt;
    @FXML
    private TextField txtNb;


    ArrayList<XYChart.Series<Number, Number>> seriesContainer = new ArrayList();//Use an ArrayList to hold new Series!


        //Button add functionality
        @FXML
        private void generateGraph() {

            Double start = Double.parseDouble(txtSt.getText());

            Double end = Double.parseDouble(txtEt.getText());
            double numberEmployees = Integer.parseInt(txtNb.getText());

            XYChart.Series<Number, Number> series= new XYChart.Series<>();

            for (int i = start.intValue(); i <= end.intValue(); i++) {
                series.getData().add(new XYChart.Data(i, numberEmployees));
            }


           // Add Series to series container.
           seriesContainer.add(series);

           //Add only new series to AreaChart
           for(XYChart.Series<Number, Number> entry : seriesContainer)
           {
               if(!areaChart.getData().contains(entry))
               {                    
                    areaChart.getData().add(entry);
               }
           }
        }

        private void setOnMouseEventsOnSeries(Node node, 
                final AreaChart chart, final String label) {

            node.setOnMouseClicked(new EventHandler<MouseEvent>() {

                @Override
                public void handle(MouseEvent t) {
                   chart.setTitle(label);
                }
            });

        }

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        areaChart.setTitle("Chronos");
        areaChart.getXAxis().setLabel("Heures");
        areaChart.getYAxis().setLabel("Employés");
    }
}