Select Row on Rightclick JavaFX TableView - java

I'm having a table view and I have added a context menu to that. When I right first time it highlight the row and show the context menu. But when I right click again on some other row it show the menu but doesn't highlight the new row and clear the old selected row.
How can I clear the old selected row and highlight the new row ?
I added the context menu using setRowFactorymethod
mytblView.setRowFactory(new Callback<TableView<Rowdata>, TableRow<Rowdata>>() {
#Override
public TableRow<Rowdata> call(TableView<Rowdata> tableView) {
final TableRow<Rowdata> row = new TableRow<>();
final ContextMenu contextMenu = new ContextMenu();
final MenuItem mnuItemAnalyze = new MenuItem("Analyze");
mnuItemAnalyze.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
//logic for menu item
}
});
contextMenu.getItems().add(mnuItemAnalyze);
// Set context menu on row, but use a binding to make it only show for non-empty rows:
row.contextMenuProperty().bind(Bindings.when(row.emptyProperty()).then((ContextMenu) null).otherwise(contextMenu));
return row;
}
});
}

Related

Why does my Menu Listener not respond to first click?

So I have a menu for a table item and I try to add a MenuListener for it. While debugging, on first click on the table, only the listener is created and the event is not handled. On the second click, it behaves as it should.
I have the following code:
private void createWidgets(Composite composite)
{
//some tabs are created
for (int i = 0; i < numberOfTabs; i++)
{
//tabs are populated with tables
this.tables[i].getTableViewer().getTable().addMenuDetectListener(new MenuDetectListener() {
#Override
public void menuDetected(MenuDetectEvent e) {
Table table = (Table) e.getSource();
addMenuForTable(table);
}
});
}
this.tabFolder.setSelection(0);
}
private void addMenuForTable(Table table)
{
final Menu someMenu = new Menu(table);
table.setMenu(someMenu);
someMenu.addMenuListener(new ChangingMenu(this, table, someMenu));
}
And my custom ChangingMenu class looks like this
public class ChangingMenu extends MenuAdapter {
private Menu someMenu;
private SomeView view;
private Table table;
public ChangingMenu(SomeView view, Table viewer, Menu someMenu) {
this.view = view;
this.someMenu= someMenu;
this.table = viewer;
}
#Override
public void menuShown(MenuEvent e) {
MenuItem[] menuItems = this.logChangeMenu.getItems();
for (int i = 0; i < menuItems.length; i++) {
menuItems[i].dispose();
}
addMenu(this.table);
}
private void addMenu(Table table) {
MenuItem menuItem= new MenuItem(this.someMenu, SWT.NONE);
menuItem.setText("Some text here");
//here I have a listener for this menu item that opens some dialog on item click
}
}
So on fist click on table, the Changing Menu is created, but the showMenu is not called somehow. Only on second click I get to see the menu item declared there.
Adding the menu in a menu detect listener is too late, there is no need to use this listener here. Just add the menu as soon as the table has been created:
addMenuForTable(this.tables[i].getTableViewer().getTable());

TreeTableView TableMenuButton setonAction

