Java FX Pie Chart - Change order of data - java

I implemented a small chart with a button to rotate the slice inside the chart, in order to do this, I implemented the following steps:
Copy the actual data of the chart into a new ObservableList "ActualData"
Create a new ObservableList "NewList" empty
Add to NewList the last value of ActualData, and then add the remaing values ( ind: 0,1,2,3 )
Clear the data of the chart
Enter using a loop all the data of the new list "NewList"
My questions are:
Is there a better way to implement such action?
Is a way to delete the ugly spaces between each slice?
Thanks
package application;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.geometry.Side;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.chart.PieChart;
import javafx.scene.chart.PieChart.Data;
import javafx.scene.control.Button;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
PieChart pieChart = new PieChart();
int counter = 0;
EnterValues(pieChart);
pieChart.setLegendVisible(false);
pieChart.setClockwise(true);
pieChart.setStartAngle(90);
StackPane.setAlignment(pieChart, Pos.TOP_CENTER);
Button button = new Button("Change Values");
StackPane.setAlignment(button, Pos.BOTTOM_CENTER);
StackPane stackPane = new StackPane();
stackPane.setPrefSize(500, 500);
stackPane.getChildren().add(pieChart);
stackPane.getChildren().add(button);
Scene scene = new Scene(stackPane);
primaryStage.setTitle("Test");
primaryStage.setMinHeight(500);
primaryStage.setMinWidth(500);
primaryStage.setScene(scene);
primaryStage.show();
button.setOnAction((EventHandler<ActionEvent>) new EventHandler<ActionEvent>() {
#Override public void handle(ActionEvent e) {
// GET DATA FROM CURRENT LIST
ObservableList<Data> ActualData = pieChart.getData();
// CREATE NEW EMPTY LIST
ObservableList<Data> NewList = FXCollections.observableArrayList();;
// ADD ITEMS TO NEW LIST ( LAST BECOMES THE FIRST ONE )
NewList.add(ActualData.get(4));
NewList.add(ActualData.get(0));
NewList.add(ActualData.get(1));
NewList.add(ActualData.get(2));
NewList.add(ActualData.get(3));
// CLEAR DATA FROM CURRENT CHART
pieChart.getData().clear();
// ENTER NEW DATA TO CHART
for(int i = 0;i<NewList.size();i++)
{
PieChart.Data slice = new PieChart.Data(NewList.get(i).getName(),NewList.get(i).getPieValue());
pieChart.getData().add(slice);
}
}
});
}
public void EnterValues(PieChart chart) {
PieChart.Data slice1 = new PieChart.Data("USA", 30);
PieChart.Data slice2 = new PieChart.Data("EU", 20);
PieChart.Data slice3 = new PieChart.Data("China", 100);
PieChart.Data slice4 = new PieChart.Data("Japan", 50);
PieChart.Data slice5 = new PieChart.Data("Others", 10);
chart.getData().add(slice1);
chart.getData().add(slice2);
chart.getData().add(slice3);
chart.getData().add(slice4);
chart.getData().add(slice5);
}
public static void main(String[] args) {
Application.launch(args);
}
}

In theory, you should just be able to rotate the pie chart data. However, because the chart API has the Node that represents the data as a part of the data class (which represents a major design flaw in my opinion, and renders the Chart API as not suitable for production code), this results in a "duplicate children added" error.
So it seems the only way around this is to create a deep copy of the data, and rotate that list, which is essentially what you do. Note there's no real need to create an ObservableList for the data copy; a plain old List (which has less overhead) will do. So your code can be reduced a little:
button.setOnAction(e -> {
List<Data> dataCopy = new ArrayList<>();
for (Data d : pieChart.getData())
dataCopy.add(new Data(d.getName(), d.getPieValue()));
Collections.rotate(dataCopy, 1);
pieChart.getData().setAll(dataCopy);
});

Related

How do you Save a ListView as a text document than loading it back into the program

