I am trying to display image fetch from database in a table view. Here is how I set up my table view with image column:
TableColumn prodImageCol = new TableColumn("IMAGES");
prodImageCol.setCellValueFactory(new PropertyValueFactory<Product, Image>("prodImage"));
prodImageCol.setMinWidth(100);
// setting cell factory for product image
prodImageCol.setCellFactory(new Callback<TableColumn<Product, Image>, TableCell<Product, Image>>() {
#Override
public TableCell<Product, Image> call(TableColumn<Product, Image> param) {
TableCell<Product, Image> cell = new TableCell<Product, Image>() {
#Override //Error here
public void updateItem(Product item, boolean empty) {
if (item != null) {
ImageView imageview = new ImageView();
imageview.setFitHeight(50);
imageview.setFitWidth(50);
imageview.setImage((Image) item.getprodImage());
setGraphic(imageview);
}
}
};
return cell;
}
});
However, I am getting method does not override or implement a method from a supertype. I have no idea why is it so because I follow the same thing from a website on how to display image in table view. Can somebody please explain to me why is it so? Thanks in advance.
UPDATE: The signature of the updateItem method is:
#Override
protected void updateItem(Image image, boolean b) {
super.updateItem(image, b);
}
I posted my original answer too quickly (before I got the same compile error you did).
You can have a method like this if you like:
public void updateItem(Product item, boolean empty);
You just can't annotate it with:
#Override
Which means you are redefining a method with the exact same signature (name and arguments) from the base class.
Alternatively, reverse the generic type arguments:
<Image, Product> vs. <Product, Image>
Related
In my table I have one cell that does not update without interaction with the table.
I found the reason already here Java: setCellValuefactory; Lambda vs. PropertyValueFactory; advantages/disadvantages
My problem is, the default value of the cells item is LocalDate.MIN and I want my cell to contain "---" as long as the item has this default value. When I update the item, I want the cell to contain the current date string.
Item Class:
public class ItemEv {
private final ObjectProperty<LocalDate> openedAt;
#XmlJavaTypeAdapter(LocalDateAdapter.class)
public final LocalDate getOpenedAt() {
return openedAt.get();
}
public final ObjectProperty<LocalDate> openedAtProperty() {
return this.openedAt;
}
public final void setOpenedAt(LocalDate openedAt) {
this.openedAt.set(openedAt);
}
}
in another CellFactory I set the new value: i.setOpenedAt(LocalDate.now());
this is working but not wanted:
openedAtColumnEv.setCellValueFactory(cellData -> cellData.getValue().openedAtProperty().asString());
and this is what I tried so far:
openedAtColumnEv.setCellValueFactory(new Callback<CellDataFeatures<ItemEv, String>, ObservableValue<String>>() {
#Override
public ObservableValue<String> call(CellDataFeatures<ItemEv, String> i) {
if (i.getValue().getOpenedAt().equals(LocalDate.MIN)) {
return new SimpleStringProperty("---");
}
return i.getValue().openedAtProperty().asString();
}
});
and this:
openedAtColumnEv.setCellValueFactory(cellData -> {
if(cellData.getValue().openedAtProperty().getValue().equals(LocalDate.MIN)) {
return new SimpleStringProperty("---");
}
return cellData.getValue().openedAtProperty().asString();
});
Both of my tests return either SimpleStringProperty or StringBinding which should be fine.
In my tests I made a mistake where the first return in the IF statement does never return true, then the cell values show the standard string for LocalDate.MIN and get updated immediately when the item property changes.
Im a bit lost on this. Please forgive my bad english, Im not a native speaker.
If the property in the model class is an ObjectProperty<LocalDate>, then the column should be a TableColumn<ItemEv, LocalDate>, not a TableColumn<ItemEv, String>.
Implementing the cellValueFactory directly (typically with a lambda expression) is always preferable to using the legacy PropertyValueFactory class. You never "need to use" a PropertyValueFactory (and never should).
The cellValueFactory is only used to determine what data to display. It is not used to determine how to display the data. For the latter, you should use a cellFactory.
So:
private TableColumn<ItemEv, LocalDate> opendAtColumnEv ;
// ...
openedAtColumnEv.setCellValueFactory(cellData -> cellData.getValue().openedAtProperty());
openedAtColumnEv.setCellFactory(column -> new TableCell<ItemEv, LocalDate>() {
#Override
protected void updateItem(LocalDate openedAt, boolean empty) {
super.updateItem(openedAt, empty);
if (openedAt == null || empty) {
setText("");
} else {
if (openedAt.equals(LocalDate.MIN)) {
setText("---");
} else {
// Note you can use a different DateTimeFormatter as needed
setText(openedAt.format(DateTimeFormatter.ISO_LOCAL_DATE));
}
}
}
});
So I have this TreeTableView and I can get text to display properly but buttons and images don't want to display. I'm currently using the method of overriding the TreeTableCell class and its update method.
TreeTableColumn<Application, Application> installed = new TreeTableColumn<Application, Application>("Installed?");
installed.setResizable(false);
installed.setPrefWidth(308.9);
installed.setCellFactory(new Callback<TreeTableColumn<Application, Application>, TreeTableCell<Application, Application>>()
{
#Override
public TreeTableCell<Application, Application> call(TreeTableColumn<Application, Application> param)
{
TreeTableCell<Application, Application> cell = new TreeTableCell<Application, Application>()
{
#Override
public void updateItem(Application app, boolean empty)
{
if(app != null)
{
setGraphic(app.getInstalledImage());
}
}
};
return cell;
}
});
appTree.getColumns().add(installed);
However, "app" throws a NullPointerException when not checking for app != null so I'm thinking that may fix my problem. Any ideas why a valid Application is not getting passed?
The TreeTableView contains empty cells; cells in the space below the last populated row and, perhaps, cells in some columns for collapsed rows. Empty cells always have updateItem(...) called with a null item.
Note that it's always essential to call super.updateItem(...) in your implementation:
#Override
public void updateItem(Application app, boolean empty)
{
super.updateItem(app, empty);
if(app != null)
{
setGraphic(app.getInstalledImage());
}
}
See the Javadocs for Cell for details.
I've overridden ListCell.updateItem(T, boolean) to provide a custom renderer for my ComboBox items (as per Oracle ComboBox tutorial) and this is working fine except when I programmatically set an item using ComboBox.setValue(T).
Instead the toString() method of T is being called. The item being set is already in the ObservableList which backs the ComboBox.
comboBox.setCellFactory(new Callback<ListView<MyType>, ListCell<MyType>>()
{
#Override
public ListCell<MyType> call(ListView<MyType> arg0)
{
return new ListCell<MyType>()
{
#Override
protected void updateItem(MyType item, boolean empty)
{
super.updateItem(item, empty);
if (item == null || empty)
{
setText("");
}
else
{
setText(item.myCustomRenderMethod());
}
}
};
}
});
Is there another method I need to override?
JavaFX2 on JDK1.7.0_45.
Thanks.
OK, found the answer here: JavaFx Editable ComboBox : Showing toString on item selection
You also need to override ComboBox.setConverter() to ensure that the selected object shows the correct text. This is not in the Oracle tutorial and violates the principle of least surprise for me as it duplicates some of the code from ListCell.updateItem()
comboBox.setConverter(new StringConverter<MyType>() {
#Override
public String toString(MyType obj) {
if (obj == null)
{
return "";
}
else
{
return obj.myCustomRenderMethod();
}
}
#Override
public MyType fromString(String s)
{
return null;
}
});
In my case using Platform.runLater() solved the issue:
Platform.runLater(() -> comboBox.setValue(value));
My best guess is that setting a value before the ComboBox is part of a Scene causes the problem. Also, be sure to use the setButtonCell(...) method of ComboBox.
I have a class called ErrorHighlighter which gets notified anytime a property called errorString is changed. Based on this propertychangeevent I update the HighLighterPredicate to highlight a particular row with a red background.
ErrorHighlighter receives the propertychangeevent, it also changes the HighlighterPredicate, but the table row does not get updated with red background.
I also update the tooltip of the row. That does not get reflected either.
Please see the code below. Could someone please help?
public class ErrorRowHighlighter extends ColorHighlighter implements PropertyChangeListener {
private Map<Integer, String> rowsInError;
private SwingObjTreeTable<ShareholderHistoryTable> treeTable;
public ErrorRowHighlighter(SwingObjTreeTable<ShareholderHistoryTable> treeTable) {
super(CommonConstants.errorColor, null);
this.treeTable = treeTable;
rowsInError=new HashMap<Integer, String>();
setHighlightPredicate(new HighlightPredicate() {
#Override
public boolean isHighlighted(Component renderer, ComponentAdapter adapter) {
if(rowsInError.containsKey(adapter.row)){
return true;
}
return false;
}
});
this.treeTable.addMouseMotionListener(new MouseMotionAdapter() {
#Override
public void mouseMoved(MouseEvent e) {
int row=ErrorRowHighlighter.this.treeTable.rowAtPoint(e.getPoint());
if(rowsInError.containsKey(row)){
ErrorRowHighlighter.this.treeTable.setToolTipText(rowsInError.get(row));
}else{
ErrorRowHighlighter.this.treeTable.setToolTipText(null);
}
}
});
}
public void highlightRowWithModelDataAsError(ShareholderHistoryTable modelData){
int indexForNodeData = treeTable.getIndexForNodeData(modelData);
if(indexForNodeData>-1){
rowsInError.put(indexForNodeData, modelData.getErrorString());
updateHighlighter();
}
}
public void unhighlightRowWithModelDataAsError(ShareholderHistoryTable modelData){
int indexForNodeData = treeTable.getIndexForNodeData(modelData);
if(indexForNodeData>-1){
rowsInError.remove(indexForNodeData);
updateHighlighter();
}
}
public void updateHighlighter(){
treeTable.removeHighlighter(this);
treeTable.addHighlighter(this);
}
#Override
public void propertyChange(PropertyChangeEvent evt) {
ShareholderHistoryTable sourceObject= (ShareholderHistoryTable) evt.getSource();
if(StringUtils.isNotEmpty(sourceObject.getErrorString())){
highlightRowWithModelDataAsError(sourceObject);
}else{
unhighlightRowWithModelDataAsError(sourceObject);
}
}
}
This looks like a mistake on my part. The method treeTable.getIndexForNodeData() actually returns back the index of the row by doing a pre-order traversal of the underlying tree data structure. This includes a root node that is not being displayed on the jxtreetable. Hence I needed to minus 1 from the index
int indexForNodeData = treeTable.getIndexForNodeData(modelData)-1;
This fixed the problem for me. I am leaving the post rather than deleting it if anyone wants to look at an example of a ColorHighlighter and a property change listener.
So I have this piece of code which is almost exactly the same on the GWT Showcase
selectionModel = new SingleSelectionModel<T>(keyProvider);
cellTable.setSelectionModel(selectionModel);
selectionModel.addSelectionChangeHandler(new SelectionChangeEvent.Handler() {
public void onSelectionChange(SelectionChangeEvent event) {
selectedRow = ((SingleSelectionModel<T>).selectionModel)
.getSelectedObject();
});
Column<T, Boolean> checkColumn = new Column<T, Boolean>(new CheckboxCell(true, false)) {
#Override
public Boolean getValue(T object) {
return cellTable.getSelectionModel().isSelected(object);
}
};
cellTable.addColumn(checkColumn, SafeHtmlUtils.fromSafeConstant("<br/>"));
The problem is, when I uncheck the checkbox the SelectionChangeEvent doesn't handle it.
The only instance the onSelectionChange is being called, is when I select another record, but deselecting a record doesn't invoke this method.
any help?
You forgot to add DefaultSelectionEventManager i guess.
Change this line
cellTable.setSelectionModel(selectionModel);
to
cellTable.setSelectionModel(selectionModel,
DefaultSelectionEventManager.<T> createCheckboxManager());