Update ObservableList with data from sorted list? - javafx

I have followed this 1 tutorial to create a tableview with filtering. It works great, but the code in the tutorial creates a new SortedList (sortedData) with the sorted data and binds it with comparotorproperty to the table view, which originally uses a ObservableList as data source.
SortedList<Record> sortedData = new SortedList<Record>(filteredData);
// 4. Bind the SortedList comparator to the TableView comparator.
sortedData.comparatorProperty().bind(tableView.comparatorProperty());
// 5. Add sorted (and filtered) data to the table.
tableView.setItems(sortedData);
In my code I also have a Pie Chart and Bar Chart. They also use the ObservableList as data sources, so my question is ; how can I bind the sortedData to the ObservableList?
My code to get the data to the PieChart (and BarChart) is this:
for (Record record : dataen) {
dataList.add(new PieChart.Data(record.getFieldMonth(), record.getFieldValue()));
}
Where record is a class with Getters and Setters.

So you want to turn ObservableList<Record> into ObservableList<PieChart.Data>, correct? For that you can use EasyBind:
ObservableList<PieChart.Data> chartData = EasyBind.map(sortedData,
r -> new PieChart.Data(r.getFieldMonth(), r.getFieldValue()));
pieChart.setData(chartData);

Related

Adding individual item to a TableView?

I have started using JavaFX for a few weeks. Here is a code snap of a TableView
#FXML protected void handleSubmitButtonAction(ActionEvent event) {
log.debug("handleSubmitButtonAction");
service.save(new InputText(inputText.getText()));
List<OutputData> outputDataList = new ArrayList<>();
service.getAll().forEach(e -> outputDataList.add(new OutputData(e)));
ObservableList<OutputData> list = FXCollections.observableArrayList(outputDataList);
outputView.setItems(list);
inputText.setText("");
}
What it does is that
Create a new entry
Save it to DB
Fetch all entries from DB
Create TableView row data for each entry
Create an ObservableList with all of the row data
Add the list to the TableView
That certainly isn't effective. Is a way to add a newly created entry directly to the TableView?
Here is what I would do.
Have service.save(new InputText(inputText.getText())); return a
true if the data was saved to the DB and false otherwise.
If true is returned, I would then add the data to the TableView
using outputView.getItems().add(inputText.getText());
If false is retured, I would use an Alert to let the user know
that the data was not added to the DB.

Javafx tableview column value from event handler

Is it possible to take a value of table column from a event handler in Javafx?
The task is I need to click a button, calculate functions, and return the value to the column.
I have this working:
data.add(new Person(id, name));
I have this:
TableColumn nameCol = new TableColumn ("name");
nameCol.setCellValueFactory(new PropertyValueFactory<>("name"));
// And id as well.
TableColumn resultsCol = new TableColumn ("Results");
resultsCol.setCellValueFactory(new PropertyValueFactory<>("results"));
And this:
add.setOnAction (e -> {
// I don't know what to put
});
Because id and name column are already working, what should I do to separately add a new value to the column from a button?
Because your CellValueFactories are pulling values directly from your Person object you would need to update the variables in the particular row's Person object when your button is clicked. You can do this with simple setter methods.
You could also use a technique like this to create a table with cells that can be edited with a click: http://java-buddy.blogspot.com/2012/04/javafx-2-editable-tableview.html?m=1
I have successfully implemented this technique in my applications.

How to populate a tableview, javafx 8, dynamically

I created a TableView via SceneBuilder so that it receives dynamic data, that is, I will always have distinct SQL scripts whose data I want to display in the TableView.
So the columns are created according to the amount of fields I detect in sql.
This is already being done. The problem is in the code for popular TableView rows.
For this, I get an ArrayList <String> with resultSet data, as it is dynamic information,
This ArrayList <String> receives each record with the fields separated by #. Then I get the
Number of fields I will have as columns and created TableView columns with similar titles To the field names. That works perfectly.
Then I created a loop to get the ArrayList <String> elements, called
Of aListString.At where:
Data [] [] has the number of rows according to the number of elements of aListString and the quantity Of columns according to the number of fields (qtdeCampos). Until now resolved.
Then the loop fills the array data [] [] without problem, each row with their respective fields.
Finally, I fill out the TableView with:
tableViewResultado.getItems().addAll(Arrays.asList(dados));
Since the TableView is defined as:
#FXML
private TableView<String[]> tableViewResultado;
However, the rows are not populated with the data data [] [], whose information is correctly Stored in this matrix. The code:
for(int j=0;j<qtdeCampos;j++)
{
TableColumn<String[],String> column = new TableColumn();
column.setText(arrayListCampos.get(j).getNomeCampo());
aTableColumn.add(column);
tableViewResultado.getColumns().add(column);
}
String dados[][] = new String[aListString.size()][qtdeCampos];
for(int i=0;i<aListString.size();i++)
{
String dadosX[]=aListString.get(i).split("#");
for(int k=0;k<dadosX.length;k++)
{
dados[i][k]=dadosX[k];
}
}
Where is the error?
Thank you for your attention.

Can't clear all items (elements) in an ObservableList

