Good day,
I have a fixed number of columns in TableView, however I need to populate column by column, not row by row, as one column data depends on the previous one. Is there an example of such thing? I have searched for such way, but unfortunately. Hope I made it understandable.
Since nobody provided me an example, and the comment was not very helpful I manage to solve my problem in the following way (in my case one column result depends on the previous one and the number of elements can be different as well as the number of columns are predefined)
Simple example:
We have an object:
public class Cars{
private String name;
private String company;
private String year;
public Cars(String name,String company,String year){
this.name=name;
this.company=company;
this.year=year;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name= name;
}
public String getCompany() {
return company;
}
public void setCompany(String company) {
this.company= company;
}
public String getYear() {
return year;
}
public void setYear(String year) {
this.year= year;
}
}
Then we have our table:
public TableView createTable() {
TableView<Cars> table = new TableView<>();
TableColumn<Cars, String> nameyColumn = new TableColumn("Name");
nameColumn.setCellValueFactory(new PropertyValueFactory<>("name"));
TableColumn<Cars, String> companyColumn = new TableColumn<>("Company");
companyColumn.setCellValueFactory(new PropertyValueFactory<>("company"));
TableColumn<Cars, String> yearColumn = new TableColumn<>("Year");
yearColumn.setCellValueFactory(new PropertyValueFactory<>("year"));
table.setItems(makeCars());
table.getColumns().addAll(nameColumn, companyColumn, yearColumn);
return table;
}
Afterwards we generate the information that we want to put into the table and put all the information into, in this case a String Array. So if we have 3 String arrays we can make an ArrayListlist of arrays and populate it with information.
However, the sizes of the String arrays inside the ArrayList have to be predefined, so that you would not get a NullPointException where the at one point you have a car's name and you dont have a year it will be set to an empty automatically, as an empty predefined String array contains null as elements automatically. So in my case I know the max size that one array can be and set all of them to the same size.
And afterwards I just loop through the ArrayList of String Arrays and create objects which I add to the ObservableList ( might be a better way of doing it but I did it this way):
private ObservableList<Cars> makeCars() {
ObservableList<Cars> madeList = FXCollections.observableArrayList();
ArrayList<String[]>arrayOfArrays=new ArrayList<>();
for(int i=0;i<maxRow;i++){
madeList.add(new Cars(arrayOfArrays.get(0)[i],arrayOfArrays.get(1)[i],
arrayOfArrays.get(2)[i]));
}
return madeList;
}
Hope this will helpful to somebody, if there is a better way and I am overdoing it please share.
Related
This has baffled me for a while now and I cannot seem to get the grasp of it. I'm using Cell Value Factory to populate a simple one column table and it does not populate in the table.
It does and I click the rows that are populated but I do not see any values in them- in this case String values. [I just edited this to make it clearer]
I have a different project under which it works under the same kind of data model. What am I doing wrong?
Here's the code. The commented code at the end seems to work though. I've checked to see if the usual mistakes- creating a new column instance or a new tableview instance, are there. Nothing. Please help!
//Simple Data Model
Stock.java
public class Stock {
private SimpleStringProperty stockTicker;
public Stock(String stockTicker) {
this.stockTicker = new SimpleStringProperty(stockTicker);
}
public String getstockTicker() {
return stockTicker.get();
}
public void setstockTicker(String stockticker) {
stockTicker.set(stockticker);
}
}
//Controller class
MainGuiController.java
private ObservableList<Stock> data;
#FXML
private TableView<Stock> stockTableView;// = new TableView<>(data);
#FXML
private TableColumn<Stock, String> tickerCol;
private void setTickersToCol() {
try {
Statement stmt = conn.createStatement();//conn is defined and works
ResultSet rsltset = stmt.executeQuery("SELECT ticker FROM tickerlist order by ticker");
data = FXCollections.observableArrayList();
Stock stockInstance;
while (rsltset.next()) {
stockInstance = new Stock(rsltset.getString(1).toUpperCase());
data.add(stockInstance);
}
} catch (SQLException ex) {
Logger.getLogger(WriteToFile.class.getName()).log(Level.SEVERE, null, ex);
System.out.println("Connection Failed! Check output console");
}
tickerCol.setCellValueFactory(new PropertyValueFactory<Stock,String>("stockTicker"));
stockTableView.setItems(data);
}
/*THIS, ON THE OTHER HAND, WORKS*/
/*Callback<CellDataFeatures<Stock, String>, ObservableValue<String>> cellDataFeat =
new Callback<CellDataFeatures<Stock, String>, ObservableValue<String>>() {
#Override
public ObservableValue<String> call(CellDataFeatures<Stock, String> p) {
return new SimpleStringProperty(p.getValue().getstockTicker());
}
};*/
Suggested solution (use a Lambda, not a PropertyValueFactory)
Instead of:
aColumn.setCellValueFactory(new PropertyValueFactory<Appointment,LocalDate>("date"));
Write:
aColumn.setCellValueFactory(cellData -> cellData.getValue().dateProperty());
For more information, see this answer:
Java: setCellValuefactory; Lambda vs. PropertyValueFactory; advantages/disadvantages
Solution using PropertyValueFactory
The lambda solution outlined above is preferred, but if you wish to use PropertyValueFactory, this alternate solution provides information on that.
How to Fix It
The case of your getter and setter methods are wrong.
getstockTicker should be getStockTicker
setstockTicker should be setStockTicker
Some Background Information
Your PropertyValueFactory remains the same with:
new PropertyValueFactory<Stock,String>("stockTicker")
The naming convention will seem more obvious when you also add a property accessor to your Stock class:
public class Stock {
private SimpleStringProperty stockTicker;
public Stock(String stockTicker) {
this.stockTicker = new SimpleStringProperty(stockTicker);
}
public String getStockTicker() {
return stockTicker.get();
}
public void setStockTicker(String stockticker) {
stockTicker.set(stockticker);
}
public StringProperty stockTickerProperty() {
return stockTicker;
}
}
The PropertyValueFactory uses reflection to find the relevant accessors (these should be public). First, it will try to use the stockTickerProperty accessor and, if that is not present fall back to getters and setters. Providing a property accessor is recommended as then you will automatically enable your table to observe the property in the underlying model, dynamically updating its data as the underlying model changes.
put the Getter and Setter method in you data class for all the elements.
I am trying to display a list of users on a table. I write the following code in order to complete the table, however the Boolean values are not displayed on checkboxes (they are always populated as empty / false when there are actually several that are true). As a test I an just adding a single object that I am creating "manually"
Below is the code:
TableView<User> objTable = new TableView<User>();
objTable.setEditable(true);
ObservableList<User> objList = FXCollections.observableArrayList(new User("User 1", true);
TableColumn objColumnName = new TableColumn<User, String>("Column Name");
TableColumn objColumnActive = new TableColumn<User, Boolean>("Active");
objColumnName.setCellValueFactory(new PropertyValueFactory<User, String>("DisplayName"));
objColumnActive.setCellValueFactory(new PropertyValueFactory<UserRequestVO, Boolean>("Active"));
objTable.getColumns().addAll(objColumn);
objTable.setItems(objList);
User Class
public class user
{
private String strFirstName;
private Boolean bolActive;
public Boolean getActive()
{
return this.bolActive
}
}
I also try renaming getActive function as isActive, but there were no changes
You should use properties,
In your user class, you would store your boolean as a SimpleBooleanProperty :
private SimpleBooleanProperty bolActive;
Instantiated like so : this.bolActive = new SimpleBooleanProperty(false); //Or true instead of false
Now create a getter for the property, the property value, and a setter for the property value :
public BooleanProperty bolActiveProperty(){
return bolActive;
}
public final Boolean getBolActive() {
return bolActive.get();
}
public final void setBolActive(Boolean bolActive) {
this.bolActive.set(bolActive);
}
Now when you create your table columns, you do this :
objColumnActive.setCellValueFactory(cellData -> cellData.getValue().bolActiveProperty());
Or if you prefer old school java :
objColumnActive.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<User,Boolean>, ObservableValue<Boolean>>() {
#Override
public ObservableValue<Boolean> call(CellDataFeatures<User, Boolean> cellData) {
return cellData.getValue().bolActiveProperty();
}
});
This also work I think, might be wrong though :
objColumnActive.setCellValueFactory(new PropertyValueFactory<User, Boolean>("bolActive"));
This will allow you to bind the User property to the column, so that any modification of the column will affect the value in the user.
Nice thing is you can listen to the value modification using myProperty.addListener((obs, oldV, newV) -> { /* Your code */ });
Where obs is the value observed, oldV the old value, and newV the new value (obviously)
Does that help/work for you?
I have created a two column editable TableView which the user can edit and change the data thats inside each cell. Now my question is, once the user has changed some data around in each cell, how do I then save this data or print it out in a way to add to an SQL query like this example below
INSERT INTO table_name
VALUES (Value from table,Value from table,Value from table,...);
//Editable cell
PriceColumn.setCellFactory(TextFieldTableCell.forTableColumn());
PriceColumn.setOnEditCommit(
new EventHandler<CellEditEvent<NewCustomerList, String>>() {
#Override
public void handle(CellEditEvent<NewCustomerList, String> t) {
((NewCustomerList) t.getTableView().getItems().get(
t.getTablePosition().getRow())).setPrice(t.getNewValue());
}
}
);
You could do this by getting the required values and then passing them onto the DAO class to execute the query on the DB. Example follows-
PriceColumn.setOnEditCommit(
new EventHandler<CellEditEvent<NewCustomerList, String>>() {
#Override
public void handle(CellEditEvent<NewCustomerList, String> t) {
((NewCustomerList) t.getTableView().getItems().get(t.getTablePosition().getRow())).setPrice(t.getNewValue());
String newPrice = t.getNewValue();
String uniqueIdentifier = t.getRowValue().getUniqueIdentifier(); //Unique identfier is something that uniquely identify the row. It could be the name of the object that we are pricing here.
daoObj.updatePrice(newPrice, uniqueIdentifier); //Call DAO now
}
}
);
And somewhere in the deep dark jungles of DAO class,
private final String updateQuery = "UPDATE <TABLE_NAME> SET <PRICE_COLUMN> = ? WHERE <UNIQUE_COLUMN> = ?"; //If you require multiple columns to get a unique row, add them in the where clause as well.
public void updatePrice(String newPrice, String uniqueIdentifier) {
PreparedStatement ps = con.prepareStatement(updateQuery); //con is the connection object
ps.setString(1,uniqIdentifier); //if a string
ps.setString(2,newPrice); //if a string
ps.executeQuery();
}
If this is not what you were expecting, then can you please clarify your requirement?
Thare is a tutorial at javaFX documentation page. This example describes how to make tableView, if you have some sertain java class, which can tell you which columns you are going to have. (That is a Person class in this example).
But what if i do not have any specific class, and number of columns can vary from time to time?
In my case i have such data structure:
class TableData{
List<Row> rows; //A list with all my rows i need to have in my table
}
class Row{
List<Column> columns; //Cells\Columns for every row.
}
class Column{
Attribute attr; //Each column - is somethig like a wrapper for the real data i need to show in a cell;
}
class Attribute{ //My precues data
String name;
SupportingInfo info;
}
class SupportingInfo{//Some supporting fields...
String name;
String value;
//...etc....
}
So, my case is very similar to this one.
The only differents is that data from the case above is not binded with its representation in javaFX table (so, even if some one will make extra controls to edit this data in a tableView, the actual object with that data will never know about it.), because it(data) goes to the table like some strings, not like some objects;
So, what do i need - is to push data to the table (like that: table.setItems(tableData)), set some set Factories, to give user ability to edit data, and to have this edited data in my tableData object;
Here are some code ive tried to make for this purpose:
//prepare my table
private void createTableHeader(TableView table, List<Attribute> ias) {
int i = 0;
for (final Attribute ia : ias) {
final int j = i;
i++;
TableColumn tc = new TableColumn(ia.getName());
tc.setSortable(true);
tc.setCellValueFactory(new Callback<CellDataFeatures<List<Attribute>, String>, ObservableValue<String>>() {
#Override
public ObservableValue<String> call(CellDataFeatures<List<Attribute>, String> arg0) {
if(arg0.getValue().get(j).getSupportingInfo() == null){
arg0.getValue().get(j).setSupportingInfo(new SupportingInfo());
}
return new SimpleObjectProperty(arg0.getValue().get(j),"value");
}
});
table.getColumns().add(tc);
}
}
//loading some data to my tableView
private void createTableBody(TableView curTable, List<Row> rows) {
ObservableList<List<Attribute>> data = FXCollections.observableArrayList();
for (Row row : rows) {
data.add(row.getColumns());
}
curTable.setItems(data);
}
//this one is to define some extra controls for editing data in a table by users
private void makeCellFactory(TableColumn curTableCol, final Attribute templateIa, final Document doc) {
curTableCol.setCellFactory(new Callback<TableColumn, TableCell>() {
public TableCell call(TableColumn p) {
final EditingCell cell = new EditingCell(templateIa, doc);
return cell;
}
});
}
But, as a result, i have just empty rows in my table, with an ability to click some cell and recieve table editing controls. But there is not defult values in by table;
What am i doing wrong in my code?
Ok, i've found a solution:
ts.setCellFactory should look like this:
tc.setCellValueFactory(new Callback<CellDataFeatures<List<Attribute>, SupportingInfo>, ObservableValue<Attribute>>() {
#Override
public ObservableValue<Attribute> call(CellDataFeatures<List<Attribute>, SupportingInfo> arg0) {
return new SimpleObjectProperty(arg0.getValue().get(j),"value",arg0.getValue().get(j));
}
});
Also, this code is needed to catch new values and put the incoming data to the table:
tc.setOnEditCommit(new EventHandler<CellEditEvent<List<Attribute>, Attribute>>() {
#Override
public void handle(CellEditEvent<List<Attribute>, Attribute> t) { t.getTableView().getItems().get(t.getTablePosition().getRow()).get(j).setSupportingInfo(t.getNewValue().getSupportingInfo());
}
});
Let's say I have a map (call it myClass.mapElem<Object, Object>) like so:
Key Val
A X
B Y
C X
I want to write HQL that can query the Values such that I can get back all instances of myClass where mapElem's value is 'X' (where 'X' is a fully populated object-- I just don't want to go through each element and say x.e1 = mapElem.e1 and x.e2=... etc). I know I can do this for the keys by using where ? in index(myClass.mapElem), I just need the corresponding statement for querying the values!
Thanks in advance...
ETA: Not sure if the syntax makes a difference, but the way I am actually querying this is like so:
select myClass.something from myClass mc join myClass.mapElem me where...
You should use elements(). I tried simulating your example with the following class
#Entity
#Table(name="Dummy")
public class TestClass {
private Integer id;
private Map<String, String> myMap;
#Id
#Column(name="DummyId")
#GeneratedValue(generator="native")
#GenericGenerator(name="native", strategy = "native")
public Integer getId() {
return id;
}
#ElementCollection
public Map<String, String> getMyMap() {
return myMap;
}
public void setId(Integer id) {
this.id = id;
}
public void setMyMap(Map<String, String> myMap) {
this.myMap = myMap;
}
}
And persisted a few instances, which constain maps of a similar structure to what you have in your example. (using < String, String > since the values in your example are strings)
The following query gives me all instances of TestClass, where the map contains a specific value
SELECT DISTINCT myClass
FROM TestClass myClass JOIN myClass.myMap myMap
WHERE ? in elements(myMap)
In my particular case, I ended up having to use an SQL query. Not ideal, but it worked.