I am currently making a program where you can add and delete items from a listview in Java, i want it to be able to automatically save when you add items to the list view and delete items. I am having a hard time figuring out how to do this any help would be greatly appreciated. i am still very new at programming and still trying to figure it all out here is my code i have so far.
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import javafx.application.*;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ListView;
import javafx.scene.control.TextField;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
import javafx.stage.Stage;
public class LendingLibraryGUI extends Application {
LendingLibrary LendingLibrary = new LendingLibrary(); //Creating an Object to access total numbers of items
MediaItems Media = new MediaItems(); // creating an array of object to access MediaItems class and allowing it to hold 100 items
private ListView<String> library = new ListView<String>();
ObservableList<String> libraryList = FXCollections.<String>observableArrayList("yes","no");
#Override
public void start(Stage primaryStage) throws Exception {
BorderPane display = new BorderPane(); //Main display
GridPane buttons = new GridPane(); //location to display buttons
TextField outPut = new TextField(); //Text field to show inventory
Insets padding = new Insets(10); //creates Insets for padding
buttons.setPadding(padding); //padding around grid pane
buttons.setHgap(10); //Horizontal gap
library.setItems(libraryList);
for (int i =0; i !=4;i++) { //Loop to create Buttons
String[] actionButtons = {"Add","Check Out","Check In","Delete"};//String to store Button names
Button temp = new Button(actionButtons[i]);
temp.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
buttons.add(temp, i, 0); //add buttons to grid pane
GridPane.setHgrow(temp, Priority.ALWAYS);
GridPane.setVgrow(temp, Priority.ALWAYS);
if (temp.getText().equals("Add")) {
temp.setOnAction((e) -> add());
}
else if (temp.getText().equals("Delete")) {
temp.setOnAction((e) -> deleteLibrary());
}
}
outPut.setEditable(false); //no editing
outPut.setFont(Font.font("monospace", FontWeight.BOLD, 20));
outPut.setMinHeight(300);//sets minimum height
display.setTop(library); //sets output in display on top
display.setCenter(buttons); //sets buttons on center
Scene scene = new Scene(display); //creates new scene
primaryStage.setTitle("Lending Library"); //sets title of GUI
primaryStage.setScene(scene); //adds scene to GUI
primaryStage.setMinHeight(400); //Minimum height
primaryStage.setMinWidth(350);//Minimum Width
primaryStage.show();//Displays GUI to user
}
public static void main(String[] args) {
launch(args);
}
private void add() {
inputGUI("Title:");
}
private void inputGUI(String input) {
Stage secondaryStage = new Stage();
BorderPane border = new BorderPane();
VBox titlePane = new VBox(8);
HBox buttonLayout = new HBox(8);
Label lblTitle = new Label(input);
Button save = new Button("Save");
Button close = new Button("Close");
Insets padding = new Insets(10);
TextField txt = new TextField("");
close.setOnAction((e) -> secondaryStage.close());;
save.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent e) {
try {
LendingLibrary.save(library);
} catch (IOException e1) {
e1.printStackTrace();
}
if (txt.getText().trim().isEmpty()) {
}
else {
if (input.equals("Title:")) {
Media.setTitle(txt.getText());
secondaryStage.close();
inputGUI("Format:");
}
else if (input.equals("Format:")) {
Media.setFormat(txt.getText());
secondaryStage.close();
addToLibrary();
}
else if (input.equals("Who did you loan this to?")) {
}
else if (input.equals("When did you loan it(date)?")) {
}
}
}
});
buttonLayout.getChildren().addAll(close,save);
titlePane.setPadding(padding);
titlePane.getChildren().addAll(lblTitle,txt,buttonLayout);
border.setCenter(titlePane);
BorderPane.setAlignment(titlePane, Pos.CENTER);
Scene scene = new Scene(border); //creates new scene
secondaryStage.setTitle("Input"); //sets title of GUI
secondaryStage.setScene(scene); //adds scene to GUI
secondaryStage.setMinHeight(200); //Minimum height
secondaryStage.setMinWidth(350);//Minimum Width
secondaryStage.show();//Displays GUI to user
}
private void addToLibrary() {
String total;
total = Media.getTitle();
total = total + " ("+ Media.getFormat() +")";
libraryList.add(total);
library.setItems(libraryList);
}
private void deleteLibrary() {
int selectedItem = library.getSelectionModel().getSelectedIndex();
libraryList.remove(selectedItem);
}
private void checkOut() {
}
}
Any other pointers or advice would be greatly appreciated!
Thanks in advance
edit:
Again im very new just trying to learn basic stuff this isnt something i am going to keep just going through a book and this is something in it that its trying to teach me.
public void save(ListView<String> library) throws IOException {
File file = new File ("LendingLibrary.txt"); //creates text file
PrintWriter output = new PrintWriter(file);
if(file.exists()) { //if the file exists
output.println(library);
output.close();
}
if(!file.exists()) { //if file doesn't exist
System.out.println("Error creating file");
}
}
What you really are interested to save is the data that is presented by the list view, you don't need all the other layout information and stuff as they are statically defined in the application and loaded on each run automatically.
Now, although saving the data in a file and loading it each time you need it can work, it is not usually the best. A better approach is to use a database to store the data of your application in form of relation entities, in this way you have a safer and a more consistent approach to work with. To get yourself started in the topic, you can go on and consult the official reference.
If you want to first try using the file approach, the advice is to save the data in some structured format which is then easy to save and load, or in more proper words serialize/deserialize. For this purpose you can use the json format to store the data in a file, and you can use gson library for example:
Each row of the list view is an object that contains the data.
Reading: Serialize the list of data to json format using the gson and store each of them in a separate line.
Reading: Load the list of strings and deserialize them to the java class using gson.

