Change icon on a selected row in a Vaadin Grid - java

So, I have a grid called "eventGrid". I added a component column with a down-arrow icon. When a user clicks on a row, addition information is displayed for that row. I want to change the down arrow to an up arrow for the selected row. How can I achieve this?
eventGrid.addColumn(Person::getFirst).setHeader("First Name");
eventGrid.addColumn(Person::getLast).setHeader("Last Name");
eventGrid.addColumn(Person::getNumber).setHeader("Phone Number");
eventGrid.addComponentColumn(item -> {
Icon icon = new Icon("lumo", "angle-down");
return icon;
}).setWidth("6em").setFlexGrow(0);

There are two steps to the solution. First you need to make the renderer react differently for selected items and second, you need to make the grid re-render the row for which the selected status changes.
The first part can be handled in the component renderer:
eventGrid.addComponentColumn(item -> {
String name = eventGrid.getSelectedItems().contains(item) ? "angle-down" : "angle-up";
Icon icon = new Icon("lumo", name);
return icon;
}).setWidth("6em").setFlexGrow(0);
The second part is a listener that uses DataProvider::refreshItem to trigger specific rows to be rendered again. This is implemented through asSingeSelect to get an event that contains both the old and the new value.
eventGrid.asSingleSelect().addValueChangeListener(event -> {
String newValue = event.getValue();
String oldValue = event.getOldValue();
if (newValue != null) {
eventGrid.getDataProvider().refreshItem(newValue);
}
if (oldValue != null) {
eventGrid.getDataProvider().refreshItem(oldValue);
}
});

Assuming you have an in-memory DataProvider:
Grid<Person> eventGrid = new Grid<Person>();
eventGrid.addColumn(Person::getFirst).setHeader("First Name");
eventGrid.addColumn(Person::getLast).setHeader("Last Name");
eventGrid.addColumn(Person::getNumber).setHeader("Phone Number");
eventGrid.addComponentColumn(item -> {
Icon icon = new Icon("lumo", "angle-down");
if (item.equals(eventGrid.asSingleSelect().getValue())) {
icon = new Icon("lumo", "angle-up");
}
return icon;
}).setWidth("6em").setFlexGrow(0);
eventGrid.addSelectionListener(e -> {
eventGrid.getListDataView().refreshAll();
});

Related

new items destroy layout of grid

By refreshing the items within a grid sometimes it happen that the grid shows completely crazy:
That's how I update the data every time. The instance of the Grid stays the same:
dataProvider = new ListDataProvider<>(newItems);
grid.setItems(dataProvider);
Does someone have an idea whether I do something wrong or there is a bug within Vaadin?
Complete code:
if (!columnsIntialized) {
for (Method method : gridProperties) {
Column<T> column = grid.addColumn(data -> {
Object value = method.invoke(data);
return getFormattedValue(value, method.getReturnType());
});
String resourceKey = method.getDeclaredAnnotation(GridProperties.class).resourceKey();
column.setKey(resourceKey);
column.setHeader(AppResources.getString(resourceKey));
int width = method.getDeclaredAnnotation(GridProperties.class).width();
if (width == -1) {
column.setAutoWidth(true);
} else {
column.setWidth(width + "px");
}
}
columnsIntialized = true;
}
dataProvider = new ListDataProvider<>(items);
grid.setItems(dataProvider);
grid.recalculateColumnWidths();
Vaadin 22.0.3 is scheduled to be released on Monday with the fix.

how to combine joptionpane with combobox

