【问题标题】:JavaFX: How to deserialize dynamically create Area Chart Series?JavaFX:如何反序列化动态创建面积图系列?
【发布时间】:2018-02-04 15:39:13
【问题描述】:

我正在使用面积图中的列表动态添加系列。我想解开这个系列。我需要这个,因为我想将面积图系列数据保存在 db 中。

应用执行时是这样的:

用户可以通过填写文本字段并单击“添加”按钮来添加系列:

我想要的是当用户单击“保存”按钮时,它应该将已添加的系列转换为数据,以便我可以将其存储在数据库中。但是我尝试过的并没有给我准确的数据。根据聊天系列,我想得到这样的输出:

Series 0 Employees: 5
Series 0 Start: 1
Series 0 End: 7
Series 1 Employees: 3
Series 1 Start: 9
Series 1 End: 12

但我明白了:

Series 0 Employees: 5
Series 0 Start: 1
Series 0 End: 5
Series 1 Employees: 3
Series 1 Start: 10
Series 1 End: 5

代码:

import java.net.URL;
import java.util.LinkedList;
import java.util.ResourceBundle;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.chart.AreaChart;
import javafx.scene.chart.XYChart;
import javafx.scene.chart.XYChart.Series;
import javafx.scene.control.TextField;


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

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


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

        //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);
                    entry.setName("XYChart.Series "+seriesContainer.size());               }
           }
        }

        //Button delete functionality
        @FXML
        private void deleteGraph() {

        }

        //Button Undo functionality
        @FXML
        private void undoGraph(){

            }

        //Button Save functionality
        @FXML
        private void saveGraph(){           
                int max = 0;

                for(int i =0; i< seriesContainer.size(); i++){
                    XYChart.Series<Number, Number> test = seriesContainer.get(i);
                        System.out.println("Series "+i+" Employees: "+test.getData().get(i).getYValue().intValue());
                        System.out.println("Series "+i+" Start: "+test.getData().get(i).getXValue().intValue());

                        // find maximal y value
                        int x = test.getData().get(i).getYValue().intValue();
                        if (x > max) {
                            max = x;
                        }
                        System.out.println("Series "+i+" End: "+max);
                }
            }

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

FXML

<?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" onAction="#deleteGraph" prefHeight="31.0" prefWidth="137.0" text="Delete" />
            <Button layoutX="410.0" layoutY="12.0" mnemonicParsing="false" onAction="#undoGraph" prefHeight="31.0" prefWidth="137.0" text="Undo" />
            <Button layoutX="479.0" layoutY="10.0" mnemonicParsing="false" onAction="#saveGraph" prefHeight="31.0" prefWidth="137.0" text="Save" />
         </children>
      </HBox>
   </children>
</VBox>

请有人指导我如何解决这个问题,我需要一些指导如何以 H2 dB 存储这些数据。我在 Spring Boot 中使用 JavaFX。

【问题讨论】:

  • 为什么要标记 javafx2 和 javafx8?
  • 哪个对象需要序列化?我无法通过查看代码来判断。
  • @JoseMartinez 这个XYChart.Series&lt;Number, Number&gt; test = seriesContainer.get(i); 在这个方法中private void saveGraph()
  • 我猜我的答案是seriesContainer。但该解决方案可用于任何对象。

标签: java javafx charts javafx-2 javafx-8


【解决方案1】:

有多种方法可以做到这一点。有些比其他更快。我将向您展示一种简单的方法,但请注意有几种方法。

如果速度不是问题,我喜欢将对象序列化为 base64 文本。这使得移动并以文本形式存储在 DB 中变得非常容易。如果我正在从事一个需要移动大量数据且速度很重要的项目,那么我可能不会采用这种方法。

1) 使用Java序列化将对象序列化为byte[]

protected byte[] convertToBytes(Object object) throws IOException {
    try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutput out = new ObjectOutputStream(bos)) {
        out.writeObject(object);
        return bos.toByteArray();
    }
}

protected Object convertFromBytes(byte[] bytes) throws IOException, ClassNotFoundException {
    try (ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
            ObjectInput in = new ObjectInputStream(bis)) {
        return in.readObject();
    }
}

这些方法可用于转换Java对象,将对象转换为字节[]。

2) 从步骤 1 中获取 byte[] 并使用它来序列化为 base64 文本。这两种方法会把你的seriesContainer变成base64字符串,或者把base64字符串变成seriesContainer

public String toBase64() {
    try {
        return Base64.getEncoder().encodeToString(convertToBytes(seriesContainer));
    } catch (IOException ex) {
        throw new RuntimeException("Got exception while converting to bytes.", ex);
    }
}

public void initializeFromBase64(String b64) {
    byte[] bytes = Base64.getDecoder().decode(b64);
    try {
        this.seriesContainer = (LinkedList<XYChart.Series<Number, Number>>) convertFromBytes(bytes);
    } catch (Exception ex) {
        throw new RuntimeException("Got exception while converting from bytes.", ex);
    }
}

3) 将步骤 2 中的字符串放入数据库,或从数据库中读取。

【讨论】:

    猜你喜欢
    • 2018-02-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多