How to populate a tableview, javafx 8, dynamically - javafx

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.

Related

javaFx TableView with Multiple ComboBoxes

I have a requirement where in i am supposed to compare two csv files. For comparison , we are trying to implement a rules configuration. Now the Rules will have an object like the following :
public class CsvInformation {
private String resultType;
private List<String> primaryKey;
private List<String> standardKey;
private List<String> ignoreKey;
public String getResultType() {
return resultType;
}
public void setResultType(String resultType) {
this.resultType = resultType;
}
public List<String> getPrimaryKey() {
return primaryKey;
}
public void setPrimaryKey(List<String> primaryKey) {
this.primaryKey = primaryKey;
}
public List<String> getStandardKey() {
return standardKey;
}
public void setStandardKey(List<String> standardKey) {
this.standardKey = standardKey;
}
public List<String> getIgnoreKey() {
return ignoreKey;
}
public void setIgnoreKey(List<String> ignoreKey) {
this.ignoreKey = ignoreKey;
}
so i am fetching a list of CSVInformation objects.Now i'd like to map/bind these to a tableView control so that the user will get an option to select values for PrimaryKey,IgnoreKey,StandardKey through a comboBox control in a TableView Cell. The TableView Control should look something similar to the following snapshot.
In the snapshot above, i'd like to fill each row of the TableView with each object of the List of CsvInformation Objects which i am getting from the backEnd. Is this achievable . I googled a bit but everywhere they have mentioned they haven't been able to use a Collection for binding to a comboBox inside a TableView . Any advice/ pointers/ suggestion will be highly appreciated. Thanks
#James_D : Hi James, Thx for the reply. The primary idea is that the user will be given the optoin to select primary Key,Standard Key & Ignore Key so as to tell us which columns to include for comparison and which ones to ignore , which is the primary key etc. Once the user makes that selection for as many rows as are present in the TableView at that time, i need to save these and create a Json out of that.The requirement is such that the tableView needs to comprise of 4 columns : 1 label, 3 Non- Editable Combo-boxes. Now to answer your query on combo box, each combo-box will be unique in nature i.e the entries that'll fill the ComboBox inside the TableView, if i say Row 1 , primaryKey Combo - box will have String values such as Mohit,Neha,Neeraj. Now when i move to fill the fill the next row, i.e Row 2 primaryKey Combo - box will have values such as James,Jason,Bourne.What i am trying to achieve is to create these combo-boxes on the go by binding to a list. I'm attaching a snapshot here for the content of csvHeaderList.Each row in the TableView Content will be from each ondex of the CSVHeaderList. Please let me know if you need any more insights on this.
< TabelView code >
TableView<CsvInformation > table = new TableView<CsvInformation >();
// Create column Result Type (Data type of String).
TableColumn<CsvInformation , String> resultTypeCol = new TableColumn<CsvInformation , String>("Result Type");
// Create column Primary Column (Data type of List<String>).
TableColumn<CsvInformation , List<String>> primaryKeyCol = new TableColumn<CsvInformation , List<String>>("Primary Column");
// Create column Standard Column (Data type of List<String>).
TableColumn<CsvInformation , List<String>> standardCol = new TableColumn<CsvInformation , List<String>>("Standard Column");
// Create column for Ignorable Columns. (Data type of List<String>).
TableColumn<CsvInformation , List<String>> ignoredCol = new TableColumn<CsvInformation , List<String>>("Ignorable Columns");
PropertyValueFactory<CsvInformation , List<CsvInformation >> resultTypeColFactory = new PropertyValueFactory<>(
"resultType");
PropertyValueFactory<CsvInformation , List<CsvInformation >> primaryColFactory = new PropertyValueFactory<>(
"primaryKey");
PropertyValueFactory> standardColFactory = new PropertyValueFactory<>(
"standardKey");
PropertyValueFactory> compareColFactory = new PropertyValueFactory<>(
"ignoreKey");
// Defines how to fill data for each cell.
// Get value from property of CsvInformation.
resultTypeCol.setCellValueFactory(new PropertyValueFactory<>("resultType"));
primaryKeyCol.setCellValueFactory(new PropertyValueFactory<>("primaryKey"));
standardCol.setCellValueFactory(new PropertyValueFactory<>("standardKey"));
ignoredCol.setCellValueFactory(new PropertyValueFactory<>("ignoreKey"));
Where i'm stuck is how to provide my definition for Tablecolumn,Table Cell,Cellfactory for a collection / List like :
TableColumn for mapping my list to a combobox inside a TableView.

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.)