i want my joptionpane can combine with combobox,and the combobox data is in database, how i managed that.
i've tried change but the red code always show
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String wel = sdf.format(cal1.getDate());
String NamaFile = "/report/harianMasuk.jasper";
HashMap hash = new HashMap();
String tak = JOptionPane.showOptionDialog(null,id.getSelectedIndex()-1,"Laporan Supplier",JOptionPane.QUESTION_MESSAGE);
try {
hash.put("til", wel);
hash.put("rul", tak);
runReportDefault(NamaFile, hash);
} catch (Exception e) {
JOptionPane.showMessageDialog(rootPane, e);
}
Read the section from the Swing tutorial on Getting User Input From a Dialog.
It demonstrates how to display a combo box in a JOptionPane.
Not exactly sure what you are trying to accomplish but it appears to be that you want to utilize a JComboBox within a JOptionPane dialog window. This ComboBox would be filled with specific data from your database. The User is to select from this ComboBox and your application continues processing based on that selection. If this is the case then you might want to try something like this:
String selectedItem = "";
int selectedItemIndex = -1;
/* Ensure dialog never hides behind anything (use if
the keyword 'this' can not be used or there is no
object to reference as parent for the dialog). */
JFrame iframe = new JFrame();
iframe.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
iframe.setAlwaysOnTop(true);
// ---------------------------------------------------
int btns = JOptionPane.OK_CANCEL_OPTION;
String dialogMessage = "<html>Select the desired item from the Drop-Down "
+ "list<br>you want to work with:<br><br></html>";
String dialogTitle = "Your Fav Items";
/* Up to you to gather what you want placed into the
JComboBox that will be displayed within the JOptionPane. */
String[] comboBoxItems = {"Your", "DB", "Items", "You", "Want", "To",
"Add", "To", "ComboBox"};
BorderLayout layout = new BorderLayout();
JPanel topPanel = new JPanel(layout);
JLabel label = new JLabel(dialogMessage);
topPanel.add(label, BorderLayout.NORTH);
JPanel centerPanel = new JPanel(new BorderLayout(5, 5));
JComboBox cb = new JComboBox();
cb.setModel(new DefaultComboBoxModel<>(comboBoxItems));
cb.setSelectedIndex(-1);
centerPanel.add(cb, BorderLayout.CENTER);
topPanel.add(centerPanel);
// Ensure a selection or Cancel (or dialog close)
while (selectedItemIndex < 0) {
int res = JOptionPane.showConfirmDialog(iframe, topPanel, dialogTitle, btns);
if (res == 2) {
selectedItem = "Selection Option Was Canceled!";
break;
}
selectedItemIndex = cb.getSelectedIndex();
if (res == JOptionPane.OK_OPTION) {
if (selectedItemIndex == -1) {
JOptionPane.showMessageDialog(iframe, "<html>You <b>must</b> "
+ "select something or select <font color=red><b>Cancel</b></font>.",
"Invalid Selection...", JOptionPane.WARNING_MESSAGE);
}
else {
selectedItem = cb.getSelectedItem().toString();
}
}
iframe.dispose();
}
JOptionPane.showMessageDialog(iframe, "<html>You selected the ComboBox item:"
+ "<br><br><b><font color=blue><center>" + selectedItem + "</center>"
+ "</font></b><br></html>", "Selected Item", JOptionPane.INFORMATION_MESSAGE);
iframe.dispose();
With the above code, the Input dialog that will be displayed would look something like this:
It is up to you to find the means to fill the comboBoxItems String Array used within the code above.

JavaFX TableView Click on Header

