Saturday, March 2, 2013

JavaFX: Interaction between table and charts

Last article demonstrate "Update StackedBarChart dynamically, with TableView". It's another example to make PieChart and LineChart update dynamically with TableView.



package javafxmulticolumnchart;

import java.util.Arrays;
import java.util.List;
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.chart.CategoryAxis;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.PieChart;
import javafx.scene.chart.XYChart;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
import javafx.util.Callback;

/**
*
* @web http://java-buddy.blogspot.com/
*/
public class JavaFXMultiColumnChart extends Application {

public class Record{
private SimpleStringProperty fieldDay;
private SimpleDoubleProperty fieldValue1;
private SimpleDoubleProperty fieldValue2;

Record(String fDay, double fValue1, double fValue2){
this.fieldDay = new SimpleStringProperty(fDay);
this.fieldValue1 = new SimpleDoubleProperty(fValue1);
this.fieldValue2 = new SimpleDoubleProperty(fValue2);
}

public String getFieldDay() {
return fieldDay.get();
}

public double getFieldValue1() {
return fieldValue1.get();
}

public double getFieldValue2() {
return fieldValue2.get();
}

public void setFieldDay(String fDay) {
fieldDay.set(fDay);
}

public void setFieldValue1(Double fValue1) {
fieldValue1.set(fValue1);
}

public void setFieldValue2(Double fValue2) {
fieldValue2.set(fValue2);
}
}

class MyList {

ObservableList<Record> dataList;
ObservableList<PieChart.Data> pieChartData1;
ObservableList<XYChart.Data> xyList2;

MyList(){
dataList = FXCollections.observableArrayList();
pieChartData1 = FXCollections.observableArrayList();
xyList2 = FXCollections.observableArrayList();
}

public void add(Record r){
dataList.add(r);
pieChartData1.add(new PieChart.Data(r.getFieldDay(), r.getFieldValue1()));
xyList2.add(new XYChart.Data(r.getFieldDay(), r.getFieldValue2()));
}

public void update1(int pos, Double val){
pieChartData1.set(pos, new PieChart.Data(pieChartData1.get(pos).getName(), val));
}

public void update2(int pos, Double val){
xyList2.set(pos, new XYChart.Data(xyList2.get(pos).getXValue(), val));
}
}

MyList myList;

private TableView<Record> tableView = new TableView<>();

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

@Override
public void start(Stage primaryStage) {
primaryStage.setTitle("java-buddy.blogspot.com");

//prepare myList
myList = new MyList();
myList.add(new Record("Sunday", 100, 120));
myList.add(new Record("Monday", 200, 210));
myList.add(new Record("Tuesday", 50, 70));
myList.add(new Record("Wednesday", 75, 50));
myList.add(new Record("Thursday", 110, 120));
myList.add(new Record("Friday", 300, 200));
myList.add(new Record("Saturday", 111, 100));

Group root = new Group();

tableView.setEditable(true);

Callback<TableColumn, TableCell> cellFactory =
new Callback<TableColumn, TableCell>() {

@Override
public TableCell call(TableColumn p) {
return new EditingCell();
}
};

TableColumn columnDay = new TableColumn("Day");
columnDay.setCellValueFactory(
new PropertyValueFactory<Record,String>("fieldDay"));
columnDay.setMinWidth(60);

TableColumn columnValue1 = new TableColumn("Value 1");
columnValue1.setCellValueFactory(
new PropertyValueFactory<Record,Double>("fieldValue1"));
columnValue1.setMinWidth(60);

TableColumn columnValue2 = new TableColumn("Value 2");
columnValue2.setCellValueFactory(
new PropertyValueFactory<Record,Double>("fieldValue2"));
columnValue2.setMinWidth(60);

//--- Add for Editable Cell of Value field, in Double
columnValue1.setCellFactory(cellFactory);
columnValue1.setOnEditCommit(
new EventHandler<TableColumn.CellEditEvent<Record, Double>>() {

@Override public void handle(TableColumn.CellEditEvent<Record, Double> t) {
((Record)t.getTableView().getItems().get(
t.getTablePosition().getRow())).setFieldValue1(t.getNewValue());

int pos = t.getTablePosition().getRow();
myList.update1(pos, t.getNewValue());
}
});

columnValue2.setCellFactory(cellFactory);
columnValue2.setOnEditCommit(
new EventHandler<TableColumn.CellEditEvent<Record, Double>>() {

@Override public void handle(TableColumn.CellEditEvent<Record, Double> t) {
((Record)t.getTableView()
.getItems()
.get(t.getTablePosition().getRow())).setFieldValue2(t.getNewValue());

int pos = t.getTablePosition().getRow();
myList.update2(pos, t.getNewValue());
}
});

//--- Prepare StackedBarChart

List<String> dayLabels = Arrays.asList(
"Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday");

final PieChart pieChart1 = new PieChart(myList.pieChartData1);
pieChart1.setPrefWidth(200);
pieChart1.setTitle("Pie Chart 1");

final CategoryAxis xAxis2 = new CategoryAxis();
final NumberAxis yAxis2 = new NumberAxis();
xAxis2.setLabel("Day");
xAxis2.setCategories(FXCollections.<String> observableArrayList(dayLabels));
yAxis2.setLabel("Value 2");
XYChart.Series XYSeries2 = new XYChart.Series(myList.xyList2);
XYSeries2.setName("XYChart.Series 2");

final LineChart<String,Number> lineChart2 =
new LineChart<>(xAxis2,yAxis2);
lineChart2.setTitle("Line Chart 2");
lineChart2.setPrefWidth(250);
lineChart2.getData().add(XYSeries2);

//---
tableView.setItems(myList.dataList);
tableView.getColumns().addAll(columnDay, columnValue1, columnValue2);
tableView.setPrefWidth(200);

HBox hBox = new HBox();
hBox.setSpacing(10);
hBox.getChildren().addAll(tableView, pieChart1, lineChart2);

root.getChildren().add(hBox);

primaryStage.setScene(new Scene(root, 750, 400));
primaryStage.show();
}

class EditingCell extends TableCell<Record, Double> {
private TextField textField;

public EditingCell() {}

@Override
public void startEdit() {
super.startEdit();

if (textField == null) {
createTextField();
}

setGraphic(textField);
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
textField.selectAll();
}

@Override
public void cancelEdit() {
super.cancelEdit();

setText(String.valueOf(getItem()));
setContentDisplay(ContentDisplay.TEXT_ONLY);
}

@Override
public void updateItem(Double item, boolean empty) {
super.updateItem(item, empty);

if (empty) {
setText(null);
setGraphic(null);
} else {
if (isEditing()) {
if (textField != null) {
textField.setText(getString());
}

setGraphic(textField);
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
} else {
setText(getString());
setContentDisplay(ContentDisplay.TEXT_ONLY);
}
}
}

private void createTextField() {
textField = new TextField(getString());
textField.setMinWidth(this.getWidth() - this.getGraphicTextGap()*2);
textField.setOnKeyPressed(new EventHandler<KeyEvent>() {

@Override
public void handle(KeyEvent t) {
if (t.getCode() == KeyCode.ENTER) {
commitEdit(Double.parseDouble(textField.getText()));
} else if (t.getCode() == KeyCode.ESCAPE) {
cancelEdit();
}
}
});
}

private String getString() {
return getItem() == null ? "" : getItem().toString();
}
}

}


No comments:

Post a Comment