I have a table with a column. Initially, the table is blank. I need to enter values at cell like Excel. I followed the question javafx-table-cell-editing and also JAVA Tutorial on TableView.
I coded like:
colCom1.setCellValueFactory(new PropertyValueFactory<>("C1"));
colCom1.setCellFactory(TextFieldTableCell.forTableColumn ());
colCom1.setOnEditCommit(new EventHandler<TableColumn.CellEditEvent<commonDataClass, String>>() {
#Override
public void handle(TableColumn.CellEditEvent<commonDataClass, String> t) {
((commonDataClass) t.getTableView().getItems().get(
t.getTablePosition().getRow())).setD1(t.getNewValue().toString());
tC1.setItems(myC1);
System.out.println("Col1->" + colCom1.isVisible());
tC1.refresh();
tC1.setVisible(true);
}
}
});
The issue I am facing is that after editing and pressing "ENTER" nothing appears in the cell (cell remains blank) while printing of data reveals that value has been properly entered.
I modified setCellValueFactory as
colCom1.setCellValueFactory (
new Callback<CellDataFeatures<commonDataClass, String>, ObservableValue<String>> () {
public ObservableValue<String> call(
CellDataFeatures<commonDataClass, String> p) {
// p.getValue() returns the Person instance for a particular TableView row
return p.getValue ().d1NameProperty ();
}
});
This clearly shows the content.
Related
Let's say I load data into a Grid. That works perfectly, everything is displayed. I can see it just fine, even after I call editItem(objectId); to edit data for any given line in the Grid.
Then let's say I have a button that adds a new line with mostly empty elements. In other words, the corresponding bean is mostly empty except for some default values. For some reason this behaves weird when I call editItem(objectId);. Here are the situations and their results:
If column is editable (column.setEditable(true);), my default data displays just fine
If column is not editable (column.setEditable(false);), my default data does NOT display. It is definitely in the bean, just not displayed. I see it once I click "Save" or "Cancel" in the edit form.
If I just show the line, do NOT enter the edit form (don't call editItem(objectId);), it display the default data just fine. I mention this just to point out what happens in the "display only" situation.
I even tried making the editField read only, and even that hid the data. So what is happening?
Example of data being displayed (see circled red):
Figure 1: Non-Empty data, but editable column
Example of data NOT being displayed (see circled red):
Figure 2: Empty data inside edit form
Figure 3: Non-Empty data after clicking save.
Note that it does not matter if the column is a ComboBox or just a regular text element, if I make it non-editable, it will not show the value I put in that column on this new line until after I click Save or Cancel.
Here is how I load the list of beans initially, where gridContainer is defined as BeanItemContainer<T> gridContainer:
public void updateList( List<T> dataList, T defaultData ) {
updateList( dataList, defaultData, new GridLoader<T>() {
#Override
public void loadGrid(List<T> dataList) {
gridContainer.removeAllItems();
if( dataList instanceof List && !dataList.isEmpty() )
gridContainer.addAll(dataList);
}
});
}
This works fine for non-editable columns, all data being displayed as expected. My pictures sort of hide it, but it is displaying just fine, and works in edit mode just fine as well.
And here is how I add a new line:
private void addRouting() {
Routing emptyData = Routing.create();
emptyData.setKey(null);
if( facilityId instanceof String && !facilityId.trim().isEmpty() )
emptyData.setFacilityId(facilityId.trim());
if(wmsItem instanceof String && !wmsItem.trim().isEmpty())
{
emptyData.setWmsItem(wmsItem);
// gridComponent.hideColumn("wmsItem", true);
// gridComponent.hideColumn("wmsItemDisplay", false);
}
else
{
// gridComponent.hideColumn("wmsItem", false);
// gridComponent.hideColumn("wmsItemDisplay", true);
}
if(workCenter instanceof String && !workCenter.trim().isEmpty())
{
emptyData.setWorkCenter(workCenter);
// gridComponent.hideColumn("workCenter", true);
// gridComponent.hideColumn("workCenterDisplay", false);
}
else
{
// gridComponent.hideColumn("workCenter", false);
// gridComponent.hideColumn("workCenterDisplay", true);
}
gridComponent.addItemAt(0, emptyData);
gridComponent.select(emptyData);
if(gridComponent.isEditorEnabled())
gridComponent.editItem(emptyData);
}
And in GridComponent, we have addItemAt defined as follows (BTW, GridComponent just wraps a layout with a toolbar at top and a Grid for the data, and so exposes various methods I need from the toolbar and Grid):
public BeanItem<T> addItemAt(int index, T bean) throws IllegalStateException {
BeanItemContainer<T> gridContainer = getGridContainer();
if(gridContainer instanceof BeanItemContainer)
{
/* Clear filter first because adding an item will break this.
* TODO: Maybe restore prior filter with "saveLastFilter();" and then "reapplyLastFilter();" after "add"
*/
saveLastFilter();
clearFilter();
BeanItem<T> newItem = gridContainer.addItemAt(index, bean);
reapplyLastFilter();
return newItem;
}
else
throw new IllegalStateException("Missing bean grid container");
}
I'm using a Grid in Vaadin 14. The grid is in multi-selection mode.
The selection handler takes a couple of seconds to complete and I'm calling setItems(...) at the end to update the items in the grid.
When the user selects another row while the previous selection handler is still running, I get an "Unknown key" error similar to the one described in https://github.com/vaadin/vaadin-grid-flow/issues/322, even though the new set of items still contains the selected item (another object instance but same according to equals()). This seems to be because the keys in the KeyMapper have already been changed due to setItems(), so the key coming from the client is not present anymore.
Is there a way to work around this, for example by disabling selection while the previous request is in progress?
UPDATE
To work around this Vaadin bug, I'm also calling setPageSize() with the exact number of items as argument. But it seems the same problem occurs even if I don't call setPageSize(), so it's probably due to setItems().
Do not change the grids items inside a SelectionListener.
You can still do all the things you wanted, but setting the items anew is not actually needed. In fact it will only create problems as you are experiencing now.
While working at this answer, I realized you will need to do your own Checkbox Column in order to be able to do actions for the one item that was just "selected", instead of removing all then add all selected ones (because much better performance). Here is how that could look.
// in my code samples, a `Foo` item can have many `Bar` items. The grid is of type Bar.
Grid.Column customSelectionColumn = grid.addComponentColumn(item -> {
Checkbox isSelected = new Checkbox();
isSelected.setValue(someParentFoo.getBars().contains(item));
isSelected.addValueChangeListener(event -> {
boolean newSelectedValue = event.getValue();
if(newSelectedValue){
someParentFoo.getBars().add(item)
} else {
someParentFoo.getBars().remove(item);
}
fooRepository.save(someParentFoo);
});
});
// make a Checkbox that selects all in the header
Checkbox toggleSelectAll = new Checkbox();
toggleSelectAll.addValueChangeListener(event -> {
if(event.getValue()){
someParentFoo.getBars().addAll(allGridItems);
} else {
someParentFoo.getBars().removeAll(allGridItems);
}
fooRepository.save(someParentFoo);
grid.getDataProvider().refreshAll(); // updates custom checkbox value of each item
});
gridHeaderRow.getCell(customSelectionColumn).setComponent(toggleSelectAll);
I solved this problem. Vaadin use data as key in HashMap. You need calc hashCode use immutable data fields. For example
public class TestData {
private int id;
private String name;
public TestData(int id) {
this.id = id;
}
#Override
public int hashCode() {
return Objects.hash(id);
}
public int getId() {
return id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
When I enter edit mode of my Table, I want the data validation exclamation mark icon (!) to be shown as soon as the user goes out of bounds of any of the validation constraints.
First, a couple of notes:
I'm using Vaadin 7, so the Bean Validation addon sadly won't work.
The data validation works as intended.
Now, I have a perfectly working table for which I am using a BeanItemContainer to keep my Person beans inside.
The code for the table and the TableFieldFactory looks something like this:
table.setContainerDataSource(buildContainer());
table.setTableFieldFactory(new TableFieldFactory() {
#Override
public Field createField(Container container, Object itemId, Object propertyId, Component uiContext) {
TextField field = (TextField) DefaultFieldFactory.get().createField(container, itemId, propertyId,
uiContext);
field.setImmediate(true);
if (propertyId.equals("firstName")) {
field.addValidator(new BeanValidator(Person.class, "firstName"));
}
return field;
}
});
The Person bean looks as follows:
public class Person {
#Size(min = 5, max = 50)
private String firstName;
... setters + getters...
}
The problem is that when I type something in the firstName field and then press enter or blur/unfocus that field, no indication whatsoever of error is shown. I have to mouseover the field to see that something is wrong.
My question is two folded...
How do I get the exclamation mark icon to appear when the field is
invalid? (This works for a normal TextField that is not in a Table)
Is there a way to get an immediate response from the invalid field
(show the icon) (i.e. immediately after you type under 5 chars,
without having to press enter or blur/unfocus the field in
question).
Would be great if I could have both questions answered! =)
Thanks in advance!
The Caption, Required Indicator (the red asterisk) and - most importantly here - Error Indicator (exclamation mark) are actually provided by the layouts containing the component, not the component themselves. When editable components are displayed in a table, they are displayed without a layout - that's why no error indicator is displayed.
If I were trying to square this circle, I would look at creating a CustomField as a wrapper for the editable field - and within that CustomField display an error indicator when the wrapped/delegate field becomes invalid. I've not tried this - I've not used editable fields in a table at all - but should be fairly easy to do.
Add a TextChangeListener to the field in FieldFactory, and call field.validate() in the listener. Note, though, that field.getValue() value is not normally changed until blur/unfocus, ergo the validator will be validating the old value - unless you do field.setValue(event.getText()) in the listener. See this post on the Vaadin forum for more details.
This is the sort of thing I meant for a validating wrapper - not tried using it. You'll see initComponent simply returns the field inside a FormLayout, which should give you the icon(s) you're seeking. (You may need to delegate more methods from ValidatingWrapper to delegate than I have- but quick look suggests this may be enough.)
You'd then wrap the field in your tableFieldFactory (second code block)
public class ValidatingWrapper<T> extends CustomField<T> {
private static final long serialVersionUID = 9208404294767862319L;
protected Field<T> delegate;
public ValidatingWrapper(final Field<T> delegate) {
this.delegate = delegate;
if (delegate instanceof TextField) {
final TextField textField = (TextField) delegate;
textField.setTextChangeEventMode(AbstractTextField.TextChangeEventMode.TIMEOUT);
textField.setTextChangeTimeout(200);
textField.addTextChangeListener(new FieldEvents.TextChangeListener() {
#Override
public void textChange(FieldEvents.TextChangeEvent event) {
textField.setValue(event.getText());
textField.validate();
}
});
}
}
#Override
public Class<? extends T> getType() {
return delegate.getType();
}
#Override
protected Component initContent() {
return new FormLayout(delegate);
}
#Override
public Property getPropertyDataSource() {
return delegate.getPropertyDataSource();
}
#Override
public void setPropertyDataSource(Property newDataSource) {
delegate.setPropertyDataSource(newDataSource);
}
}
table.setContainerDataSource(buildContainer());
table.setTableFieldFactory(new TableFieldFactory() {
#Override
public Field createField(Container container, Object itemId, Object propertyId, Component uiContext) {
TextField field = (TextField) DefaultFieldFactory.get().createField(container, itemId, propertyId,
uiContext);
field.setImmediate(true);
if (propertyId.equals("firstName")) {
field.addValidator(new BeanValidator(Person.class, "firstName"));
}
return ValidatingWrapper(field);
}
});
I've been working on this problem for quite a while but have not been able to solve it.
I have a listgrid with a field type icon. I would like to change the cursor to "hand" over the icon.
I've been searching the web and saw that a couple of solutions existed.
One of them is using addCellOverHandler for the list grid. But I don't understand how you can change the cursor for the specified field of the listgrid.
this.addCellOverHandler(new CellOverHandler() {
#Override
public void onCellOver(CellOverEvent event) {
// not able to get the field and setCursor()
}
});
My field in the listgrid is defined as:
ListGridField iconField = new ListGridField("icon");
iconField.setAlign(Alignment.CENTER);
iconField.setType(ListGridFieldType.ICON);
iconField.setIcon("icons/icon.gif");
Like someone pointed out on the forum, a setCursor() method exist for the listgrid, but not for the field only...
If anybody has a clue...
Thanks
After some more (a lot more...) googling, I found this:
http://forums.smartclient.com/showthread.php?t=15748
The thing is to Override the getCellStyle method in the listgrid.
Here is the code I use:
#Override
protected String getCellStyle(ListGridRecord record, int rowNum, int colNum) {
if (colNum==6){
return "EC_pointer";
}
return super.getCellStyle(record, rowNum, colNum);
}
and in my CSS file:
.EC_pointer {
cursor: pointer;
}
The major fallout is that you have to know in advance the column number of the field.
Further to my comment and adding information from here I tested the following code which works with SmartGwt2.4 under Firefox 5.0.
demandesGrid.setCanHover(true);
demandesGrid.setShowHover(false);
demandesGrid.addCellHoverHandler(new CellHoverHandler() {
#Override
public void onCellHover(CellHoverEvent event) {
if (event.getColNum() == demandesGrid.getFieldNum("icon")) {
// SC.say(demandesGrid.getChildren()[3].toString());
demandesGrid.getChildren()[3].setCursor(Cursor.POINTER);
} else {
demandesGrid.getChildren()[3].setCursor(Cursor.DEFAULT);
}
}
});
I don't know if the index of the ListGridBody is constant; I found it with the SC.say line.
How about
grid.addCellOverHandler(new CellOverHandler() {
#Override
public void onCellOver(CellOverEvent event) {
//cellOver event to get field and refresh the cell
//grid.refreshCell(i, j);
}
});
The best approach is fully demonstrated here (take a look at how "comments/stats" field is being initialized).
In short, u have to extend ListGrid and override createRecordComponent method. In this method you can make any custom component you like and it will be show in grid cell.
Also ListGrid should be initialized with:
listGrid.setShowRecordComponents(true);
listGrid.setShowRecordComponentsByCell(true);
I noticed that vaadin 6.7.0 beta1 supports to add tooltip for row/cell of a table. However, I did not find any example how to add it.
Is there anybody who can provide some sample?
Use code as below:
table.setItemDescriptionGenerator(new ItemDescriptionGenerator() {
public String generateDescription(Component source, Object itemId, Object propertyId) {
if(propertyId == null){
return "Row description "+ itemId;
} else if(propertyId == COLUMN1_PROPERTY_ID) {
return "Cell description " + itemId +","+propertyId;
}
return null;
}}
You could accomplish this by setting a formfieldfactory. Here you could return a button that only loooks like text with styling CSS. This will let you set a caption on the button. This is obviously a ugly hack. More info about buttons and links in vaadin.
table.setTableFieldFactory(new TableFieldFactory() {
// container is the datasource
// item is the row
// property is the column
//
#Override
public Field createField(Container container, Object itemId, Object propertyId, Component uiContext) {
})
You can't add tooltpis (setDescription) to a row/cell nativly - not yet!
It is already in there issue tracker but don't know when they will implement this feature