How to make a ListView selectable but not editable

so I'm writing a javafx app and I need to be able to select the cells from the list view (for copy paste purposes) but I don't want to make it editable, I mean, the content cannot be changed unless I want to (allowing it through a button, for example).
So I have the following code:
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.scene.Scene;
import javafx.scene.control.ListView;
import javafx.scene.control.cell.TextFieldListCell;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception{
List<String> contacts = new ArrayList<>(Arrays.asList("968787522","3424234234","2343234324"));
ListView<String> contactsList = new ListView();
contactsList.setItems(FXCollections.observableArrayList(contacts));
//this gives me the ability to edit the row as text field but I want this text field to not be editable
contactsList.setCellFactory(TextFieldListCell.forListView());
StackPane pane = new StackPane();
pane.getChildren().add(contactsList);
primaryStage.setScene(new Scene(pane, 300, 275));
primaryStage.show(); }
public static void main(String[] args) {
launch(args);
}
}
and if I set 'contactsList' as not editable, I'm not able to edit, neither select.
As you can see (image bellow),I'm editing the cell, but I want to be able to select the text(not the item), but I don't want to be able to delete characters (text selectable but not editable).
so after breaking my head off, lots of research and API reading, I came up with a solution. This does EXACTLY what I wanted to do. Here is the demo if someone needs it ;)
So the idea is, each time we want to select the content of a row we need to select the row, get the textField and set the editing to true or false, (every time).
So in the demo that I made, I placed a button so you can toggle the editing to true or false to be sure that's is working, and how is working.
Cheers.
I commented some of the code for better understanding, if you have any questions about this just let me know.
package sample;
import com.sun.javafx.scene.control.skin.VirtualFlow;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.control.cell.TextFieldListCell;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Main extends Application {
private boolean editable = false;
public static IndexedCell getCell(final Control control, final int index) {
return getVirtualFlow(control).getCell(index);
}
public static VirtualFlow<?> getVirtualFlow(Control control) {
Group group = new Group();
Scene scene = new Scene(group);
Stage stage = new Stage();
if(control.getScene() == null) {
group.getChildren().setAll(control);
stage.setScene(scene);
stage.show();
}
VirtualFlow<?>flow = (VirtualFlow<?>) control.lookup("#virtual-flow");
return flow;
}
public void setEditable(ListView contactsList){
//this needs to be done since we need to run our code after the text field was rendered
//so we need to invoke our code after this happens, if not it will throw a null pointer...
Platform.runLater(() -> {
//this is one of the most important guys because javafx api says that
//TextFieldListCell.forListView() allows editing of the cell content when the cell is double-clicked,
// or when {#link ListView#edit(int)} is called.
int rowIndex = contactsList.getSelectionModel().getSelectedIndex();
contactsList.edit(rowIndex);
ListCell rootCell = (ListCell) getCell(contactsList, rowIndex);
TextField textField = (TextField) rootCell.getGraphic();
textField.setEditable(editable);
});
}
#Override
public void start(Stage primaryStage) throws Exception{
List<String> contacts = new ArrayList<>(Arrays.asList("968787522","3424234234","2343234324"));
ListView<String> contactsList = new ListView();
contactsList.setItems(FXCollections.observableArrayList(contacts));
contactsList.setEditable(true);
//this gives me the ability to edit the row as text field but I want this text field to not be editable
contactsList.setCellFactory(TextFieldListCell.forListView());
contactsList.setOnEditStart(e -> {
setEditable(contactsList);
});
StackPane pane = new StackPane();
Button editBtn = new Button("Toggle edit");
editBtn.setOnAction(event -> {
editable = !editable;
editBtn.setText("Editing = " + editable);
//to cancel any editing that might be occuring
contactsList.getSelectionModel().clearSelection();
});
pane.getChildren().addAll(contactsList,editBtn);
primaryStage.setScene(new Scene(pane, 300, 275));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
If I understand you correctly, it is not necessary to set the listview to 'not editable', as the default behaviour should suffice for your purpose. Take a look at this code, for example:
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.ListView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class NewFXMain extends Application {
#Override
public void start(Stage primaryStage) {
ListView listView = new ListView();
listView.getItems().addAll("one","two","three","four");
listView.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
System.out.println(listView.getSelectionModel().getSelectedItem());
}
});
StackPane root = new StackPane();
root.getChildren().add(listView);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("ListView Example");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
I changed nothing about the editable-property of the ListView, but I can select every item, without being able to edit it (in the sense of changing its value). You can easily add an EventHandler to the ListView to perform whatever operation you want to perform. You could also add an EventHandler to every cell of the ListView by manipulating the CellFactory, as shown in this answer: How to handle ListView item clicked action?
Here's what works for me:
TableView<DataBean> table = new TableView<>();
table.setItems(...); // list of some DataBean objects with dataBeanField proprty
table.setEditable(true);
TableColumn<DataBean, String> column = new TableColumn<>("SomeData");
column.setCellValueFactory(new PropertyValueFactory<DataBean, String>("dataBeanField"));
column.setCellFactory(new Callback<TableColumn<DataBean, String>, TableCell<DataBean, String>>() {
#Override
public TableCell<DataBean, String> call(TableColumn<DataBean, String> param) {
return new TextFieldTableCell<>(new DefaultStringConverter() {
private String defaultValue = "";
#Override
public String fromString(String newValue) {
return super.fromString(defaultValue);
}
#Override
public String toString(String value) {
return defaultValue = super.toString(value);
}
});
}
});

In javafx, how does one make methods done in event handlers affect the rest of the code?

Basically my code is like this:
fileOpener.setOnAction(
new EventHandler<ActionEvent>() {
#Override
public void handle(final ActionEvent e) {
myFileList.add(openMusicTracks.showOpenDialog(window));
System.out.println(myFileList.getName(0)); //prints file name so I know this works
}
});
I want the add method (that's inside of the EventHandler) to actually edit the arraylist for everywhere else so that later when I reference it in
ObservableList<String> playList = FXCollections.observableArrayList ();
for(int i = 0; i < myFileList.size(); i++) {
playList.add(i, myFileList.get(i).getName());
System.out.println(myFileList.getName(0)); //doesn't print the file name, so I know this doesn't work.
}
the arraylist won't be empty. How do I do this? I'm sorry if there's a more elegant way to word this, but I have honestly no idea how to research this, I've tried. Thanks.
A simple example which shows how can an ArrayList be shared between methods.
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import java.util.ArrayList;
import java.util.List;
public class Main extends Application {
private List<String> list = new ArrayList<>();
#Override
public void start(Stage primaryStage) {
Button add = new Button("Add");
Button display = new Button("Show");
// Add Items
add.setOnAction(event -> list.add("Item"));
// Display Items
display.setOnAction(e -> {
printAndClear();
});
VBox root = new VBox(10, add, display);
root.setAlignment(Pos.CENTER);
Scene scene = new Scene(root, 200, 200);
primaryStage.setScene(scene);
primaryStage.show();
}
private void printAndClear() {
list.forEach(System.out::println);
list.clear();
}
public static void main(String[] args) {
launch(args);
}
}

Disable all MouseEvents on the Children of a Pane

I have a Pane in which i add and remove nodes during a computation. Therefor i save a boolean which is set to true if the computation is running. of course i do some handling on starting and terminating a computation.
What i want to do now is: disable all MouseEvents on the children of the Pane if the computation starts and reenable them if the computation is terminated.
My tries until now where limited to completly remove the EventHandlers, but then i can't add them again later.
unfortunately i couldn't find a way to do this, so i hope for help here :)
Thanks in advance
Assuming you have implemented the long-running computation as a Task or Service (and if you haven't, you should probably consider doing so), you can just do something along the following lines:
Pane pane ;
// ...
Task<ResultType> computation = ... ;
pane.disableProperty().bind(computation.runningProperty());
new Thread(computation).start();
Calling setDisable(true) on a node will disable all its child nodes, so this will disable all the children of the pane, and re-enable them when the task is no longer running.
Here's an SSCCE:
import javafx.application.Application;
import javafx.concurrent.Service;
import javafx.concurrent.Task;
import javafx.geometry.HPos;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Priority;
import javafx.stage.Stage;
public class ComputationSimulation extends Application {
#Override
public void start(Stage primaryStage) {
// text fields for input:
TextField xInput = new TextField();
TextField yInput = new TextField();
// Service for performing the computation.
// (For demo here, the computation just computes the sum of
// the two input values. Obviously this doesn't take long, so
// a random pause is inserted.)
Service<Integer> service = new Service<Integer>() {
#Override
protected Task<Integer> createTask() {
final int x = readTextField(xInput);
final int y = readTextField(yInput);
return new Task<Integer>() {
#Override
public Integer call() throws Exception {
// simulate long-running computation...
Thread.sleep((int)(Math.random() * 2000) + 1000);
// this doesn't really take much time(!):
return x + y ;
}
};
}
};
// Label to show result. Just use binding to bind to value of computation:
Label result = new Label();
result.textProperty().bind(service.valueProperty().asString());
// Button starts computation by restarting service:
Button compute = new Button("Compute");
compute.setOnAction(e -> service.restart());
// Pane to hold controls:
GridPane pane = new GridPane();
// Disable pane (and consequently all its children) when computation is running:
pane.disableProperty().bind(service.runningProperty());
// layout etc:
pane.setHgap(5);
pane.setVgap(10);
pane.addRow(0, new Label("x:"), xInput);
pane.addRow(1, new Label("y:"), yInput);
pane.addRow(2, new Label("Total:"), result);
pane.add(compute, 1, 3);
ColumnConstraints left = new ColumnConstraints();
left.setHalignment(HPos.RIGHT);
left.setHgrow(Priority.NEVER);
pane.getColumnConstraints().addAll(left, new ColumnConstraints());
pane.setPadding(new Insets(10));
Scene scene = new Scene(pane);
primaryStage.setScene(scene);
primaryStage.show();
}
// converts text in text field to an int if possible
// returns 0 if not valid text, and sets text accordingly
private int readTextField(TextField text) {
try {
return Integer.parseInt(text.getText());
} catch (NumberFormatException e) {
text.setText("0");
return 0 ;
}
}
public static void main(String[] args) {
launch(args);
}
}

Live update Pie Chart

I want to create very useful and easy way to live update Pie chart. For example:
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.chart.PieChart;
import javafx.scene.control.Label;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
public class MainApp extends Application {
#Override
public void start(Stage stage) {
Scene scene = new Scene(new Group());
stage.setTitle("Imported Fruits");
stage.setWidth(500);
stage.setHeight(500);
ObservableList<PieChart.Data> pieChartData =
FXCollections.observableArrayList(
new PieChart.Data("Grapefruit", 13),
new PieChart.Data("Oranges", 25),
new PieChart.Data("Plums", 10),
new PieChart.Data("Pears", 22),
new PieChart.Data("Apples", 30));
final PieChart chart = new PieChart(pieChartData);
chart.setTitle("Imported Fruits");
final Label caption = new Label("");
caption.setTextFill(Color.DARKORANGE);
caption.setStyle("-fx-font: 24 arial;");
for (final PieChart.Data data : chart.getData()) {
data.getNode().addEventHandler(MouseEvent.MOUSE_PRESSED,
new EventHandler<MouseEvent>() {
#Override public void handle(MouseEvent e) {
caption.setTranslateX(e.getSceneX());
caption.setTranslateY(e.getSceneY());
caption.setText(String.valueOf(data.getPieValue())
+ "%");
}
});
}
((Group) scene.getRoot()).getChildren().addAll(chart, caption);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
When I display the chart I want to call Java Method and update the chart like this:
PieChartUpdate(valueOne, valueTwo, valueThree);
Can you show me how I can edit the code in order to make the live updates more easy to use?
As far as i could see, all classes that are used to establish a PieChart, like PieChart.Data and of course the ObservableList are already designed so that they will update the PieChart the moment something changes, be it the list itself or values inside the Data Objects. See the binding chapters how this is done. But you don't need to write your own bindings for the PieChart.
The code below should do what you want. Use addData(String name, double value) to create a new Data object for your pie chart, or update an existing one which has the same name like the first parameter of the method. The PieChart will automatically play a animation when changes are made to the list (new Data object added) or a Data object got changed.
//adds new Data to the list
public void naiveAddData(String name, double value)
{
pieChartData.add(new Data(name, value));
}
//updates existing Data-Object if name matches
public void addData(String name, double value)
{
for(Data d : pieChartData)
{
if(d.getName().equals(name))
{
d.setPieValue(value);
return;
}
}
naiveAddData(name, value);
}
Just in case someone feels extremely lost and isn't sure how to implement denhackl's answer, here is a working version of what he tried to explain.
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.chart.PieChart;
import javafx.scene.control.Label;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
public class LivePie extends Application {
ObservableList<PieChart.Data> pieChartData;
#Override
public void start(Stage stage) {
Scene scene = new Scene(new Group());
stage.setTitle("Imported Fruits");
stage.setWidth(500);
stage.setHeight(500);
this.pieChartData =
FXCollections.observableArrayList();
addData("Test", 5.1);
addData("Test2", 15.1);
addData("Test3", 3.1);
addData("Test1", 4.9);
addData("Test2", 15.1);
addData("Test3", 2.1);
addData("Test5", 20.1);
final PieChart chart = new PieChart(pieChartData);
chart.setTitle("Imported Fruits");
final Label caption = new Label("");
caption.setTextFill(Color.DARKORANGE);
caption.setStyle("-fx-font: 24 arial;");
((Group) scene.getRoot()).getChildren().addAll(chart, caption);
stage.setScene(scene);
stage.show();
}
public void naiveAddData(String name, double value)
{
pieChartData.add(new javafx.scene.chart.PieChart.Data(name, value));
}
//updates existing Data-Object if name matches
public void addData(String name, double value)
{
for(javafx.scene.chart.PieChart.Data d : pieChartData)
{
if(d.getName().equals(name))
{
d.setPieValue(value);
return;
}
}
naiveAddData(name, value);
}
public static void main(String[] args) {
launch(args);
}
}
Many thanks to the creator of the topic and the answers provided!
Here's a good introductory article on using properties and binding.
http://docs.oracle.com/javafx/2/binding/jfxpub-binding.htm

Categories

Resources