Is there any possible way to listen or to override the default TableMenuButton setonAction?
Something like this?
TreeTableView ttv = new TreeTableView();
ttv.setTableMenuButtonVisible(true);
ttv.setOnMouseClicked((MouseEvent event) -> {
....
});
I would like to know which column has been set to visible or invisible.
Any help is greatly appreciated.
I created an example about how to adapt the TableView's menu button. The TreeTableView is just similar. What you need to do is to get the ContextMenu. You can get it either by reflection or by using a lookup. Once you have it, you can do whatever you want with it.
I also filed a change request so that the context menu becomes accessible since the current implementation isn't satisfactory.
Here's the modified code of the lookup version:
public class TableUtils {
/**
* Make table menu button visible and replace the context menu with a custom context menu via reflection.
* The preferred height is modified so that an empty header row remains visible. This is needed in case you remove all columns, so that the menu button won't disappear with the row header.
* IMPORTANT: Modification is only possible AFTER the table has been made visible, otherwise you'd get a NullPointerException
* #param tableView
*/
public static void addCustomTableMenu( TreeTableView tableView) {
// enable table menu
tableView.setTableMenuButtonVisible(true);
// replace internal mouse listener with custom listener
setCustomContextMenu( tableView);
}
private static void setCustomContextMenu( TreeTableView table) {
TreeTableViewSkin<?> tableSkin = (TreeTableViewSkin<?>) table.getSkin();
// get all children of the skin
ObservableList<Node> children = tableSkin.getChildren();
// find the TableHeaderRow child
for (int i = 0; i < children.size(); i++) {
Node node = children.get(i);
if (node instanceof TableHeaderRow) {
TableHeaderRow tableHeaderRow = (TableHeaderRow) node;
// setting the preferred height for the table header row
// if the preferred height isn't set, then the table header would disappear if there are no visible columns
// and with it the table menu button
// by setting the preferred height the header will always be visible
// note: this may need adjustments in case you have different heights in columns (eg when you use grouping)
double defaultHeight = tableHeaderRow.getHeight();
tableHeaderRow.setPrefHeight(defaultHeight);
for( Node child: tableHeaderRow.getChildren()) {
// child identified as cornerRegion in TableHeaderRow.java
if( child.getStyleClass().contains( "show-hide-columns-button")) {
// get the context menu
ContextMenu columnPopupMenu = createContextMenu( table);
// replace mouse listener
child.setOnMousePressed(me -> {
// show a popupMenu which lists all columns
columnPopupMenu.show(child, Side.BOTTOM, 0, 0);
me.consume();
});
}
}
}
}
}
/**
* Create a menu with custom items. The important thing is that the menu remains open while you click on the menu items.
* #param cm
* #param table
*/
private static ContextMenu createContextMenu( TreeTableView table) {
ContextMenu cm = new ContextMenu();
// create new context menu
CustomMenuItem cmi;
// select all item
Label showAll = new Label("Show all");
showAll.addEventHandler(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
for (Object obj : table.getColumns()) {
((TreeTableColumn<?, ?>) obj).setVisible(true);
}
}
});
cmi = new CustomMenuItem(showAll);
cmi.setHideOnClick(false);
cm.getItems().add(cmi);
// deselect all item
Label hideAll = new Label("Hide all");
hideAll.addEventHandler(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
for (Object obj : table.getColumns()) {
((TreeTableColumn<?, ?>) obj).setVisible(false);
}
}
});
cmi = new CustomMenuItem(hideAll);
cmi.setHideOnClick(false);
cm.getItems().add(cmi);
// separator
cm.getItems().add(new SeparatorMenuItem());
// menu item for each of the available columns
for (Object obj : table.getColumns()) {
TreeTableColumn<?, ?> tableColumn = (TreeTableColumn<?, ?>) obj;
CheckBox cb = new CheckBox(tableColumn.getText());
cb.selectedProperty().bindBidirectional(tableColumn.visibleProperty());
cmi = new CustomMenuItem(cb);
cmi.setHideOnClick(false);
cm.getItems().add(cmi);
}
return cm;
}
}

Context Menu on a row of TableView?

