I have a class called "Product", with a double attribute "price". I'm showing it on a table column inside a table view, but i wanted to show the price formatted -- "US$ 20.00" instead of just "20.00".
Here's my code for populating the table view:
priceProductColumn.setCellValueFactory(cellData -> cellData.getValue().priceProperty());
I tried everything: convert the returned value to a string, using the method toString that priceProperty has, etc, but not seems to work.
Do i need to bind an event of something like that?
Use the cellValueFactory as you have it to determine the data that is displayed. The cell value factory is basically a function that takes a CellDataFeatures object and returns an ObservableValue wrapping up the value to be displayed in the table cell. You usually want to call getValue() on the CellDataFeatures object to get the value for the row, and then retrieve a property from it, exactly as you do in your posted code.
Use a cellFactory to determine how to display those data. The cellFactory is a function that takes a TableColumn (which you usually don't need) and returns a TableCell object. Typically you return a subclass of TableCell that override the updateItem() method to set the text (and sometimes the graphic) for the cell, based on the new value it is displaying. In your case you get the price as a Number, and just need to format it as you require and pass the formatted value to the cell's setText(...) method.
It's worth reading the relevant Javadocs: TableColumn.cellFactoryProperty(), and also Cell for a general discussion of cells and cell factories.
priceProductColumn.setCellValueFactory(cellData -> cellData.getValue().priceProperty());
priceProductColumn.setCellFactory(col ->
new TableCell<Product, Number>() {
#Override
public void updateItem(Number price, boolean empty) {
super.updateItem(price, empty);
if (empty) {
setText(null);
} else {
setText(String.format("US$%.2f", price.doubleValue()));
}
}
});
(I'm assuming priceProductColumn is a TableColumn<Product, Number> and Product.priceProperty() returns a DoubleProperty.)
If you have not, read this together with #James_D post.
https://docs.oracle.com/javafx/2/ui_controls/table-view.htm
Related
If I have a TableView in JavaFX with some TableColumn's is there a way I can get the data in that column's cells?
TableColumn concentrationCol = new TableColumn("Initial Concentration");
concentrationCol.setMinWidth(150);
concentrationCol.setCellValueFactory(
new PropertyValueFactory<SpeciesDoubleWrapper, String>("d"));
concentrationCol.setCellFactory(TextFieldTableCell.forTableColumn());
concentrationCol.setOnEditCommit(
new EventHandler<TableColumn.CellEditEvent<SpeciesDoubleWrapper, String>>() {
#Override
public void handle(TableColumn.CellEditEvent<SpeciesDoubleWrapper, String> t) {
((SpeciesDoubleWrapper) t.getTableView().getItems().get(
t.getTablePosition().getRow())
).setD(t.getNewValue());
}
}
);
This is the code I use to create my TableColumn. I know there is a function getCellObservableValue(int i) which returns the contents of the ith cell, but when I use it I get ObjectProperty [value: 0.0] returned instead of 0.0, which is the value of the cell.
You can call getValue method of extended class ObjectExpression:
getCellObservableValue(0).getValue()
https://docs.oracle.com/javase/8/javafx/api/javafx/beans/binding/ObjectExpression.html#getValue--
You are getting a Property, and more precisely an ObjectProperty.
These classes are used for the concept of data binding. To make it short, data binding allows JavaFX to keep track of the values if they change and automatically update the view accordingly.
To get the value, just call get().
I have the following problem.
I'm making a assignment for school, we need to show a gregoriancalendar value in a tableview.
this is my code for the table
TableColumn geboortedatum = new TableColumn("Geboortedatum");
geboortedatum.setCellValueFactory(new PropertyValueFactory<Persoon, SimpleDateFormat>("gebDat"));
When I actually run this I get the following value in my tableview no matter what.
java.util.GregorianCalendar[time=-23574157200000,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="Europe/Berlin",offset=3600000,dstSavings=3600000,useDaylight=true,transitions=143,lastRule=java.util.SimpleTimeZone[id=Europe/Berlin,offset=3600000,dstSavings=3600000,useDaylight=true,startyear=0,startMode=2,startMonth=2,startDay=-1,startTime=360000
and it goes on like that.
anyone who has a simple solution for me? I'm probably missing something really easy here.
First, it looks you have the wrong type for the PropertyValueFactory. You get away with this because you are using a raw TableColumn, but your code will be easier to understand if you properly type the column. From the output, I can see that your Persoon.getGebDat() method returns a Calendar object. So you should have
TableColumn<Persoon, Calendar> geboortedatum = new TableColumn<>("Geboortedatum");
geboortedatum.setCellValueFactory(new PropertyValueFactory<Persoon, Calendar>("gebDat"));
The default behavior of a TableCell is to call the toString method of the item it is displaying. The text you are seeing is the result of calling toString on your Calendar object.
To change the way the data is displayed, you need to specify a cell factory on the TableColumn that creates a TableCell that knows how to format the Calendar as you want it.
So you'll do something like
final DateFormat dateFormat = DateFormat.getDateInstance() ; // or whatever format object you need...
geboortedatum.setCellFactory(col -> new TableCell<Persoon, Calendar>() {
#Override
public void updateItem(Calendar item, boolean empty) {
super.updateItem(item, empty);
if (item == null) {
setText(null);
} else {
setText(dateFormat.format(item.getTime()));
}
}
});
at the moment I have an app that allows me to display data in a Jtable and then when I double click the Jtable this open a little window to edit only 3 fields, comments, expiration date and description. I update the this values (whit a preparedStatement) the thing is that everytime that I make an update to the database my table just refresh itself, changing the dateFormat with the new value that I've just inserted in my other window but with a different format!. How is this possible?
I' don't understand this because the only I only set a model to the table when I press my "search" button which contains the following code:
ArrayList<FiltrosResumen> filtrosResumenList = MainFrame.dataBase.searchFiltroResumen(query);
FiltrosResumenTableModel resumenModel = new FiltrosResumenTableModel(filtrosResumenList);
this.resumenTable.setModel(resumenModel);
hideColumns(1);
I'm using a custom table model containing all the table Fields, so first as you can see I colect all the rows from the database into a ArrayList from a custom object "FiltrosResumen", then I pass this to the constructor from my customTable model "FiltrosResumenTableModel" which extends AbstractTableMode I'm not using any special renders the most important methods are
public Object getValueAt(int rowIndex, int columnIndex) {
switch (columnIndex) {
case 0:
return this.filtrosResumen.get(rowIndex).getIdFiltro();
//....
//case 9:
default:
return null;
}
}
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
FiltrosResumen filtroResumen = new FiltrosResumen();
switch (columnIndex) {
case 0:
filtroResumen = this.filtrosResumen.get(rowIndex);
filtroResumen.setIdFiltro(Long.parseLong(aValue.toString()));
this.fireTableCellUpdated(rowIndex, columnIndex);
break;}
//....
//case 9:
}
And the constructor
public FiltrosResumenTableModel(List<FiltrosResumen> filtrosResumen) {
this.filtrosResumen = filtrosResumen;
}
And as I stated before, the database does not interact directly whit the table since storing the query result in a ArrayList, and then sending this to the constructor of my customTableModel.
EDIT: In order to change the value from one of the rows items I send a FiltrosResumen Object in this way:
FiltrosResumenTableModel modelo = (FiltrosResumenTableModel) this.resumenTable.getModel();
resumen = modelo.getResumen(row);
EditResumenIF editConexionesIF = new EditResumenIF(resumen);
EDIT: Passing a the resumen object to a InternalFrame Constructor (EditResumenIF).So in this new InternalFrame (EditResumenIF) I assign the values to a JCalendar and a JTextField to change the values and then save them. Afther the same object received by the constructor to a method that does the query and then return a string, ( if the string it's empty it' means that the query was successful without any mistakes)
String error = MainFrame.dataBase.updateResumen(resumen, resumen.getIdFiltro());
How comes that my Table knows that the value changed?
The default renderer for a cell of type Object.class is "a label that displays the object's string value." Unless your implementation of TableModel override's getColumnClass() to return some other value, your result is not unexpected. You might compare this example using DefaultTableModel to your implementation.
Addendum: How does my table know that the value changed?
JTable is a TableModelListener; any change to the model is (or should be) propagated to the table. Absent a complete example, I'm guessing that you are using a second table, table2, to edit a copy of certain data obtained from the original, table1.
Verify that you are copying the data in getResumen() and not just copying a reference to the table1 model.
In your implementation of setValueAt() in the TableModel of table2, update the model of table1. The exact mechanism depends on your TableModel; two approaches are contrasted here.
Addendum: I'm not using another tableā¦I'm passing a reference to my internal frame.
The same principles would apply. As an alternative to directly coupling the models, let the table's model be a PropertyChangeListener to the internal frame, as shown here.
I am trying to make my table select an entire row when you click on a cell (which can be done by turning off column select), but, I don't want the extra thick border around the specific cell you clicked to be highlighted. I was hoping this would be easy but apparently it involves renderers so I did a lot of research and the closest I can get is this:
JTable contactTable = new JTable(tableModel);
contactTable.setCellSelectionEnabled(true);
contactTable.setColumnSelectionAllowed(false);
contactTable.setRowSelectionAllowed(false);
contactTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
// This renderer extends a component. It is used each time a
// cell must be displayed.
class MyTableCellRenderer extends JLabel implements TableCellRenderer {
// This method is called each time a cell in a column
// using this renderer needs to be rendered.
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int rowIndex, int vColIndex) {
// 'value' is value contained in the cell located at
// (rowIndex, vColIndex)
if (isSelected) {
// cell (and perhaps other cells) are selected
}
if (hasFocus) {
// this cell is the anchor and the table has the focus
this.setBackground(Color.blue);
this.setForeground(Color.green);
} else {
this.setForeground(Color.black);
}
// Configure the component with the specified value
setText(value.toString());
// Set tool tip if desired
// setToolTipText((String)value);
// Since the renderer is a component, return itself
return this;
}
// The following methods override the defaults for performance reasons
public void validate() {}
public void revalidate() {}
protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) {}
public void firePropertyChange(String propertyName, boolean oldValue, boolean newValue) {}
}
int vColIndex = 0;
TableColumn col = contactTable.getColumnModel().getColumn(vColIndex);
col.setCellRenderer(new MyTableCellRenderer());
I copied the Renderer from an example and only changed the hasFocus() function to use the colors I wanted. Setting colors in isSelected() did nothing.
The problem with this code is:
It only works on one column specified by vColIndex at the bottom. Obviously I want this applied to all columns so clicking on a cell in one highlights the entire row. I could make a for loop to change it to every cell but I figure there's a better way of doing this that changes the cellRenderer for ALL columns at once.
setForegroundColor() works to change text but setBackgroundColor() does nothing to the cells background. I would like it to actually change the background color like the property implies.
Solution for #2: Use this.setOpaque(true); before assigning backgroundcolor.
When the renderer does work, it only works on a single Cell. How can I get it to color all the Cells in the row?
Solution for #3: I figured it out! Instead of using hasFocus(), which only affects the single cell, if you enable row selection (table.setRowSelectionAllowed(true)) then you put the color changing in the if(isSelected) statement. Then the whole row is considered selected and it colors all the cells in!
3 was the big one but if anyone knows #1 or can explain to me why it was designed such that you can only apply the renderer to one column at a time it would be much appreciated.
too direct just do add line
tablename.setSelectionBackground(Color.red);
in my case
jtbillItems.setSelectionBackground(Color.red);
The tutorial article Concepts: Editors and Renderers explains that "a single cell renderer is generally used to draw all of the cells that contain the same type of data," as returned by the model's getColumnClass() method.
Alternatively, override prepareRenderer(), which is invoked for all cells, to selectively alter a row's appearance. This example compares the two approaches, and the article Table Row Rendering expands on the versatility of the approach.
For the second question you can try setSelectionBackground(Color) and setSelectionForeGround(Color) methods. I'm not sure how you can solve the first one. And one last suggestion you can use some swing designer plugin such ass JBuilder. It would help lot.
I have two columns which are orderbyborder links. When i click one column i changed the color of column by adding attributeModifier in the following way
add(new AttributeModifier("style", true, new Model<String>("background-color:#80b6ed;")));
This works fine. But when i click on second column, the first column remains the changed color. But I expect only the column which i click should hold this attributeModifier!
You shouldn't change the modifier.
The trick is to have your model return the correct value. So instead of using new Model<String>("background-color:#80b6ed;"), which always returns the same constant value, you'd have something like:
new Model<String>() {
#Override
public String getObject() {
if( columnName.equals( selectedColumn ) { //or something along these lines, to check if the current column is the selected one
return "background-color:#80b6ed;";
}
return "background-color:white;";
}
}
And of course this also means you can add an attribute modifier to every column when you create them and don't have to worry about them later on.
Another way to achieve what you want is to add a css class to the selected line via Javascript (removing the class from old one).