I have a Factory class which contains a list of employees. I want to use a TreeTableView to display the Factory data. It is pretty forward to display the name and the size of a Factory, but i don't know how to display the employees names!
public class Factory {
private String name;
private double size;
private List<Employee> employees;
public Factory(name, size){this.name=name; this.size=size}
// Getters & setters
}
I want to have the following output:
With the possibilty to fold the factory.
In a TreeView or TreeTableView all nodes in the tree have to be of the same type. This makes the kind of design you want (which is very natural) something of a pain. Basically, you have to make the type of the TreeView or TreeTableView the most specific superclass of all the types of rows you want in the tree: i.e. in this case the type of the TreeTableView needs to be a superclass of both Employee and Factory. Then the cell value factories on the columns would have to type test the row objects to determine what value to return.
It would be unusual to have an object model in which these were related by inheritance other than both being subclasses of Object, so you probably need a TreeTableView<Object> here.
So roughly speaking (if you are using plain old JavaBean style, instead of the recommended JavaFX properties), you would define something like
TreeTableView<Object> treeTable = new TreeTableView<>();
treeTable.setShowRoot(false);
TreeTableColumn<Object, String> nameColumn = new TreeTableColumn<>("Name");
nameColumn.setCellValueFactory(cellData -> {
TreeItem<Object> rowItem = cellData.getValue();
if (rowItem != null && (rowItem.getValue() instanceof Factory)) {
Factory f = (Factory) rowItem.getValue() ;
return new SimpleStringProperty(f.getName());
} else {
return new SimpleStringProperty("");
}
});
TreeTableColumn<Object, Number> sizeColumn = new TreeTableColumn<>("Size");
sizeColumn.setCellValueFactory(cellData -> {
TreeItem<Object> rowItem = cellData.getValue();
if (rowItem != null && (rowItem.getValue() instanceof Factory)) {
Factory f = (Factory) rowItem.getValue() ;
return new SimpleObjectProperty<Number>(Double.valueOf(f.getSize()));
} else {
return new SimpleObjectProperty<Number>(null);
}
});
TreeTableColumn<Object, String> employeeColumn = new TreeTableColumn<>("Employee");
employeeColumn.setCellValueFactory(cellData -> {
TreeItem<Object> rowItem = cellData.getValue();
if (rowItem != null && (rowItem.getValue() instanceof Employee)) {
Employee emp = (Employee) rowItem.getValue() ;
return new SimpleStringProperty(emp.getName());
} else {
return new SimpleStringProperty("");
}
});
treeTable.getColumns().addAll(nameColumn, sizeColumn, employeeColumn);
and of course you populate it with
// fully initialized list of factories, with employee lists initialized:
List<Factory> factories = ... ;
TreeItem<Object> root = new TreeItem<>(null);
for (Factory factory : factories) {
TreeItem<Object> factoryItem = new TreeItem<>(factory);
root.getChildren().add(factoryItem);
for (Employee emp : factory.getEmployees()) {
TreeItem<Object> employeeItem = new TreeItem<>(emp);
factoryItem.getChildren().add(employeeItem);
}
}
treeTable.setRoot(root);
Here's a simple SSCCE using this:
import java.util.ArrayList;
import java.util.List;
import javafx.application.Application;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.scene.Scene;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeTableColumn;
import javafx.scene.control.TreeTableView;
import javafx.stage.Stage;
public class TreeTableExample extends Application {
#Override
public void start(Stage primaryStage) {
TreeTableView<Object> treeTable = new TreeTableView<>();
treeTable.setShowRoot(false);
TreeTableColumn<Object, String> nameColumn = new TreeTableColumn<>("Name");
nameColumn.setCellValueFactory(cellData -> {
TreeItem<Object> rowItem = cellData.getValue();
if (rowItem != null && (rowItem.getValue() instanceof Factory)) {
Factory f = (Factory) rowItem.getValue() ;
return new SimpleStringProperty(f.getName());
} else {
return new SimpleStringProperty("");
}
});
TreeTableColumn<Object, Number> sizeColumn = new TreeTableColumn<>("Size");
sizeColumn.setCellValueFactory(cellData -> {
TreeItem<Object> rowItem = cellData.getValue();
if (rowItem != null && (rowItem.getValue() instanceof Factory)) {
Factory f = (Factory) rowItem.getValue() ;
return new SimpleObjectProperty<Number>(Double.valueOf(f.getSize()));
} else {
return new SimpleObjectProperty<Number>(null);
}
});
TreeTableColumn<Object, String> employeeColumn = new TreeTableColumn<>("Employee");
employeeColumn.setCellValueFactory(cellData -> {
TreeItem<Object> rowItem = cellData.getValue();
if (rowItem != null && (rowItem.getValue() instanceof Employee)) {
Employee emp = (Employee) rowItem.getValue() ;
return new SimpleStringProperty(emp.getName());
} else {
return new SimpleStringProperty("");
}
});
treeTable.getColumns().addAll(nameColumn, sizeColumn, employeeColumn);
List<Factory> factories = createData();
TreeItem<Object> root = new TreeItem<>(null);
for (Factory factory : factories) {
TreeItem<Object> factoryItem = new TreeItem<>(factory);
root.getChildren().add(factoryItem);
for (Employee emp : factory.getEmployees()) {
TreeItem<Object> employeeItem = new TreeItem<>(emp);
factoryItem.getChildren().add(employeeItem);
}
}
treeTable.setRoot(root);
Scene scene = new Scene(treeTable, 800, 800);
primaryStage.setScene(scene);
primaryStage.show();
}
private List<Factory> createData() {
String[][] empNames = {
{"John", "Jane", "Mary"},
{"Susan", "Mike"},
{"Alex", "Francois", "Joanne"}
};
List<Factory> factories = new ArrayList<>();
for (String[] emps : empNames) {
int count = factories.size()+1 ;
Factory f = new Factory("Factory "+ count, count*10);
for (String empName : emps) {
f.getEmployees().add(new Employee(empName));
}
factories.add(f);
}
return factories ;
}
public static class Employee {
private String name ;
public Employee(String name) {
this.name = name ;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class Factory {
private String name ;
private double size ;
private List<Employee> employees ;
public Factory(String name, double size) {
this.name = name ;
this.size = size ;
this.employees = new ArrayList<>();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getSize() {
return size;
}
public void setSize(double size) {
this.size = size;
}
public List<Employee> getEmployees() {
return employees;
}
}
public static void main(String[] args) {
launch(args);
}
}
Another approach, which I think is a bit artificial, is to create a class representing the row in the table view, and then to make Factory and Employee subclasses of it:
public abstract class EmploymentEntity {
public String getName() {
return null ;
}
public Double getSize() {
return null ;
}
public String getEmployeeName {
return null ;
}
}
then
public class Employee extends EmploymentEntity {
private String name ;
public Employee(String name) {
this.name = name ;
}
#Override
public String getEmployeeName() {
return name ;
}
public void setEmployeeName(String name) {
this.name = name ;
}
}
and
public class Factory extends EmploymentEntity {
private String name ;
private double size ;
private List<Employee> employees ;
public Factory(String name, double size) {
this.name = name ;
this.size = size ;
this.employees = new ArrayList<>();
}
#Override
public String getName() {
return name ;
}
public void setName(String name) {
this.name = name ;
}
#Override
public Double getSize() {
return size ;
}
public void setSize(double size) {
this.size = size ;
}
public List<Employee> getEmployees() {
return employees ;
}
}
This object model is really unnatural (to me, anyway), but it does make the table a little easier:
TreeTableView<EmploymentEntity> treeTable = new TreeTableView<>();
TreeTableColumn<EmploymentEntity, String> nameColumn = new TreeTableColumn<>("Name");
nameColumn.setCellValueFactory(cellData -> new SimpleStringProperty(cellData.getValue().getValue().getName()));
TreeTableColumn<EmploymentEntity, Number> sizeColumn = new TreeTableColumn<>("Size");
sizeColumn.setCellValueFactory(cellData -> new SimpleObjectProperty<Number>(cellData.getValue().getValue().getSize()));
TreeTableColumn<EmploymentEntity, String> employeeColumn = new TreeTableColumn<>("Employee");
employeeColumn.setCellValueFactory(cellData -> new SimpleStringProperty(cellData.getValue().getValue().getEmployeeName()));
// etc...
Related
I'm trying to add static methods largest and smallest to the Measurable interface.
The methods should return the object with the largest or smallest measure (double) from an array of Measurable Country objects. I tried doing so in the interface, but someone recommended me using the Comparator interface. How can this be done by using the Measurable interface instead?
class Main {
public static void main(String args[]) {
Measurable[] countries = new Measurable[3];
countries[0] = new Country("Uruguay", 176220);
countries[1] = new Country("Thailand", 514000);
countries[2] = new Country("Belgium", 30510);
Measurable maximum = Measurable.largest(countries);
Measurable smallest = Measurable.smallest(countries);
}
}
class Country implements Measurable {
private String name;
private double area;
public Country(String name, double area) {
this.name = name;
this.area = area;
}
}
interface Measurable {
static Measurable largest(Measurable[] countries) {
public static Measurable largest(Measurable[]objects){
if (objects == null || objects.length == 0) {
return new Country("", 0);
}
Measurable max = new Country("", 0);
for (Measurable obj : objects) {
if (obj.getMeasure() > max.getMeasure()) {
max = obj;
}
}
return max;
}
}
static Measurable smallest(Measurable[] objects) {
if (objects == null || objects.length == 0) {
return new Country("", 0);
}
Measurable max = new Country("", 0);
for (Measurable obj : objects) {
if (obj.getMeasure() < min.getMeasure()) {
min = obj;
}
}
return min;
}
}
double getMeasure();
}
You don't need to create the Measurable interface if you want to use Comparator/Comparable.
Just implement Comparable in Country and then loop through the array to find min and max.
class Main {
public static void main(String args[]) {
Country[] countries = new Country[3];
countries[0] = new Country("Uruguay", 176220);
countries[1] = new Country("Thailand", 514000);
countries[2] = new Country("Belgium", 30510);
Country max = null;
Country min = null;
for (Country c : countries) {
if (max == null || max.compareTo(c) < 0) {
max = c;
}
if (min == null || min.compareTo(c) > 0) {
min = c;
}
}
System.out.printf("max: %s (%s)%n", max.name, max.area);
System.out.printf("min: %s (%s)%n", min.name, min.area);
}
}
class Country implements Comparable<Country> {
String name;
double area;
public Country(String name, double area) {
this.name = name;
this.area = area;
}
#Override
public int compareTo(Country other) {
// Returns int <0 if this is smaller than other
// 0 if they are equal
// int >0 if this is greater than other
return Double.compare(this.area, other.area);
}
}
If you put your countries in a collection you can use the Collections.min() and Collections.max() functions together with the Comparable interface. Your main method would then look like this:
public static void main(String args[]) {
List<Country> countries = new ArrayList<>();
countries.add(new Country("Uruguay", 176220));
countries.add(new Country("Thailand", 514000));
countries.add(new Country("Belgium", 30510));
Country max = Collections.max(countries);
Country min = Collections.min(countries);
System.out.printf("max: %s (%s)%n", max.name, max.area);
System.out.printf("min: %s (%s)%n", min.name, min.area);
}
If you still want to use the Measurable interface you can extend ArrayList and have that class implement it like this:
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
class Main {
public static void main(String args[]) {
CountryList countries = new CountryList();
countries.add(new Country("Uruguay", 176220));
countries.add(new Country("Thailand", 514000));
countries.add(new Country("Belgium", 30510));
Country max = countries.getLargest();
Country min = countries.getSmallest();
System.out.printf("max: %s (%s)%n", max.name, max.area);
System.out.printf("min: %s (%s)%n", min.name, min.area);
}
}
class CountryList extends ArrayList<Country> implements Measurable{
#Override
public Country getSmallest() {
return Collections.min(this);
}
#Override
public Country getLargest() {
return Collections.max(this);
}
}
interface Measurable{
Country getSmallest();
Country getLargest();
}
class Country implements Comparable<Country> {
String name;
double area;
public Country(String name, double area) {
this.name = name;
this.area = area;
}
#Override
public int compareTo(Country o) {
return Double.compare(this.area, o.area);
}
}
I have a small class with some data, called MyData:
public class MyData {
public String name = "";
public String nameonly = "";
public int id = 0;
public double earn = 0;
public double paid = 0;
....
public MyData(String name, String nameonly, int id) {
this.name = name;
this.nameonly = nameonly;
this.id = id;
}
}
Then I have a class with arrays of this class for specific type of people called AllMyData:
public class AllMyData {
public ArrayList<MyData> cli = new ArrayList<>();
public ArrayList<MyData> sub = new ArrayList<>();
public ArrayList<MyData> emp = new ArrayList<>();
public ArrayList<MyData> exp = new ArrayList<>();
public ArrayList<MyData> oex = new ArrayList<>();
public ArrayList<MyData> bin = new ArrayList<>();
public ArrayList<MyData> ven = new ArrayList<>();
....
}
in main class I need to add new items to specific array (if id does not exists) where I have a string representative of AllMyData array
public AllMyData elems = new AllMyData();
public void initArray(int id, String name, String tip) {
//this is an example just for "cli" element and "cli" is in String tip
if (!checkForId(elems.cli, id)) {
MyData element = new MyData(name, name, id);
elems.cli.add(element);
}
}
private boolean checkForId(ArrayList<MyData> a, int id) {
for (MyData e : a) {
if (e.id == id) return true;
}
return false;
}
Then I need just a call, for example:
initArray(5, "Test", "emp");
and would like to avoid switch statement and to repeat code for every single type. In this call, "emp" would be element elems.emp
Is there a way to access elems member with a string name instead of creating switch statement?
Create a map of lists in AllMyData instead.
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
AllMyData data = new AllMyData();
data.add("foo", new MyData("Hello World", "", 1));
data.add("cli", Arrays.asList(new MyData("BASH", "", 2), new MyData("SHELL", "", 3)));
System.out.println(data);
}
}
AllMyData [map={cli=[MyData [name=BASH, nameonly=, id=2, earn=0.0, paid=0.0], MyData [name=SHELL, nameonly=, id=3, earn=0.0, paid=0.0]], sub=[], oex=[], bin=[], foo=[MyData [name=Hello World, nameonly=, id=1, earn=0.0, paid=0.0]], emp=[], exp=[], ven=[]}]
import java.util.*;
public class AllMyData {
private Map<String, List<MyData>> map;
public AllMyData() {
map = new HashMap<String, List<MyData>>();
map.put("cli", new ArrayList<>());
map.put("sub", new ArrayList<>());
map.put("emp", new ArrayList<>());
map.put("exp", new ArrayList<>());
map.put("oex", new ArrayList<>());
map.put("bin", new ArrayList<>());
map.put("ven", new ArrayList<>());
}
public void add(String key, List<MyData> data) {
List<MyData> list = get(key);
if (list == null) {
map.put(key, data);
} else {
list.addAll(data);
map.put(key, list);
}
}
public void add(String key, MyData data) {
List<MyData> list = get(key);
if (list == null) {
list = new ArrayList<>();
}
list.add(data);
map.put(key, list);
}
public List<MyData> get(String key) {
return map.get(key);
}
#Override
public String toString() {
return String.format("AllMyData [map=%s]", map);
}
}
public class MyData {
public String name = "";
public String nameonly = "";
public int id = 0;
public double earn = 0;
public double paid = 0;
public MyData(String name, String nameonly, int id) {
this.name = name;
this.nameonly = nameonly;
this.id = id;
}
#Override
public String toString() {
return String.format("MyData [name=%s, nameonly=%s, id=%s, earn=%s, paid=%s]", name, nameonly, id, earn, paid);
}
}
Consider the use of a Map from String to ArrayList.
It would look like this:
Map> allMyData = new HashMap<>();
I have a JTable in which I have the operations of several customer accounts.
I want to calculate the cumulative balance with each operation and this for each account. In my JTable I have a column (of type string) in which there is a list of accounts, another column (of type int) in which there is the amount of operations.
How will I be able to retrieve the list of accounts and calculate the cumulative balance of transactions for each account?
I have a solution of my problems
int nombreDeLignes = model.getRowCount();
double cumul=0;
String numcompte=null; // une valeur qui n'existe nulle part
for(int i=0; i<nombreDeLignes; i++) {
String numcompteLigne = model.getValueAt(i, 4).toString();
if ( numcompte==null || !numcompte.equals(numcompteLigne) ) {
numcompte = numcompteLigne;
cumul=0;
}
cumul+= (int) model.getValueAt(i, 5);
model.setValueAt(cumul, i, 9);
}
Here is a code to create Consolidate the Data and create SubTotal
public enum AggregatorType {
SUM, AVG, DISPLAY, LABEL
}
public class DataRow {
private final Object[] values;
private final boolean totalRow;
public DataRow(Object[] values, boolean totalRow) {
this.values = values;
this.totalRow = totalRow;
}
public Object[] getValues() {
return values;
}
public boolean isTotalRow() {
return totalRow;
}
public static Object[] getvalues(Object obj) {
if (obj instanceof DataRow) {
return ( (DataRow) obj).getValues() ;
} else if (obj instanceof Object[]) {
return (Object[]) obj;
} else {
return new Object[] { obj};
}
}
}
public class Aggregator {
private final int column;
private final String prefix;
private final String subfix;
private final AggregatorType type;
public Aggregator( int column,AggregatorType type)
{
this(column,type,null);
}
public Aggregator( int column,AggregatorType type,String prefix)
{
this(column,type,prefix,null);
}
public Aggregator( int column,AggregatorType type,String prefix,String subfix)
{
this.column=column;
this.type=type;
this.prefix=prefix;
this.subfix=subfix;
}
public int getColumn() {
return column;
}
public AggregatorType getType() {
return type;
}
public Object aggregate( List<?> objects) {
Object object = null;
switch(this.type) {
case SUM : object = total(objects); break;
case AVG : object = avg(objects); break;
case LABEL: object = ""; break;
default: object = display(objects); break;
}
if( object != null && ( prefix != null || subfix != null )) {
return ( prefix == null ? "" : prefix.toString() ) +
object.toString() +
( subfix == null ? "" : subfix.toString() );
} else {
return object;
}
}
public Object display( List<?> objects) {
return DataRow.getvalues(objects.get(0))[column];
}
public Object total( List<?> objects) {
double total = 0.0;
for( Object object : objects ) {
Object[] objA = DataRow.getvalues(object);
Object value = objA[column];
if( value instanceof Number ) {
total += ( ( Number ) value ).doubleValue();
}
}
return total;
}
public Object avg( List<?> objects) {
double total = 0.0;
int count = 0;
for( Object object : objects ) {
Object[] objA = DataRow.getvalues(object);
Object value = objA[column];
if( value instanceof Number ) {
total += ( ( Number ) value ).doubleValue();
count++;
}
}
return count > 0 ? ( total / count ) : 0.0;
}
}
import java.util.List;
public class SubTotalCreator {
private final int columnIndex;
private final boolean grandTotal;
private final List<Aggregator> aggregatorList;
public SubTotalCreator(int index, List<Aggregator> aggregatorList) {
this(index, false, aggregatorList);
}
public SubTotalCreator(int index, boolean grandTotal, List<Aggregator> aggregatorList) {
this.aggregatorList = aggregatorList;
this.columnIndex = index;
this.grandTotal = grandTotal;
}
public boolean canCreateSubTotal(Object[] object1, Object[] object2) {
return !object1[columnIndex].equals(object2[columnIndex]);
}
public Object[] createSubTotal(List<?> subList) {
Object[] obj = DataRow.getvalues(subList.get(0));
int length = obj.length;
Object[] subtotal = new Object[length];
for (Aggregator aggregator : aggregatorList) {
Object value = aggregator.aggregate(subList);
subtotal[aggregator.getColumn()] = value;
}
return subtotal;
}
public int getColumnIndex() {
return columnIndex;
}
public boolean isGrandTotal() {
return grandTotal;
}
public List<Aggregator> getAggregatorList() {
return aggregatorList;
}
}
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
public class Consolidator {
private final List<SubTotalCreator> list;
private final Comparator<Object[]> comparator;
private List<Object[]> objects;
private List<DataRow> rows;
public Consolidator(Comparator<Object[]> comparator, List<SubTotalCreator> list) {
this.comparator = comparator;
this.list = list;
}
public List<Object[]> getSummary() {
List<Object[]> list = new ArrayList<>();
for (int index = 0; index < rows.size(); index++) {
DataRow row = rows.get(index);
if (row.isTotalRow()) {
list.add(row.getValues());
}
}
return list;
}
public Object[][] getAllRowAsArray() {
Object[][] list =new Object[rows.size()][];
for (int index = 0; index < rows.size(); index++) {
DataRow row = rows.get(index);
list[index]=row.getValues();
}
return list;
}
public List<Object[]> getAllRows() {
List<Object[]> list = new ArrayList<>();
for (int index = 0; index < rows.size(); index++) {
DataRow row = rows.get(index);
list.add(row.getValues());
}
return list;
}
public List<Object[]> getObjects() {
return objects;
}
public List<DataRow> getRows() {
return rows;
}
public void setObjects(Object[][] objects) {
List<Object[]> list = new ArrayList<>();
for (int index = 0; index < objects.length; index++) {
list.add(objects[index]);
}
setObjects(list);
}
public void setObjects(List<Object[]> objects) {
this.objects = objects;
}
private void createDataRow() {
List<DataRow> list = new ArrayList<>();
for (int index = 0; index < objects.size(); index++) {
list.add(new DataRow(objects.get(index), false));
}
this.rows = list;
}
public void consolidate() {
objects.sort(comparator);
createDataRow();
computeSubTotal();
computeGrandTotal();
}
public void computeSubTotal() {
for (SubTotalCreator creator : list) {
if (!creator.isGrandTotal()) {
computeSubTotal(creator);
}
}
}
public void computeGrandTotal() {
for (SubTotalCreator creator : list) {
if (creator.isGrandTotal()) {
computeSubTotal(creator);
}
}
}
public void computeSubTotal(SubTotalCreator creator) {
List<?> list = null;
if (!creator.isGrandTotal()) {
ArrayList<DataRow> subList = new ArrayList<DataRow>();
DataRow prevDataRow = null;
for (int index = 0; index < rows.size(); index++) {
DataRow dataRow = rows.get(index);
if (dataRow.isTotalRow())
continue;
if (prevDataRow != null) {
boolean flag = creator.canCreateSubTotal(prevDataRow.getValues(), dataRow.getValues());
if (flag) {
DataRow subTotal = new DataRow(creator.createSubTotal(subList), true);
rows.add(index, subTotal);
subList.clear();
index++;
}
}
subList.add(dataRow);
prevDataRow = dataRow;
}
list = subList;
} else {
list = objects;
}
DataRow subTotal = new DataRow(creator.createSubTotal(list), true);
rows.add(subTotal);
}
public static void print(Object[][] objects) {
for (Object[] objA : objects) {
System.out.println(Arrays.asList(objA));
}
}
public static void print(List<Object[]> objects) {
for (Object[] objA : objects) {
System.out.println(Arrays.asList(objA));
}
}
public static void main(String[] str) {
Object[][] accountDetails = new Object[][] { { "Abhi", 20 }, { "Abhi", 200 }, { "Sekar", 100 }, { "Abhi", 45 },
{ "Sekar", 120 }, { "Abhi", 35 }, { "Abhi", 40 }, { "Sekar", 500 } };
Comparator<Object[]> comparator = new Comparator<Object[]>() {
public int compare(Object[] obj1, Object[] obj2) {
return ((String) obj1[0]).compareTo((String) obj2[0]);
}
};
List<SubTotalCreator> list = new ArrayList<SubTotalCreator>();
List<Aggregator> aggregatorList = new ArrayList<Aggregator>();
aggregatorList.add(new Aggregator(0, AggregatorType.DISPLAY, null, " 's Total"));
aggregatorList.add(new Aggregator(1, AggregatorType.SUM));
SubTotalCreator creator = new SubTotalCreator(0, aggregatorList);
list.add(creator);
List<Aggregator> grandAggList = new ArrayList<Aggregator>();
grandAggList.add(new Aggregator(0, AggregatorType.LABEL, "Grand Total"));
grandAggList.add(new Aggregator(1, AggregatorType.SUM));
SubTotalCreator creator2 = new SubTotalCreator(0, true, grandAggList);
list.add(creator2);
Consolidator consolidator = new Consolidator(comparator, list);
consolidator.setObjects(accountDetails);
System.out.println("Before Consolidate ");
print(consolidator.getObjects());
consolidator.consolidate();
System.out.println("After Consolidate ");
print(consolidator.getAllRows());
System.out.println("After Consolidate Summary Alone ");
print(consolidator.getSummary());
JFrame frame = new JFrame("test");
JTable table = new JTable( consolidator.getAllRowAsArray(),new String[] {"Name" ,"Amount"});
frame.getContentPane().add( new JScrollPane(table),BorderLayout.CENTER);
frame.setSize( 400,400);
frame.setVisible( true);
}
}
Anybody help me? I want to change row color in TableView depending on value.
For example: i want to change row color to green color when value in column colType is equal to "good"
This is my method where Im filling TableView with data from database:
public void setCustomers() {
List<Customer> list = customer.getTable(); //getting results from database
data = FXCollections.observableArrayList();
Integer count = 1;
for (Customer customer1 : list) {
data.add(new CustomerObj(count++, customer1.getId(), customer1.getName(),
form.formatDate(customer1.getBorn().toString()), customer1.getStreet(),
customer1.getCity(), customer1.getIdCustomerType().getPhrase()));
}
tblCustomer.setItems(data);
tblCustomer.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
colID.setCellValueFactory(cell -> cell.getValue().getPropertyId());
colName.setCellValueFactory(cell -> cell.getValue().getPropertyName());
colBorn.setCellValueFactory(cell -> cell.getValue().getPropertyBorn());
colAddr.setCellValueFactory(cell -> cell.getValue().getPropertyAddr());
colCity.setCellValueFactory(cell -> cell.getValue().getPropertyCity());
colType.setCellValueFactory(cell -> cell.getValue().getPropertyType());
rowOptions.setCellValueFactory(new PropertyValueFactory<>("Button"));
editCust(); //just filling TableCell with Button
rowOptions1.setCellValueFactory(new PropertyValueFactory<>("Button"));
deleteCust(); //just filling TableCell with Button
}
And this is the CustomerObj class:
package sk.evka.fp.obj;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
public class CustomerObj {
private SimpleIntegerProperty id;
private SimpleIntegerProperty idDB;
private SimpleStringProperty name;
private SimpleStringProperty born;
private SimpleStringProperty addr;
private SimpleStringProperty city;
private SimpleStringProperty type;
public CustomerObj(Integer i, Integer id, String n, String b, String a, String c, String t) {
this.id = new SimpleIntegerProperty(i);
this.idDB = new SimpleIntegerProperty(id);
this.name = new SimpleStringProperty(n);
this.born = new SimpleStringProperty(b);
this.addr = new SimpleStringProperty(a);
this.city = new SimpleStringProperty(c);
this.type = new SimpleStringProperty(t);
}
public Integer getId() {
return id.get();
}
public Integer getIdDB() {
return idDB.get();
}
public String getName() {
return name.get();
}
public String getBorn() {
return born.get();
}
public String getAddr() {
return addr.get();
}
public String getCity() {
return city.get();
}
public String getType() {
return type.get();
}
public void setId(Integer i) {
this.id = new SimpleIntegerProperty(i);
}
public void setIdDB(Integer i) {
this.idDB = new SimpleIntegerProperty(i);
}
public void setName(String n) {
name = new SimpleStringProperty(n);
}
public void setBorn(String b) {
born = new SimpleStringProperty(b);
}
public void setAddr(String a) {
addr = new SimpleStringProperty(a);
}
public void setCity(String c) {
city = new SimpleStringProperty(c);
}
public void setType(String t) {
type = new SimpleStringProperty(t);
}
public SimpleIntegerProperty getPropertyId() {
return id;
}
public SimpleIntegerProperty getPropertyIdDB() {
return idDB;
}
public SimpleStringProperty getPropertyName() {
return name;
}
public SimpleStringProperty getPropertyBorn() {
return born;
}
public SimpleStringProperty getPropertyAddr() {
return addr;
}
public SimpleStringProperty getPropertyCity() {
return city;
}
public SimpleStringProperty getPropertyType() {
return type;
}
public void setPropertyId(SimpleIntegerProperty i) {
this.id = i;
}
public void setPropertyIdDB(SimpleIntegerProperty i) {
this.idDB = i;
}
public void setPropertyName(SimpleStringProperty n) {
name = n;
}
public void setPropertyBorn(SimpleStringProperty b) {
born = b;
}
public void setPropertyAddr(SimpleStringProperty a) {
addr = a;
}
public void setPropertyCity(SimpleStringProperty c) {
city = c;
}
public void setPropertyType(SimpleStringProperty t) {
type = t;
}
}
i havent found an answer to this nowhere.
If you want to color the whole row, use a rowFactory that changes the color of the TableRows it creates according to item property.
Furthermore you better use JavaFX properties appropriately:
Properties are not meant to be replaced themselfs. The property getter should always return the same property instance or at least instances that store listeners in a common data structure; Otherwise the value could be modified without the possibility of being notified of that fact (replacing the property with a property containing a new value).
public static class Item {
// property only assigned once
private final StringProperty type;
public Item(String type) {
this.type = new SimpleStringProperty(type);
}
// getter for value wrapped in property
public final String getType() {
return this.type.get();
}
// setter for value wrapped in property
public final void setType(String value) {
this.type.set(value);
}
// property getter
public final StringProperty typeProperty() {
return this.type;
}
}
public static Color typeToColor(String type) {
if (type == null) {
return Color.WHITESMOKE;
}
switch (type) {
case "bad":
return Color.RED;
case "good":
return Color.LIME;
default:
return Color.WHITESMOKE;
}
}
TableView<Item> table = new TableView<>(FXCollections.observableArrayList(
new Item("ok"),
new Item("bad"),
new Item("good")));
TableColumn<Item, String> typeColumn = new TableColumn<>("type");
typeColumn.setCellValueFactory(new PropertyValueFactory<>("type"));
table.setRowFactory(tv -> {
TableRow<Item> row = new TableRow<>();
StringBinding typeBinding = Bindings.selectString(row.itemProperty(), "type");
row.backgroundProperty().bind(Bindings.createObjectBinding(()
-> new Background(new BackgroundFill(typeToColor(typeBinding.get()), CornerRadii.EMPTY, Insets.EMPTY)), typeBinding));
return row;
});
table.getColumns().add(typeColumn);
Finally I have done this thing:
Callback<TableColumn<CustomerObj, String>, TableCell<CustomerObj, String>> cellFactory
= new Callback<TableColumn<CustomerObj, String>, TableCell<CustomerObj, String>>() {
public TableCell call(TableColumn p) {
TableCell cell = new TableCell<CustomerObj, String>() {
#Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (!empty) {
CustomerObj obj = this.getTableView().getItems().get(getIndex());
setText(obj.getType());
switch (obj.getType()) {
case "good":
setStyle("-fx-background-color: rgba(71, 209, 71, .7)");
break;
case "problem":
setStyle("-fx-background-color: rgba(255, 51, 51, .7)");
break;
case "ViP":
setStyle("-fx-background-color: rgba(255, 219, 25 .7)");
break;
default:
break;
}
} else {
setText(null);
}
}
private String getString() {
return getItem() == null ? "" : getItem().toString();
}
};
return cell;
}
};
colType.setCellFactory(cellFactory);
Works fine and looks so much better, but thanks it brought me closer to the solution.
Here is the thing: I have an application to manage user's tickets.
I have 2 basic classes : Ticket and User.
Using GXT I have some ColumnConfig class like this:
ColumnConfig<TicketProxy, String> dateColumn = new ColumnConfig<TicketProxy, String>(
new ValueProvider<TicketProxy, String>() {
public String getValue(TicketProxy object) {
Date initialDate = object.getInitialDate();
String date = "";
if (initialDate != null) {
date = dtFormat.format(initialDate);
}
return date;
}
public void setValue(TicketProxy object, String initialDate) {
if (object instanceof TicketProxy) {
object.setInitialDate(dtFormat.parse(initialDate));
}
}
public String getPath() {
return "initialDate";
}
}, 70, "Date");
columnsChamado.add(dateColumn);
but I want to get some data from UserProxy class, some like this:
ColumnConfig<UserProxy, String> userRoomColumn = new ColumnConfig<UserProxy, String>(
new ValueProvider<UserProxy, String>() {
public String getValue(UserProxy object) {
String userRoom = object.getUserRoom();
String room = "";
if (userRoom != null) {
room = userRoom;
}
return room;
}
public void setValue(UserProxy object, String userRoom) {
if (object instanceof UserProxy) {
object.setUserRoom(userRoom);
}
}
public String getPath() {
return "userRoom";
}
}, 70, "User's Room");
columnsChamado.add(userRoomColumn);
But GWT doesn't allow me to change the "Proxy" parameter to another class in the same ColumnConfig.
How can I get data from other Proxy class in this ColumnConfig?
I use GXT 3.0 (Sencha) + Hibernate.
Proxy classes:
BaseEntityProxy:
package com.acme.ccc.shared;
import com.acme.ccc.server.locator.CCCLocator;
import com.acme.db.base.DatabaseObject;
import com.google.web.bindery.requestfactory.shared.EntityProxy;
import com.google.web.bindery.requestfactory.shared.ProxyFor;
import com.google.web.bindery.requestfactory.shared.SkipInterfaceValidation;
#SkipInterfaceValidation
#ProxyFor(value = DatabaseObject.class, locator = CCCLocator.class)
public interface BaseEntityProxy extends EntityProxy {
Long getId();
Long getVersion();
void setId(Long id);
void setVersion(Long version);
}
TicketProxy:
package com.acme.ccc.shared.entityproxy;
import java.util.Date;
import java.util.List;
import com.acme.ccc.db.Ticket;
import com.acme.ccc.server.locator.CCCLocator;
import com.acme.ccc.shared.BaseEntityProxy;
import com.google.web.bindery.requestfactory.shared.ProxyFor;
#ProxyFor(value = Ticket.class, locator = CCCLocator.class)
public interface TicketProxy extends BaseEntityProxy {
Date getPrazo();
void setPrazo(Date prazo);
TicketTipoProxy getTicketTipo();
void setTicketTipo(TicketTipoProxy chamadoTipo);
CanalOrigemProxy getCanalOrigem();
void setCanalOrigem(CanalOrigemProxy canalOrigem);
UserProxy getUser();
void setUser(UserProxy user);
CategoriaProxy getPedidoTipo();
void setPedidoTipo(CategoriaProxy pedidoTipo);
Date getInitialDate();
void setInitialDate(Date dt);
Long getTotal();
void setTotal(Long total);
}
UserProxy:
package com.acme.ccc.shared.entityproxy;
import java.util.List;
import com.acme.ccc.db.User;
import com.acme.ccc.server.locator.CCCLocator;
import com.acme.ccc.shared.BaseEntityProxy;
import com.google.web.bindery.requestfactory.shared.ProxyFor;
#ProxyFor(value = User.class, locator = CCCLocator.class)
public interface UserProxy extends BaseEntityProxy {
String getName();
String getUserRoom();
Long getTotal();
void setName(String name);
void setUserRoom(Sting room)
void setTotal(Long total);
}
An gxt grid is able to show the data only of one data type. If you put a single TicketProxy row, how do you expect to access a user object?
If you want to display both Tickets and Users independently (so a row is either a Ticket OR a User), you have to use BaseEntityProxy in your Grid: Grid<BaseEntityProxy>. Then you can define your columns as ColumnConfig<BaseEntityProxy, ?> and check the type within your getters and setter:
List<ColumnConfig<BaseEntityProxy, ?>> columnsChamado = new ArrayList<ColumnConfig<BaseEntityProxy, ?>>();
ColumnConfig<BaseEntityProxy, String> dateColumn = new ColumnConfig<BaseEntityProxy, String>(
new ValueProvider<BaseEntityProxy, String>() {
private final DateTimeFormat dtFormat = DateTimeFormat.getFormat(DateTimeFormat.PredefinedFormat.DATE_FULL);
public String getValue(BaseEntityProxy object) {
Date initialDate = ((TicketProxy) object).getInitialDate();
String date = "";
if (initialDate != null) {
date = dtFormat.format(initialDate);
}
return date;
}
public void setValue(BaseEntityProxy object, String initialDate) {
if (object instanceof TicketProxy) {
((TicketProxy) object).setInitialDate(dtFormat.parse(initialDate));
}
}
public String getPath() {
return "initialDate";
}
}, 70, "Date");
columnsChamado.add(dateColumn);
ColumnConfig<BaseEntityProxy, String> userRoomColumn = new ColumnConfig<BaseEntityProxy, String>(
new ValueProvider<BaseEntityProxy, String>() {
public String getValue(BaseEntityProxy object) {
String userRoom = ((UserProxy)object).getUserRoom();
String room = "";
if (userRoom != null) {
room = userRoom;
}
return room;
}
public void setValue(BaseEntityProxy object, String userRoom) {
if (object instanceof UserProxy) {
((UserProxy)object).setUserRoom(userRoom);
}
}
public String getPath() {
return "userRoom";
}
}, 70, "User's Room");
columnsChamado.add(userRoomColumn);
ColumnModel<BaseEntityProxy> cm = new ColumnModel<BaseEntityProxy>(columnsChamado);
If, on the other hand, you want one grid row to display a User AND a Ticket, you have to use a wrapper class:
class TicketWithUserProxy extends BaseEntityProxy{
private UserProxy userProxy;
private TicketProxy ticketProxy;
public UserProxy getUserProxy() {
return userProxy;
}
public void setUserProxy(UserProxy userProxy) {
this.userProxy = userProxy;
}
public TicketProxy getTicketProxy() {
return ticketProxy;
}
public void setTicketProxy(TicketProxy ticketProxy) {
this.ticketProxy = ticketProxy;
}
}
and setup your grid (Grid<TicketWithUserProxy>) accordingly:
List<ColumnConfig<TicketWithUserProxy, ?>> columnsChamado = new ArrayList<ColumnConfig<TicketWithUserProxy, ?>>();
ColumnConfig<TicketWithUserProxy, String> dateColumn = new ColumnConfig<TicketWithUserProxy, String>(
new ValueProvider<TicketWithUserProxy, String>() {
private final DateTimeFormat dtFormat = DateTimeFormat.getFormat(DateTimeFormat.PredefinedFormat.DATE_FULL);
public String getValue(TicketWithUserProxy object) {
Date initialDate = object.getTicketProxy().getInitialDate();
String date = "";
if (initialDate != null) {
date = dtFormat.format(initialDate);
}
return date;
}
public void setValue(TicketWithUserProxy object, String initialDate) {
object.getTicketProxy().setInitialDate(dtFormat.parse(initialDate));
}
public String getPath() {
return "initialDate";
}
}, 70, "Date");
columnsChamado.add(dateColumn);
ColumnConfig<TicketWithUserProxy, String> userRoomColumn = new ColumnConfig<TicketWithUserProxy, String>(
new ValueProvider<TicketWithUserProxy, String>() {
public String getValue(TicketWithUserProxy object) {
String userRoom = object.getUserProxy().getUserRoom();
String room = "";
if (userRoom != null) {
room = userRoom;
}
return room;
}
public void setValue(TicketWithUserProxy object, String userRoom) {
object.getUserProxy().setUserRoom(userRoom);
}
public String getPath() {
return "userRoom";
}
}, 70, "User's Room");
columnsChamado.add(userRoomColumn);
ColumnModel<TicketWithUserProxy> cm = new ColumnModel<TicketWithUserProxy>(columnsChamado);
If you have a Column of TicketProxy, you can get the UserProxy from the TicketProxy ?
ColumnConfig<TicketProxy, String> userRoomColumn = new ColumnConfig<TicketProxy, String>(
new ValueProvider<TicketProxy, String>() {
public String getValue(TicketProxy object) {
String userRoom = object.getUser().getUserRoom();
String room = "";
if (userRoom != null) {
room = userRoom;
}
return room;
}
public void setValue(TicketProxy object, String userRoom) {
object.getUser().setUserRoom(userRoom);
}
public String getPath() {
return "user.userRoom";
}
}, 70, "User's Room");
columnsChamado.add(userRoomColumn);