I am using JavaFX and my application has a table and I can add elements to the table but I want to create a context menu that displays on a row when I right click on that row.
What I have...
In Scene Builder I have a method that runs on when the Context Menu is activated but that isn't exactly what I want. This would be fine really because I am programmatically grab the selected item from the table whenever I want. The issue, if I keep what I currently have, is getting the context menu to popup at the selected element.
contextMenu is the context menu with menu items.
connectedUsers is the TableView
The following is the closest I can get, but this shows the context menu at the bottom of the TableView
contextMenu.show(connectedUsers, Side.BOTTOM, 0, 0);
I believe that the best solution would be this as discussed in here.
table.setRowFactory(
new Callback<TableView<Person>, TableRow<Person>>() {
#Override
public TableRow<Person> call(TableView<Person> tableView) {
final TableRow<Person> row = new TableRow<>();
final ContextMenu rowMenu = new ContextMenu();
MenuItem editItem = new MenuItem("Edit");
editItem.setOnAction(...);
MenuItem removeItem = new MenuItem("Delete");
removeItem.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
table.getItems().remove(row.getItem());
}
});
rowMenu.getItems().addAll(editItem, removeItem);
// only display context menu for non-empty rows:
row.contextMenuProperty().bind(
Bindings.when(row.emptyProperty())
.then((ContextMenu) null)
.otherwise(rowMenu);
return row;
}
});
JavaFX 8 (with Lambda):
MenuItem mi1 = new MenuItem("Menu item 1");
mi1.setOnAction((ActionEvent event) -> {
System.out.println("Menu item 1");
Object item = table.getSelectionModel().getSelectedItem();
System.out.println("Selected item: " + item);
});
ContextMenu menu = new ContextMenu();
menu.getItems().add(mi1);
table.setContextMenu(menu);
See also:
https://docs.oracle.com/javase/8/javafx/api/javafx/scene/control/ContextMenu.html
try this..
ContextMenu cm = new ContextMenu();
MenuItem mi1 = new MenuItem("Menu 1");
cm.getItems().add(mi1);
MenuItem mi2 = new MenuItem("Menu 2");
cm.getItems().add(mi2);
table.addEventHandler(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent t) {
if(t.getButton() == MouseButton.SECONDARY) {
cm.show(table, t.getScreenX(), t.getScreenY());
}
}
});

Showing a right click menu for a SWT TableItem?

Is it possible to show a right click menu on table items with SWT? The menu would be different for every item, e.g for some rows, some of the menu items would be enabled, for others, they would be disabled. So, each row would need its own menu, and when setting up the menu i'd need a way to identify which row I was working with.
Any ideas?
Listening for SWT.MouseDown, as suggested by #user4793956, is completely useless. The context menu is always brought up, no need to call setVisible(true). Quite contrary, you need to cancel the SWT.MenuDetect event, if you do not want the menu to pop up.
This works for me:
// Create context menu
Menu menuTable = new Menu(table);
table.setMenu(menuTable);
// Create menu item
MenuItem miTest = new MenuItem(menuTable, SWT.NONE);
miTest.setText("Test Item");
// Do not show menu, when no item is selected
table.addListener(SWT.MenuDetect, new Listener() {
#Override
public void handleEvent(Event event) {
if (table.getSelectionCount() <= 0) {
event.doit = false;
}
}
});
Without using a DynamicTable:
Menu contextMenu = new Menu(table);
table.setMenu(contextMenu);
MenuItem mItem1 = new MenuItem(contextMenu, SWT.None);
mItem1.setText("Menu Item Test.");
table.addListener(SWT.MouseDown, new Listener(){
#Override
public void handleEvent(Event event) {
TableItem[] selection = table.getSelection();
if(selection.length!=0 && (event.button == 3)){
contextMenu.setVisible(true);
}
}
});
table = new DynamicTable(shell, SWT.BORDER | SWT.FULL_SELECTION);
table.addMenuDetectListener(new MenuDetectListener()
{
#Override
public void menuDetected(MenuDetectEvent e)
{
int index = table.getSelectionIndex();
if (index == -1)
return; //no row selected
TableItem item = table.getItem(index);
item.getData(); //use this to identify which row was clicked.
//The popup can now be displayed as usual using table.toDisplay(e.x, e.y)
}
});
More details: http://www.eclipsezone.com/eclipse/forums/t49734.html

Adding button to the GXT Grid cell

I use GXT 2.2.0 and I need to make a button for deleting rows. It was an idea to make checkboxes and create a button "delete", but I already have checkbox for choosing rows by users to use them further and decided it is not "user-friendly". So how to add button to the cell?
to add the button to the cell I had to do this:
column = new ColumnConfig();
column.setRenderer(new GridCellRenderer() {
#Override
public Object render(ModelData model, String property, ColumnData config, int rowIndex, int colIndex, ListStore store, Grid grid) {
final int row = store.indexOf((PropertyItem) model);
Button b = new Button("remove", new SelectionListener<ButtonEvent>() {
#Override
public void componentSelected(ButtonEvent ce) {
Window.alert("row index= " + row);
remove(row, customerId);
}
});
b.setIconStyle("/gxt/images/gxt/icons/delete.png");
return b;
}
});

Categories