Is there a way to get an mouse-click on an Header of a Table?
Why i need this?
I have a Table with many Columns. But only a specific witdth for the whole Table.
To avoid scrolling, i want to give each Column an specific width (50 or so), and just if you click on an header, this column will expand so you can read the content. If you click on another header, the previous one collapse.
Hopefully someone can help me:)
Unfortunately there isn't a nice way to do this. The only public API option is to replace the "graphic" of the column with your own label, and then add a mouse listener to that. For this to work you also need to clear any existing column text.
Note that columns by default have click listeners to implement sorting, it seems you don't want this behaviour, so you'll also need to call column.setSortable(false)
#Override
public void start(Stage primaryStage) throws Exception {
TableView<String> tableView = new TableView<>();
TableColumn<String, Object> x = new TableColumn<>("x");
tableView.getColumns().add(x);
TableColumn<String, Object> y = new TableColumn<>("");
tableView.getColumns().add(y);
x.setSortable(false);
y.setSortable(false);
makeHeader(x, "X", 0);
makeHeader(y, "Y", 1);
EventHandler<? super MouseEvent> handler = event -> {
System.out.println("Column clicked " + ((Node)event.getTarget()).getProperties().get("index"));
};
x.getGraphic().addEventFilter(MouseEvent.MOUSE_CLICKED, handler);
y.getGraphic().addEventFilter(MouseEvent.MOUSE_CLICKED, handler);
primaryStage.setScene(new Scene(tableView));
primaryStage.show();
}
private void makeHeader(TableColumn<?, ?> target, String name, int index) {
VBox vBox = new VBox(new Label(name));
vBox.setAlignment(Pos.CENTER);
vBox.getProperties().put("index", index);
target.setGraphic(vBox);
target.setText("");
}
// Step 0: call setOnShown(...).
stage.setOnShown(event -> {
setHeaderClickListeners(); // Call this method when the stage is shown.
});
And then you create a method setHeaderClickListeners(), as follows:
private void setHeaderClickListeners() {
// Step 1: Get the table header row.
TableHeaderRow headerRow = null;
for (Node n : ((TableViewSkin<?>) tableView.getSkin()).getChildren()) {
if (n instanceof TableHeaderRow) {
headerRow = (TableHeaderRow) n;
}
}
if (headerRow == null) {
return;
}
// Step 2: Get the list of the header columns.
NestedTableColumnHeader ntch = (NestedTableColumnHeader) headerRow.getChildren().get(1);
ObservableList<TableColumnHeader> headers = ntch.getColumnHeaders();
// Step 3: Add click listener to the header columns.
for (int i = 0; i < headers.size(); i++) {
TableColumnHeader header = headers.get(i);
final int index = i;
header.setOnMouseClicked(mouseEvent -> {
// Optional:
// Get the TableColumnBase (which is the object responsible
// for displaying the content of the column.)
TableColumnBase column = header.getTableColumn();
// Step 4: Handle double mouse click event.
if (mouseEvent.getButton() == MouseButton.PRIMARY && mouseEvent.getClickCount() == 2) {
P.x("Header cell " + index + " clicked! " + column.getText());
}
});
}
}

Having a String or int with a binding to a Property