I've a couple of copied elements in an observablelist which I use for copy/paste operations in a TableView. The name of the table is cpTable (copy and paste Table) for storing copied elements and to paste elements that are stored in the table. After each paste operation I want to clear the contents of cpTable before I copy other selected items with Ctrl+C.
But I always get the error:
JavaFX Application Thread" java.lang.UnsupportedOperationException:
Not supported.
at com.sun.javafx.scene.control.ReadOnlyUnbackedObservableList.remove(ReadOnlyUnbackedObservableList.java:246)
Here is my pseudocode:
if (cpTable !=null) {
//first, get all copied items for removing all elements
ObservableList<String> copiedItems = cpTable.getItems();
int size = copiedItems.size();
// remove all elements
for(int i=0;i<size;i++) {
copiedItems.remove(i);
}
cpTable.setItems(copiedItems); //clear cpTable by setting an empty list
}
This is a method that copies the contents of selected items and puts it in a cpTable
public TableView<String> copySelectionToClipboard(TableView<String> table) {
ObservableList<String> data = table.getSelectionModel().getSelectedItems();
TableView<String> tmp = new TableView<>();
tmp.setItems(data);
return tmp;
}
When Ctrl+C is pressed the following line puts all copied items in a cpTable:
cpTable = copySelectionToClipboard( (TableView<String>) keyEvent.getSource());
As mentioned I want to clear all cpTable contents immediately after pasting
the items in a table.
Just clear your Observable List. It looks like you should use copiedItems.clear();
That should clear your table.
As James_D already mentioned, you haven't cleared exactly what's the point.
If you want to delete selected items from a table, you need to delete them from the table item list itself and not from the selection model.
A possible solution looks like this:
TableView<String> table = new TableView<>();
ObservableList<String> tableItems = table.getItems();
// needs multirowselection is set to true
ObservableList<String> readOnlyItems = table.getSelectionModel().getSelectedItems();
// removes all selected elements for the table
readOnlyItems.stream().forEach((item) -> {
tableItems.remove(item);
});
// clear the selection
table.getSelectionModel().clearSelection();
Update
This method get's an TableView, calls it's selection model to get all selected items. And then you add the data to a new TableView. And there is the problem! It's an unmodifiable read only list that you attached to your new table. First make it modifiable, like in the code below:
public TableView<String> copySelectionToClipboard(TableView<String> table) {
ObservableList<String> readOnlyData = table.getSelectionModel().getSelectedItems();
ObservableList<String> writableData = FXCollections.<String>observableArrayList(readOnlyData);
TableView<String> tmp = new TableView<>();
tmp.setItems(writableData);
return tmp;
The next problem is in your call to this method. You call it with a TableView<CsvData> and with a TableView<String> as your method needs. If CsvData is a subtype of String, than you have to change your method signature to TableView<? extends String>
If you are trying to clear all the items from your tableView and want just an empty tableView. You can use this:
myTableView.getItems().clear();
This basically gets all the items from your table view which is nothing but just the observable list now it performs clear operations to remove all the items in tableView.
Assuming you mean
table.getSelectionModel().getSelectedItems()
(since the selection model has no getItems() method), according to the Javadocs, this returns a read-only list. Thus attempting to modify the list will throw an UnsupportedOperationException.
To clear the selection, do
table.getSelectionModel().clearSelection();
(And similarly, if you want to manipulate the selection in any other way, you use methods on the selection model, rather than on the list.)

How to sort AdvancedDataGrid with hierarchical data?

I have an AdvancedDataGrid with a HierarchicalCollectionView as its dataProvider. When I view the grid with the dataset I'm working with, and click the header of the column I wish to sort on, everything works perfectly. It sorts it hierarchically exactly how I would expect it to.
What I want to do now is have the grid already be sorted when it is shown to the user. Is there a way to do this programatically? I can't for the life of me figure out how to do this, and clearly it's possible since the AdvancedDataGrid has this built in.
Edit - BTW, I've tried this:
var myData:HierarchicalCollectionView = new HierarchicalCollectionView(theDataSource);
// Works fine using only the line above and clicking the header to sort.
// This is the part that I tried adding:
var sort:Sort = new Sort();
sort.fields = [new SortField("startDate")];
myData.sort = sort;
myData.refresh();
This appears to do something as far as sorting goes, but it doesn't sort it in the same way as clicking the column header. "startDate" is a property of an object in theDataSource by the way.
Looks like you want to sort dates. Sort can't do that out of the box. You have to use a compareFunction.
If your objects are of type Date it's quite easy:
var sortField:SortField = new SortField("startDate");
sortField.compareFunction = ObjectUtil.dateCompare;
In case your column contains dates as strings you'll have to parse them first (code example from http://blog.flexexamples.com/2007/08/12/sorting-date-columns-in-a-datagrid/):
private function date_sortCompareFunc(itemA:Object, itemB:Object):int
{
/* Date.parse() returns an int, but
ObjectUtil.dateCompare() expects two
Date objects, so convert String to
int to Date. */
var dateA:Date = new Date(Date.parse(itemA));
var dateB:Date = new Date(Date.parse(itemB));
return ObjectUtil.dateCompare(dateA, dateB);
}
var sortField:SortField = new SortField("startDate");
sortField.compareFunction = date_sortCompareFunc;
Then just use the sortField like you did in your example. That should work fine.
You can create a new advanced data grid sort event and dispatch it on the grid after the hierarchical data is set on it (unfortunately I've had to use a callLater to give the grid time to deal with the collection internally it seems assignments to the dataProvider of the ADG are sometimes asynchronous)
var advancedDataGridEvent : AdvancedDataGridEvent = new AdvancedDataGridEvent(AdvancedDataGridEvent.SORT, false, true);
advancedDataGridEvent.columnIndex = columnIndex;
advancedDataGridEvent.dataField = dataField;
dispatchEvent(advancedDataGridEvent);
This code is from an extension of ADG so you would want the dispatchEvent to actually be on your instance of the grid if you're not creating an extension.
Also a note from the code:
//setting sortDescending=true on a column does not work as expected. so, until a solution
//is found, this works just as well. the event that is dispatch just tells the column
//to reset. so, one resorts ascending (the default), while a second resorts descending.
//however, this second is only dispatched if defaultSortDesc is true on the grid.
if (defaultSortDesc)
{
dispatchEvent(advancedDataGridEvent);
}
It dispatches the event twice to flip the sort.

Resources