JavaFX: Selecting a lot of rows in a large table

It seems a simple question, but I can't find a solution myself.
I have a TableView (to be frank I have two TableViews and would like to put the items from one to the other) with a large number of rows (for my tests, I had a little more than 6600) in it.
When I move the items, I would like to modify the selection of the destination table to be exactly the ones freshly selected.
#FXML
private TableView<PositionWrapper> source;
#FXML
private TableView<PositionWrapper> target;
private ObservableList<PositionWrapper> sourceList = FXCollections.observableArrayList();
private ObservableList<PositionWrapper> targetList = FXCollections.observableArrayList();
private void moveSourceToTarget(MouseEvent event) {
// collecting selected items
ObservableList<PositionWrapper> selectedItems =
FXCollections.observableArrayList(
source.getSelectionModel().getSelectedItems());
// Adding selected items to the target
targetList.addAll(selectedItems);
// Removing selected items from source
sourceList.removeAll(selectedItems);
// Clearing the selection in both table (source has none of the
// selected items now, the target selection should be updated completely)
target.getSelectionModel().clearSelection();
source.getSelectionModel().clearSelection();
// My first try. Doesn't work (UnsupportedOperationException)
target.getSelectionModel().getSelectedItems().setAll(selectedItems);
// Second try: doing it one-by-one. Works, but extremely slow.
selectedItems.stream().forEach(p -> target.getSelectionModel().select(p));
}
The second alternative works, but extremely slow. (How slow I don't know, because I killed my program after 20 seconds.)
My question: how to select a large number of rows in a TableView quickly?
I made some deeper search and checked the implementation source code of the MultipleSelectionModelBase class. When selecting an item by row content (as I did in my second try), it iterates over all the items in the table to find the index of it, then calls the select(int) method with the index found.
It means that selecting several rows by content is an n*m algorithm, with a worst case of n^2 when selecting (almost) all items.
But this gave me the solution as well. As it is now proved to me that only the by-value selection suffers from the n^2 anomaly, the natural workaround is to use the index-based selection.
Here is my code snippet:
private void moveSourceToTarget(MouseEvent event) {
[...]
// Allocating an array to store indexes
int[] idx = new int[selectedItems.size()];
int p = 0;
// Performance tuning to move selected items into a set
// (faster contains calls)
Set<PositionWrapper> s = new HashSet<>(Arrays.asList(
selectedItems.toArray(new PositionWrapper[0])));
// Iterating over items in target list (but only once!)
for (int i = 0; i < target.getItems().size(); i++) {
if (s.contains(target.getItems().get(i))) {
// and adding to the list of indexes when selected
idx[p++] = i;
}
}
// Calling the more effective index-based selection setter
target.getSelectionModel().selectIndices(-1, idx);
}
Aftermath: the time required for selecting the 6600+ items reduced from 20+ sec to 0.1 sec.
BTW, I don't know why isn't selectAll(S...) is part of the JavaFX code...

Update ObservableList with data from sorted list?

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);

Spring JDBC Dynamic Query into Map of objects

I have to dynamically execute queries which will come from database.The query has dynamic fields,which needs to be converted into map as key value pairs and send to view.For ex
one query may return only one fields and other may return more than two field of multiple rows.I have to write code in such way that it will work for n no.of fields and return it as map using spring jdbc.
Spring offers two ways to solve your problem.
Approach 1: use queryForList method from JdbcTemplate class. this will return List of Map populated by column names as key , and DB record as value. you have to manualy iterate over the list. each map object inside the list represents a single row in resultset.
example :
List<Map<String, Object>> result = jdbcTemplate.queryForList(query, new Object[]{123});
Iterator items = result.iterator();
while(items.hasNext()){
Map<String, Object> row = (Map<String, Object>) items.next();
System.out.println(row);
}
Approach 2 : this dosen't exactly match your requirements, but little faster than the first approach also more coding involved. you can use queryForRowSet method.
SqlRowSet rowSet = jdbcTemplate.queryForRowSet(query, new Object[]{3576});
int columnCount = rowSet.getMetaData().getColumnCount();
System.out.println(columnCount);
while(rowSet.next()){
for(int id =1 ; id <= columnCount ; id ++){
System.out.println(rowSet.getString(id)) ;
// your custom logic goes here
}
}

Resources