I need to make a programm in JavaFX where I need to manage a movie library. I have a tableview that is filled by an observable list. Then I made bindings between the Properties and the Textboxes or Labels next to the tableview. Now the problem is, I have also pictures that are related to the movies, like cinema posters. and at the moment I just use a hardcoded one:
imgPoster = new Image(getClass().getResourceAsStream("../resources/images/posters/" + 5 + ".jpg"));
In the datafile there is one column with the ID of the movie and the same number is also the picture for it. So I need to replace that "5" in the sample code with a binding or so that it actively changes the picture as soon as I click on a row in the tableview.
How do I do that?
edit:
After the first comment i did that:
imgOscars = new Image(getClass().getResourceAsStream("../resources/images/oscar/Oscar-logo.png"));
oscars = new ImageView(imgOscars);
oscars.setPreserveRatio(true);
oscars.setFitHeight(45);
but question stays
Either add a listener to the selected item property in the table (I am just guessing at the model you are using for the table):
TableView<Movie> table = ... ;
table.getSelectionModel().selectedItemProperty().addListener((obs, oldSelectedMovie, newSelectedMovie) -> {
if (newSelectedMovie == null) {
oscars.setImage(null);
} else {
// get image from new selection
Image image = new Image(getClass().getResourceAsStream("../resources/images/oscar/"+newSelectedMoviegetId()+".png"));
oscars.setImage(image);
}
});
or use a binding:
oscars.imageProperty().bind(Bindings.createObjectBinding(() -> {
if (table.getSelectionModel().getSelectedItem() == null) {
return null ;
} else {
Movie selected = table.getSelectionModel().getSelectedItem();
return new Image(getClass().getResourceAsStream("../resources/images/oscar/"+selected.getId()+".png")); ;
},
table.getSelectionModel().selectedItemProperty());

SWT Table with date chooser fields

This is an obvious question but for some reason I haven't found a solution that works. I have a table with 3 columns, the first two are dates, the third one I'm using a Spinner because I want the user to only enter numbers. I need all fields to be editable, but
the field should be editable only when it's in focus, when it's clicked on
the other fields in the same row should not be editable
when the field loses focus, it should go back to "default" mode
These are all normal things that one would expect in an editable table. For some reason I couldn't make this work in SWT. Right now what I have is:
I add a new row, all fields are "default"
I click on the row, all fields turn into editable (the date fields become combo boxes etc.)
after the row losing focus, it remains editable
This is the code that I have right now, it's based on some other code I found on the internet:
// this will happen when you click on the table
table.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Clean up any previous editor control
final TableEditor editor1 = new TableEditor(table);
// The editor must have the same size as the cell and must
// not be any smaller than 50 pixels.
editor1.horizontalAlignment = SWT.LEFT;
editor1.grabHorizontal = true;
editor1.minimumWidth = 50;
Control oldEditor = editor1.getEditor();
if (oldEditor != null)
oldEditor.dispose();
// Identify the selected row
TableItem item = (TableItem)e.item;
if (item == null) return;
// this is the editor for the first column
DateTime startDateTxt = new DateTime(table, SWT.BORDER | SWT.DROP_DOWN | SWT.LONG);
startDateTxt.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
DateTime text = (DateTime)editor1.getEditor();
editor1.getItem().setText(0, new LocalDate(text.getYear(), text.getMonth(), text.getDay()).toString());
}
});
editor1.setEditor(startDateTxt, item, 0);
// and now comes the editor for the 2nd column
//~~~~
// Clean up any previous editor control
final TableEditor editor2 = new TableEditor(table);
// The editor must have the same size as the cell and must
// not be any smaller than 50 pixels.
editor2.horizontalAlignment = SWT.LEFT;
editor2.grabHorizontal = true;
editor2.minimumWidth = 50;
oldEditor = editor2.getEditor();
if (oldEditor != null)
oldEditor.dispose();
// this is the editor for the second column
DateTime endDateTxt = new DateTime(table, SWT.BORDER | SWT.DROP_DOWN | SWT.LONG);
endDateTxt.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
DateTime text = (DateTime)editor2.getEditor();
editor2.getItem().setText(1, new LocalDate(text.getYear(), text.getMonth(), text.getDay()).toString());
}
});
editor2.setEditor(endDateTxt, item, 1);
//~~~~
// Clean up any previous editor control
final TableEditor editor3 = new TableEditor(table);
// The editor must have the same size as the cell and must
// not be any smaller than 50 pixels.
editor3.horizontalAlignment = SWT.LEFT;
editor3.grabHorizontal = true;
editor3.minimumWidth = 50;
oldEditor = editor3.getEditor();
if (oldEditor != null)
oldEditor.dispose();
// this is the editor for the third column
Spinner percentTxt = createNewSpinner(table, SWT.NONE);
percentTxt.addModifyListener(new ModifyListener() {
public void modifyText(ModifyEvent me) {
Spinner text = (Spinner)editor3.getEditor();
editor3.getItem().setText(2, text.getText());
}
});
editor3.setEditor(percentTxt, item, 2);
//~~~~
}
});
As you can see, when the user clicks on the table, I get the current row, and add 3 editors to the row. What I would like to do is get the selected column. I haven't found how to do this. If I get the selected column, then I would be able to create an editor just for the selected cell, and not the whole row.
I also haven't figured out how to dispose the editor after it loses focus. If the user clicks outside the table, then it has clearly happened. But what if the user just clicks on another cell? Then I would have to dispose the old editor and create a new one.
To get the selected column you can call TableItem.getBounds(columnIndex) for each column and see if the selection is within the rectangle returned.

Categories

Resources