JavaFX How to get data of selected row from Tableview - java

I would like to get data from one selected row
I have this little code
Stlpce aktualne = (Stlpce) tableview_objednavka.getSelectionModel().getSelectedItems();
double aktcena = aktualne.getCena();
But When I run the app I get this error
Caused by: java.lang.ClassCastException: javafx.scene.control.TableView$TableViewArrayListSelectionModel$5 cannot be cast to sample.Stlpce
I use scene builder for create TableView.
Can you help me?
This is solved - the problem was, that I have getSelectedItems(); instead of getSelectedItem();

If you only care about which row is selected, assuming you have a TableView, you can simply use:
List selected = selectionModel.getSelectedItems();
or if your table only allows single row selection:
SomeObject selected = selectionModel.getSelectedItem();
System.out.println(selected.getName());
Try it 100% working...
or try this for better understand Get row data from TableView

The exception is clear in its meaning:
http://docs.oracle.com/javase/7/docs/api/java/lang/ClassCastException.html
The method call you make (https://docs.oracle.com/javase/8/javafx/api/javafx/scene/control/TableView.TableViewSelectionModel.html#getSelectedItems--) returns a reference to an
ObvservableList<T>
Object, which Stlpe does not implement/extend and therefore a Stlpe reference cannot point to such an Object.
Is the Stlpe class the Type class of your ObservableList? If so, maybe you need to find the Stlpe Object in your list:
if (returnedList.size() > 0) {
Stlpe item = returnedList.get(0);
}

In your declaration the TableView should be casted to your object
eg: TableView <Stlpce> tableview_objednavka;

Related

Adding/creating a click event for rows to a Vaadin Grid with SelectionMode.MULTI?

I am trying to create a small application where I have various file locations stored in a Vaadin grid, the grid currently only shows two columns - ID and File Name, and I would like to see as a notification the file location too whenever I click on a row.
Meaning, every time I click a row from the grid I would like it to show me the location, using Notification.show(), like that:
(Please ignore the <b></b>s, they are irrelevant.)
As my grids selection model is MULTI, per default the click listener cannot register which row it is clicked on and selecting the row via checkbox is not what I want to have the data displayed. Simply, I would like to get the item for every row I click and have the location displayed as a notification.
So far, I found a solution for a similar issue but it deals with columns and the rows in Vaadin grids are rather different from what I am used to.
public static <T> void addColumnClickListener(Grid<T> grid, Consumer<Column<T>> listener)
{
String expression = "function(){const col=element.getEventContext(event).column;return col ? col.id : '';}()";
grid.getElement().addEventListener("click", e ->
{
String colId = e.getEventData().getString(expression);
Optional<Column<T>> column = grid.getColumns().stream().filter(col -> colId.equals(col.getId().get())).findFirst();
column.ifPresent(listener);
}
).addEventData(expression);
}
And I am to call the function like that:
addColumnClickListener(grid, column -> Notification.show("fubar"));
This code snippet is from the Vaadin forums and I do not quite understand it. The string expression seems to be that it contains possible JavaScript code and the rest overrides the type of the column. (I think, I really do not understand this snippet fully)
Is there any way to do something similar to the snippet above but for rows?
You can do this with an ItemClickListener on the Grid:
grid.addItemClickListener(item -> {
Notification.show(String.format("File location: %s", item.getLocation()));
});

How to correct a display problem when inserting a row in a JavaFX grid?

I want to insert a new JavaFX bean in a grid using an "insert" button. Everything is fine, except for a display problem. After insertion, a "ghost selection" is displayed lower in the grid, as shown in this screenshot. In this example, a fourth section bean was added and selected as requested. But a fake selection appears 10 lines under the last real bean, where no bean is set for this row.
Has anyone experienced this kind of behavior? Any clue how get rid of this ghost selection? Here is what the code for the insert button looks like:
#FXML
private Button insert;
...
insert.setOnAction(event -> {
JfxBean newBean = createBean();
tableView.getItems().add(newBean);
int index = tableView.getItems().indexOf(newBean);
tableView.getSelectionModel().clearSelection();
tableView.requestFocus();
tableView.scrollTo(index);
tableView.getSelectionModel().focus(index);
tableView.getSelectionModel().select(index);
};
According to javaFX-8 documentation, SelectionModel.java does not expose any focus() method. FocusModel.java does instead. Therefore JVM will fail to compile your presented code.
Below is a possible solution:
insert.setOnAction(event -> {
JfxBean newBean = createBean();
tableView.getItems().add(newBean);
int index = tableView.getItems().indexOf(newBean);
tableView.getSelectionModel().clearSelection();
tableView.requestFocus();
tableView.scrollTo(index);
// below line is the amendment
tableView.getFocusModel().focus(index);
tableView.getSelectionModel().select(index);
};
Finally, adding tableView.refresh() corrected this weird behavior. No more ghost selection.

How to get media details(title, album, etc) from JavaFX Media object and add details to ObservableList?

I have created an ArrayList of media file paths and i want to get details of media file like title and album info in my JavaFX application. I want to add these details in ObservableList. So I created an iterator which gives path of all media files. Inside iterator loop, I have created a Media object. To get media information from Media object, I have created metadata event listener. I got media information in lambda function but i can't able to use them outside of lambda function. If i add info in ObservableList inside event listener lambda function than many null values inserting because of meta data iteration and only one useful information is inserting.
Here is my code:
ObservableList<PlayListModel> playListData = FXCollections.observableArrayList();
Iterator<JMPPlayListItem> it = playList.getIterator();
while(it.hasNext()) {
listMedia = new Media(it.next().getPath());
PlayListModel playListItem = new PlayListModel();
listMedia.getMetadata().addListener((MapChangeListener.Change<? extends String, ? extends Object> c)-> {
if (c.wasAdded()) {
if ("artist".equals(c.getKey())) {
playListItem.setArtist(c.getValueAdded().toString());
} else if ("title".equals(c.getKey())) {
// It prints title of song
System.out.println(c.getValueAdded().toString());
playListItem.setTitle(c.getValueAdded().toString());
} else if ("album".equals(c.getKey())) {
playListItem.setAlbum(c.getValueAdded().toString());
}
}
});
// It print null
System.out.println(playListItem.getTitle());
playListData.add(playListItem);
}
System.out.println(c.getValueAdded().toString()) is printing title of song but outside of lambda function System.out.println(playListItem.getTitle()) prints null. It means playListItem object's values isn't changing. I tried making playListItem final but wouldn't help. I also tried initializing playListItem object and playListData.add(playListItem) inside lambda function but it inserts title with many null title values because of event listener iteration.
I also tested with local variables but I'm not able to get values outside of listener lambda function.
I solved this problem. My solution is pass Media object in bean class's constructor and create another method in bean class that will retrieve media information and update bean object. This method is called through constructor. Now add this bean class's object in ObservableList. Observable list get updated automatically when media information event is fired. Now i can render tableview using ObservableList and using table.refresh() method, i can refresh table data when event is fired.

How to use Nebula NatTable's PreserveSelectionModel?

I am developing an RCP Application, and am using Nebula's NatTable for that.
When it comes to selection, I am failing to understand how I am supposed to use it.
What I want is:
I want to have entire Rows selected. I was able do that using the RowOnlySelectionConfiguration and the RowOnlySelectionBindings.
If I select a row, I want the selection to stay there and not be cleared when some data in that row gets updated. How do I do that?
If a row is selected, and the position of the element in that row changes (e.g. one of the previous elements is removed, and the position changes to index - 1), I want the selection to change the position with the element, so that the same element is selected after the change. How do I do that?
I have seen that the documentation talks about a PreserveSelectionModel that can be used for that:
If you used the PreserveSelectionStructuralChangeEventHandler workaround in previous versions for not clearing the selection on structural changes, you will notice that this workaround will not work anymore. If you still need that behavior, you are now able to achieve the same by configuring and setting a SelectionModel instance like this:
SelectionModel model = new SelectionModel(selectionLayer);
// configure to not clear the selection on structural changes
model.setClearSelectionOnChange(false);
selectionLayer.setSelectionModel(model);
If you expect that the selection should update and move with structural changes (e.g. sorting), try to use the PreserveSelectionModel.
https://www.eclipse.org/nattable/nandn/nandn_120.php
So I guess I have to use the PreserveSelectionModel? But there I can't call setClearSelectionOnChange(false). Does it do that by default?
And how do I use the PreserveSelectionModel? What do I pass in the constructor?
I implement my own BodyLayerStack, in a class called TableBodyLayerStack, where I tried this in the constructor:
public TableBodyLayerStack(IUniqueIndexLayer underlyingLayer) {
super(underlyingLayer);
columnReorderLayer = new ColumnReorderLayer(underlyingLayer);
columnHideShowLayer = new ColumnHideShowLayer(columnReorderLayer);
selectionLayer = new SelectionLayer(columnHideShowLayer, null, true, false);
PreserveSelectionModel<?> selectionModel = new PreserveSelectionModel<>(
selectionLayer, null, null);
selectionLayer.setSelectionModel(selectionModel);
selectionLayer.registerEventHandler(new SelectEventHandler(selectionLayer));
viewportLayer = new ViewportLayer(selectionLayer);
setUnderlyingLayer(viewportLayer);
registerCommandHandler(new CopyDataCommandHandler(selectionLayer));
}
Then, in the contructor of my implementation of the GridLayer, I do this:
// ...
bodyLayer = new TableBodyLayerStack(eventLayer);
// register different selection move command handler that always moves by row
bodyLayer.getSelectionLayer().addConfiguration(new RowOnlySelectionConfiguration<T>());
// register selection bindings that will perform row selections instead of cell selections
// registering the bindings on a layer that is above the SelectionLayer will consume the
// commands before they are handled by the SelectionLayer
bodyLayer.addConfiguration(new RowOnlySelectionBindings());
// ...
But this is giving me NullPointerExceptions in the PreserveSelectionModel.
Error while painting table: null
java.lang.NullPointerException
at org.eclipse.nebula.widgets.nattable.selection.preserve.PreserveSelectionModel.getRowPositionByRowObject(PreserveSelectionModel.java:520)
at org.eclipse.nebula.widgets.nattable.selection.preserve.PreserveSelectionModel.createMarkerPoint(PreserveSelectionModel.java:559)
at org.eclipse.nebula.widgets.nattable.selection.preserve.PreserveSelectionModel.getSelectionAnchor(PreserveSelectionModel.java:531)
at org.eclipse.nebula.widgets.nattable.selection.SelectionLayer.getSelectionAnchor(SelectionLayer.java:276)
at org.eclipse.nebula.widgets.nattable.selection.SelectionLayer.getConfigLabelsByPosition(SelectionLayer.java:415)
at org.eclipse.nebula.widgets.nattable.layer.AbstractLayerTransform.getConfigLabelsByPosition(AbstractLayerTransform.java:316)
at org.eclipse.nebula.widgets.nattable.layer.AbstractIndexLayerTransform.getConfigLabelsByPosition(AbstractIndexLayerTransform.java:318)
at org.eclipse.nebula.widgets.nattable.layer.CompositeLayer.getConfigLabelsByPosition(CompositeLayer.java:553)
at org.eclipse.nebula.widgets.nattable.layer.cell.AbstractLayerCell.getConfigLabels(AbstractLayerCell.java:48)
at org.eclipse.nebula.widgets.nattable.layer.AbstractLayer.getCellPainter(AbstractLayer.java:354)
at org.eclipse.nebula.widgets.nattable.layer.AbstractLayerTransform.getCellPainter(AbstractLayerTransform.java:336)
at org.eclipse.nebula.widgets.nattable.layer.AbstractLayerTransform.getCellPainter(AbstractLayerTransform.java:336)
at org.eclipse.nebula.widgets.nattable.layer.AbstractLayerTransform.getCellPainter(AbstractLayerTransform.java:336)
at org.eclipse.nebula.widgets.nattable.layer.AbstractIndexLayerTransform.getCellPainter(AbstractIndexLayerTransform.java:340)
at org.eclipse.nebula.widgets.nattable.layer.AbstractLayerTransform.getCellPainter(AbstractLayerTransform.java:336)
at org.eclipse.nebula.widgets.nattable.layer.AbstractIndexLayerTransform.getCellPainter(AbstractIndexLayerTransform.java:340)
at org.eclipse.nebula.widgets.nattable.layer.CompositeLayer.getCellPainter(CompositeLayer.java:586)
at org.eclipse.nebula.widgets.nattable.painter.layer.CellLayerPainter.paintCell(CellLayerPainter.java:171)
at org.eclipse.nebula.widgets.nattable.painter.layer.CellLayerPainter.paintLayer(CellLayerPainter.java:81)
at org.eclipse.nebula.widgets.nattable.painter.layer.GridLineCellLayerPainter.paintLayer(GridLineCellLayerPainter.java:106)
at org.eclipse.nebula.widgets.nattable.selection.SelectionLayerPainter.paintLayer(SelectionLayerPainter.java:95)
at org.eclipse.nebula.widgets.nattable.layer.CompositeLayer$CompositeLayerPainter.paintLayer(CompositeLayer.java:913)
at org.eclipse.nebula.widgets.nattable.painter.layer.NatLayerPainter.paintLayer(NatLayerPainter.java:43)
at org.eclipse.nebula.widgets.nattable.NatTable.paintNatTable(NatTable.java:408)
at org.eclipse.nebula.widgets.nattable.NatTable.paintControl(NatTable.java:403)
...
I guess it is because I pass null values in the constructor of my PreserveSelectionModel. But how do I use it instead? What do I have to pass as arguments for the constructor? Where do I get the values from?
Any help is appreciated.
you are on the wrong track to achieve your goals. First I will answer your questions:
So I guess I have to use the PreserveSelectionModel?
No, the PreserveSelectionModel is intended to preserve the selection for cell selections. You want to preserve the selection for whole rows. So you need to use the RowSelectionModel.
But there I can't call setClearSelectionOnChange(false). Does it do that by default?
Yes
But this is giving me NullPointerExceptions in the PreserveSelectionModel. I guess it is because I pass null values in the constructor of my PreserveSelectionModel.
Yes
What do I have to pass as arguments for the constructor? Where do I get the values from?
The second parameter is IRowDataProvider<T>, so it is the IDataProvider for the body.
The third parameter is IRowIdAccessor<T>. You need to create an implementation that provides an unique id, so a row can be identified without knowing the position or index in the underlying collection.
So what you need to do is something like this:
selectionLayer.setSelectionModel(new RowSelectionModel<Person>(
selectionLayer, bodyDataProvider, new IRowIdAccessor<Person>() {
#Override
public Serializable getRowId(Person rowObject) {
return rowObject.getId();
}
}));
But of course you need to provide the IDataProvider and also the IRowIdAccessor to your TableBodyLayerStack if you want to keep it generic.
Also note that you don't have to call SelectionLayer#registerEventHandler() yourself! This is done internally by calling SelectionLayer#setSelectionModel().
You can find several examples in the NatTable Examples Application at https://www.eclipse.org/nattable/ (the Try it! button on the right side).
For your question the Tutorial Examples -> Layers -> Selection -> RowSelectionExample seems to be the one to look at.

Items decorations in a TreeViewer

I have the following problem:
I'm preparing an editor in Eclipse and one of the tab contains TreeViewer to show items in the tree. Each item has a name and a value, which is editable.
The problem I need to indicate to user that value is incorrect (e.g. exceeds a given range). My idea is to decorate incorrect cells with a warning or error icon which will be shown also after editing is complete.
Does anybody have an idea how to decorate items in the tree? I was experimenting with ControlDecoration class but without success.
Thanks in advance,
Marcin
PS. I'm limited to Eclipse 3.4
There are two ways that this can be done. If your TreeViewer displays objects that are instances of EObject (generated by EMF. If your don't understand this part, skip to the next paragraph :)), you can change these EObject's "XyzItemProvider" so that their "getImage" method return a decorated image instead of the "plain" image... and that's it for EMF objects, nothing else needs to be changed.
If you're displaying "classic" Java Objects, you'll have to change your TreeViewer's LabelProvider in order to decorate the Image. This is done through the TreeViewer#setLabelProvider() method.
What you will need then is "how to decorate an Image", which is done through code such as this :
public class MyLabelProvider extends DecoratingLabelProvider {
public Image getImage(Object element) {
Image image = super.getImage(element);
List<Object> images = new ArrayList<Object>(2);
images.add(image);
images.add(<Image of the decorator>);
labelImage = new ComposedImage(images); // This will put the second of the "images" list (the decorator) above the first (the element's image)
return decoratedImage;
}
[...]
}
You then need to give your tree viewer this label provider :
TreeViewer treeViewer = new TreeViewer(...);
treeViewer.setLabelProvider(new MyLabelProvider(new LabelProvider()); // new LabelProvider()... or your previous label provider if you have one.

Categories