I have a table which is loaded dynamically from a given database; the problem is that it duplicates data. Here is the method that generates the table:
#FXML
public void buildCentres() {
Connection c;
ResultSet result;
ObservableList<ObservableList> centers = FXCollections.observableArrayList();
try {
c = DBconnection.getconection_planning();
result = c.createStatement().executeQuery("SELECT centreno,centrename FROM plan_centres");
for (int i = 0; i < result.getMetaData().getColumnCount(); i++) {
final int j = i;
TableColumn col = new TableColumn(result.getMetaData().getColumnName(i + 1));
col.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<ObservableList, String>, ObservableValue<String>>() {
#Override
public ObservableValue<String> call(TableColumn.CellDataFeatures<ObservableList, String> param) {
return new SimpleStringProperty(param.getValue().get(j).toString());
}
});
HomeView.getColumns().addAll(col);
}
while (result.next()) {
//Iterate Row
ObservableList<String> row = FXCollections.observableArrayList();
for (int i = 1; i <= result.getMetaData().getColumnCount(); i++) {
//Iterate Column
row.add(result.getString(i));
}
centers.add(row);
}
HomeView.setItems(null);
HomeView.setItems(centers);
c.close();
result.close();
} catch (Exception e) {
// Something to notify
}
}
Here is the interface:
The columns and rows are duplicating and when I want to clear the table and load something else, it adds on the new content as a column in the existing columns.
Thanks in advance for your help.
You don't need to create columns on each query.
Either wrap first loop in if (HomeView.getColumns().isEmpty()) or clear them before the first loop.
Rows generating code looks fine, so make sure you are not calling buildCentres() twice and that DB doesn't have duplicates.
Related
I have a TableView with a list of items (Transaction) and want it to sort, so that all positive values are above the negative ones. This is the only requirement.
What I have until now:
expensesTableView.sortPolicyProperty().set(
new Callback<TableView<Transaction>, Boolean>() {
#Override
public Boolean call(TableView<Transaction> param) {
Comparator<Transaction> c = (a, b) -> {
if (a.getValue().contains("-") ^ b.getValue().contains("-")) { //getValue() returns a String
return a.getValue().contains("-") ? 1 : -1;
}
return 0;
};
FXCollections.sort(expensesTableView.getItems(), c);
return true;
};
});
This wasn't my idea, I found this on the net, so don't ask if it looks like a strange way to achieve that. The real problem is, that the table doesn't sort on its own when a new item is added/edited/deleted. I need to click the header 3 times and then it does what I want.
How can I have a list that is always sorted correctly?
I tried adding a ChangeListener and sort on change. But besides that this is an ugly way to do that, it didn't even work... I'm at the end of ideas.
The bitwise OR in the comparator didn't work in my tests, so I've changed it to a normal one, and it's also not checking for change in the value of items from the list.
I wonder if it might be more efficient to do a numeric check rather than a String check, negatives could still sort out below, but I guess the conversion might cost more?
My first idea with SortedList in the comments was actually related to keeping the original sorted order, to be restored after the user has changed the sort, so was off the mark.
Edited to add: Just to clarify, it's the act of keeping the source list sorted that keeps the table list sorted.
public class TestApp extends Application {
private int c;
private ObservableList<TestTransaction> sortedOL;
private final Comparator<TestTransaction> comp = (TestTransaction a, TestTransaction b) -> {
if (a.getValue().contains("-") || b.getValue().contains("-")) {
return a.getValue().contains("-") ? 1 : -1;
}
return 0;
};
private TableView<TestTransaction> tableView;
#Override
public void start(Stage primaryStage) {
ArrayList<TestTransaction> rawList = new ArrayList<>();
for (int i = 1; i < 20; i++) {
int v = i * 3;
if (v % 2 > 0) {
v = v * -1;
}
c = i;
rawList.add(new TestTransaction(Integer.toString(v), "Item " + c));
}
sortedOL = FXCollections.observableArrayList(rawList);
sortedOL.addListener((ListChangeListener.Change<? extends TestTransaction> c1) -> {
if (c1.next() && (c1.wasAdded() || c1.wasRemoved())) {
FXCollections.sort(sortedOL, comp);
}
});
FXCollections.sort(sortedOL, comp);
tableView = new TableView<>(sortedOL);
TableColumn<TestTransaction,String> valCol = new TableColumn<>("Value");
valCol.setCellValueFactory(new PropertyValueFactory("value"));
TableColumn<TestTransaction,String> nameCol = new TableColumn<>("Name");
nameCol.setCellValueFactory(new PropertyValueFactory("name"));
tableView.getColumns().setAll(valCol, nameCol);
BorderPane tpane = new BorderPane();
Button btnAdd = new Button("Add");
btnAdd.setOnAction(a -> {addTransaction();});
ToolBar tb = new ToolBar(btnAdd);
tpane.setTop(tb);
tpane.setCenter(tableView);
tpane.setPrefSize(600, 600);
Scene scene = new Scene(tpane, 600, 600);
primaryStage.setTitle("Test");
primaryStage.setScene(scene);
primaryStage.show();
}
private void addTransaction() {
c++;
int v = (int) Math.floor(Math.random() * 50);
if (v % 2 > 0) {
v = v * -1;
}
sortedOL.add(new TestTransaction(Integer.toString(v), "New Item " + c));
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
public class TestTransaction {
private String value;
private String name;
public TestTransaction(String value, String name) {
this.value = value;
this.name = name;
}
/**
* #return the value
*/
public String getValue() {
return value;
}
/**
* #return the name
*/
public String getName() {
return name;
}
}
If you want to use SortedList, meaning you could inline the comparator:
sortedOL = FXCollections.observableArrayList(rawList);
SortedList sorted = new SortedList(sortedOL, comp);
tableView = new TableView<>(sorted);
I have a class called Result (data that I want to show in my table) with several attributes.
public class Result
{
private final SimpleStringProperty object;
private List<SimpleStringProperty> listObject= new ArrayList<SimpleStringProperty>();
private final Util util = new Util();
public Result(String object, String[] listObject)
{
this.object= new SimpleStringProperty(object);
this.objectList= util.transformar(listObject);
}
public String getObject()
{
return this.object.get();
}
public void setObject(String object)
{
this.hash.set(hash);
}
public String[] getListObject()
{
return util.transformar2(this.listObject);
}
public void setListObject(String[] listObject)
{
this.listObject= transformar(listObject);
}
}
And I have my controller where I have an empty table and I add the columns and the objetcs Result. The controller has the attribute:
#FXML
private TableView tablaResultado;
The method were I do that is:
private List<TableColumn> load()
{
List<TableColumn> listColumn = new ArrayList<TableColumn>();
Object2 object2= new Object2();
List<Result> listaResultado = object2.getResultado();
ObservableList<Result> prueba = FXCollections
.observableArrayList(listaResultado);
TableColumn<Result, String> object= new TableColumn<Result, String>("object");
direccion.setCellValueFactory(
new PropertyValueFactory<Result, String>(
"object"));
listColumn.add(object);
List<TableColumn<Result, String>> listObject = new ArrayList<TableColumn<Result, String>>();
for (int i = 0; i < ((Result) listaResultado
.get(0)).getListObject().length; i++)
{
TableColumn<Result, String> columna = new TableColumn<Result, String>(
this.lenguaje.getProperty("listObject"+i);
columna.setCellValueFactory(
new PropertyValueFactory<Result, String>(
"listObject[" + i + "]"));
objectList.add(columna);
}
listColumn.addAll(objectList);
ObservableList<TableColumn<Result, String>> prueba2 = FXCollections
.observableArrayList(listObject);
this.tablaResultado.setItems(prueba);
this.tablaResultado.getColumns().addAll(object);
for (int i = 0; i < prueba2.size(); i++)
{
this.tablaResultado.getColumns().addAll(prueba2.get(i));
}
}
return listColumn ;
The result is the columns with their names and the data in the column object but the data in the columns listObject is empty. It has to be a list or something because I don't know the size of listObject.
If I change:
columna.setCellValueFactory(new PropertyValueFactory<Result, String ("listObject[" + i + "]"));
and I write:
columna.setCellValueFactory(new PropertyValueFactory<Result, String ("listObject"));
I got something like Ljava.lang.String;#bda3303 in that columns.
Do
final int index = i ;
columna.setCellValueFactory(cellData ->
new SimpleStringProperty(cellData.getValue().getListObject()[index]));
PropertyValueFactory does not "evaluate" an expression. It just tries to access a property of the table item. The default TableCells will use the toString method to get the text to display, which is why you get something like Ljava.lang.String;#bda3303 in the third version, see Java arrays printing out weird numbers, and text .
However you can write your own cellValueFactory:
public class Result
public StringProperty listObjectProperty(int index) {
return listObject.get(index);
}
final int columnIndex = i;
columna.setCellValueFactory(cellData -> cellData.getValue().listObjectProperty(columnIndex));
Alternatively simply create a ObservableValue<String> with a constant value for the column value:
final int columnIndex = i;
columna.setCellValueFactory(cellData -> Bindings.createStringBinding(() -> cellData.getValue().getListObject()[columnIndex]));
I have creating this treetable
Now I want to sum up th children values and show the result in the parent cell under the related column. For example for Function 7 in column 2 and row 2 I want to right 2.0, and for Function 11 column 4 row 4 right 1.0 (function 12 + function 13)
Here is the code which produces the treetable.
root.setExpanded(true);
Set<String> combinedKeys = new HashSet<>(dc.getCombiFunc().keySet());
Set<String> funcAllKeys = new HashSet<>(dc.getSortedfuncAll().keySet());
funcAllKeys.removeAll(dc.getCombiFunc().keySet());
for (List<String> value : dc.getCombiFunc().values()) {
funcAllKeys.removeAll(value);
}
for (String valueremained : funcAllKeys) {
ArrayList<String> tempNameId = new ArrayList<>();
tempNameId.add(dc.getSortedfuncAll().get(valueremained));
// all elements which are not in combined functions (They are all
// orphan)
root.getChildren().add(new TreeItem<String>(tempNameId.get(0)));
}
// Getting Keys that have children//////
Set<String> keyFromcombined = new HashSet<>();
List<String> valueOfCombined = new ArrayList<String>();
for (Entry<String, List<String>> ent : dc.getCombiFunc().entrySet()) {
for (int i = 0; i < ent.getValue().size(); i++)
valueOfCombined.add(ent.getValue().get(i));
}
List<String> rootKeyList = new ArrayList<>();
for (String key : combinedKeys) {
if (!valueOfCombined.contains((key))) {
keyFromcombined.add(dc.getFuncAll().get(key));
rootKeyList.add(key);
}
}
String[] rootKeys = rootKeyList.toArray(new String[rootKeyList.size()]);
// ////////////////treetable////////////////////////////
treeTable.setRoot(root);
Arrays.stream(rootKeys).forEach(
rootKey -> root.getChildren().add(
createTreeItem(dc.getCombiFunc(), rootKey)));
// ////////////////First column/////////////////////////
TreeTableColumn<String, String> firstColumn = new TreeTableColumn<>("");
treeTable.getColumns().add(firstColumn);// Tree column
firstColumn.setPrefWidth(50);
firstColumn
.setCellValueFactory(new Callback<CellDataFeatures<String, String>, ObservableValue<String>>() {
public ObservableValue<String> call(
CellDataFeatures<String, String> p) {
return new ReadOnlyStringWrapper(p.getValue()
.getValue());
}
});
// //////////////////Rest Columns////////////////////////
for (Entry<String, String> ent : dc.getSortedAssignedOrg().entrySet()) {
TreeTableColumn<String, ArrayList<String>> col = new TreeTableColumn<>();
Label label = new Label(ent.getValue());
col.setGraphic(label);
label.setTooltip(new Tooltip(label.getText()));// tooltip for column
// headers
col.setPrefWidth(45);
// cell Value Factory////////////////////////
col.setCellValueFactory(new Callback<TreeTableColumn.CellDataFeatures<String, ArrayList<String>>, ObservableValue<ArrayList<String>>>() {
#Override
public ObservableValue<ArrayList<String>> call(
CellDataFeatures<String, ArrayList<String>> param) {
TreeMap<String, List<String>> temp = (TreeMap<String, List<String>>) dc
.getFuncTypeOrg().clone();
ArrayList<String> result = new ArrayList<>();
for (int i = 0; i < dc.getFuncTypeOrg().size(); i++) {
List<String> list = temp.firstEntry().getValue();
String key = temp.firstEntry().getKey();
if (list.get(1).equals(param.getValue().getValue())
&& !list.get(5).equals(label.getText())) {
result.add("white");
}
if (!root.isLeaf()) {
result.add("parent");
}
if (list.get(1).equals(param.getValue().getValue())
&& list.get(5).equals(label.getText())) {
result.add(0, list.get(2));// weight
if (list.size() > 6) {
result.add(1, list.get(list.size() - 1));// color
result.add(2, list.get(6));// App component
}
else
// result.add("white");
result.add("noOrg");
} else
temp.remove(key);
}
return new ReadOnlyObjectWrapper<ArrayList<String>>(result);
}
}); // end cell Value Factory
// //////////////cellfactory/////////////////////////
col.setCellFactory(new Callback<TreeTableColumn<String, ArrayList<String>>, TreeTableCell<String, ArrayList<String>>>() {
#Override
public TreeTableCell<String, ArrayList<String>> call(
TreeTableColumn<String, ArrayList<String>> param) {
return new TreeTableCell<String, ArrayList<String>>() {
public void updateItem(ArrayList<String> item,
boolean empty) {
super.updateItem(item, empty);
if (item == null || empty) {
setStyle("");
setText("");
} else if (item.contains("Green")) {
float weightInt = Float.parseFloat(item.get(0));
float res = weightInt * 1;
String resString = Float.toString(res);
this.setStyle("-fx-background-color:green");
setTooltip(new Tooltip(item.get(2)));
setText(resString);
} else if (item.contains("yellow")) {
this.setStyle("-fx-background-color:yellow");
setTooltip(new Tooltip(item.get(2)));
setText("0");
} else if (item.contains("white")) {
this.setStyle("-fx-background-color:linear-gradient(black, white); ");
// setText("DD");
} else if (item.contains("parent")) {
for (int i = 0; i < dc.getFuncTypeOrg().size(); i++) {
}
String text = param.getCellData(root).get(0);
// setText(text);
}
}
};
};
});// end cell factory
treeTable.getColumns().add(col);
}//end for loop col
TreeMap temp clones dc.getFuncTypeOrg(). In this TreeMap I have value for each child (color and the number). then in cellfactory i multiply value in color ( green = 1 and yellow = 0). Outside the loop I thought to make a treemap containg each parent as key and all it's children as value. Then I can sum up children values together and make a treemap in which first key is parent and as value the required value(or just string ArrayList ). After that I can check the name of cell in cellFactory and if it is a parent just right the value in the cell. I have been told how i can get treeitem values, and i am now here :
//after col loop ends
TreeMap<String, List<TreeItem<String>>> mytreemap = new TreeMap<>();
TreeMap<String, List<String>> parChild = new TreeMap<>();
for(TreeItem node: root.getChildren()){
if(!node.isLeaf())
mytreemap.put(node.getValue().toString(), node.getChildren());
}
for(Entry<String, List<TreeItem<String>>> ent: mytreemap.entrySet()){
for(TreeItem myItem : ent.getValue()){
// how can i fill parChild with parent as key and all its children as value?
System.out.println(ent.getKey()+" "+myItem.getValue());
}
}
treeTable.setPrefWidth(1200);
treeTable.setPrefHeight(500);
treeTable.setShowRoot(false);
treeTable.setTableMenuButtonVisible(true);
return treeTable; }
Here at setCellFactory
else if (item.contains("parent")) {
for (int i = 0; i < dc.getFuncTypeOrg().size(); i++) {
}
i can get the roots. Is there a way to do a recursion (up to the number of children and subchildren for that root cell) and add their value together and setText the parent cell to that value?
You can use onEditCommit method to add all childern values and show them in parent cell. For example
column1.setOnEditCommit((evt) -> {
//finalsing value of the cell
evt.getRowValue().getValue().setCellValue((evt.getNewValue()));
//Returns all the sibblings of the current cell
ObservableList<TreeItem> children = evt.getRowValue().getParent().getChildren();
int parentValue = 0;
for (TreeItem<> child : children) {
parentValue = parentValue + Integer.valueOf(child.getValue().getCellValue());
}
evt.getRowValue().getParent().getValue().setCellValue(parentValue);
});
I have following error in this code: Cannot infer type arguments for ReadOnlyListWrapper<>
How should my return type look like? I need to save arraylist for each node in all columns. But I can not return it.
for (Entry<String, String> ent : dc.getSortedOrgAll().entrySet()) {
TreeTableColumn<String, ArrayList<String>> col = new TreeTableColumn<>(
ent.getValue());
col.setCellValueFactory(new Callback<TreeTableColumn.CellDataFeatures<String, ArrayList<String>>, ObservableValue<ArrayList<String>>>() {
#Override
public ObservableValue<ArrayList<String>> call(
CellDataFeatures<String, ArrayList<String>> param) {
TreeMap<String, List<String>> temp = (TreeMap<String, List<String>>) dc
.getFuncTypeOrg().clone();
ArrayList<String> result = new ArrayList<>();
for (int i = 0; i < temp.size(); i++) {
List<String> list = temp.firstEntry().getValue();
String key = temp.firstEntry().getKey();
// root.getChildren();
if (list.get(1).equals("Papier")) {
System.out.println(list.get(1));
}
if (list.get(1).equals(param.getValue().getValue())
&& list.get(5).equals(col.getText())) {
result.add(list.get(2));
if(list.size()==9)
result.add(list.get(list.size()-1));
else result.add("White");
} else {
temp.remove(key);
// result = null;
}
}
return new ReadOnlyListWrapper<>(result);
}
});
ReadOnlyListWrapper<T> implements ObservableValue<ObservableList<T>>, which isn't what you need, as you declared the callback to return an ObservableValue<ArrayList<T>> (T is just String here).
So I think you just need
return new ReadOnlyObjectWrapper<ArrayList<String>>(result);
and you can probably omit the generic type:
return new ReadOnlyObjectWrapper<>(result);
Just a comment: I think you could make your life much easier by defining some actual data model classes, instead of trying to force your data into various collections implementations.
what I have done with a grid view is .. According to ma database i have added columns to the datatable and after that i binded it to a gridview.,
here is the code,
/// Get Activities here to bind to GridView To Get the Activities at first Column.
Dt = BlObj.BlDynamic_Table("[USP_DynamicGridView]", 2);
DtOperation = BlObj.BlDynamic_Table("[USP_DynamicGridView]", 1);
for (int i = 0; i < DtOperation.Rows.Count; i++)
{
Dt.Columns.Add(DtOperation.Rows[i][0].ToString());
}
dgrDynamic.DataSource = Dt;
dgrDynamic.DataBind();
but for me needed is to get the column index.. here is the code
private int GetColumnIndexByName(int p)
{
return ((int)GetColumnName(BlObj.BlDynamic_Table("[USP_DynamicGridView]",
4, p).ToString()));
}
private int GetColumnName(string name)
{
foreach (DataColumn col in dgrDynamic.Columns)
{
int Index = 0;
if(col.Equals(name.ToLower().Trim()))
// if (col.Name.ToLower().Trim() == name.ToLower().Trim())
{
return Index;
}
Index += 1;
}
return -1;
}
What the problem is the foreach loop is not working..
I'm a fresher to .NET and I also don't know whether I have followed the right way.. can anybody please help me?
Thanks in advance.
Here's how I did it:
private int GetColumnIndex(GridView gv, string columnName, int columnCount)
{
for (int i = 0; i < gv.Columns.Count; i++)
if (gv.Columns[i].HeaderText == columnName)
return i - columnCount + 1;
throw new Exception("no such column '" + columnName + "'");
}
It works in my codebase.
Use following Function to get Column Index:
private int GetColumnIndexByName(GridView grid, string name)
{
foreach (DataControlField col in grid.Columns)
{
if (col.HeaderText.ToLower().Trim() == name.ToLower().Trim())
{
return grid.Columns.IndexOf(col);
}
}
return -1;
}