PatrickT80
PatrickT80

Reputation: 65

JavaFX TableView get row from button cell

Referring to question JavaFX TableView custom cell rendering split menu button, i'm able to render split menu button in every row. I've updated my code as suggested by James_D and in the answer by Keyur Bhanderi. The question is about get value of the row where split menu is located without selecting row before click.

Update: Added images to view output

The images below show the output, every button i click.

Row selected click frist action button

Row selected click second action button

Updated SplitMenuCellFactory.java

package com.example.splimenubtn;

import java.util.List;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.util.Callback;

public class SplitMenuCellFactory<S, T> implements Callback<TableColumn<S, T>, TableCell<S, T>> {

 private List<MenuItemFactory<T>> menuItems;

 public SplitMenuCellFactory() {}

 public SplitMenuCellFactory(List<MenuItemFactory<T>> items) {
  menuItems = items;
 }

 @Override
 public TableCell<S, T> call(TableColumn<S, T> param) {
  return new TableCell<S, T>() {
   @Override
   public void updateItem(T item, boolean empty) {
    super.updateItem(item, empty);
    if (empty) {
     setGraphic(null);
     setText(null);
    } else {
     setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
     if (getTableRow() != null) {
      setGraphic(new SplitMenuButtonFactory<>(menuItems, getTableRow().getIndex()).buildButton());
     }
    }
   }
  };
 }
}

Update, adding missing class

SplitMenuButtonFactory.java

package com.example.splimenubtn;

 import java.util.List;
 import javafx.scene.control.MenuItem;
 import javafx.scene.control.SplitMenuButton;

 public class SplitMenuButtonFactory<T> {

  private List<MenuItemFactory<T>> menuItems;
  private int rIndex = 0;

  public SplitMenuButtonFactory(List<MenuItemFactory<T>> items) {
   menuItems = items;
  }

  public SplitMenuButtonFactory(List<MenuItemFactory<T>> items, int rI) {
   menuItems = items;
   rIndex = rI;
  }

  public SplitMenuButton buildButton() {
   SplitMenuButton menuBtn = new SplitMenuButton();
   // menuBtn.getItems().addAll(menuItems);
   for (MenuItemFactory<?> mIF : menuItems) {
    MenuItem btn = mIF.setRowIndex(rIndex).buildMenuItem();
     if (mIF.isDefault()) {
     menuBtn.setText(btn.getText());
     menuBtn.setOnAction(btn.getOnAction());
    }
    menuBtn.getItems().add(btn);
   }
  return menuBtn;
 }
}

MenuItemsFactory.java

package com.example.splimenubtn;

import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.control.MenuItem;
import javafx.scene.control.TableView;

public class MenuItemFactory<S> {

 private MenuItemActions itemType;
 private String itemLbl;
 private TableView<S> table;
 private boolean defaultAction;
 private int rIndex = 0;

 public MenuItemFactory(MenuItemActions itemType, String itemLabel, boolean dA) {
  this.itemType = itemType;
  itemLbl = itemLabel;
  defaultAction = dA;
 }

 public MenuItemFactory(MenuItemActions itemType, String itemLabel, TableView<S> t, boolean dA) {
  this.itemType = itemType;
  itemLbl = itemLabel;
  defaultAction = dA;
  table = t;
 }

 public MenuItemFactory<S> setDataList(TableView<S> t) {
  table = t;
  return this;
 }

 public boolean isDefault() {
  return defaultAction;
 }

 public MenuItemFactory<S> setRowIndex(int rI) {
  rIndex = rI;
  return this;
 }

 public MenuItem buildMenuItem() {
  MenuItem mI = new MenuItem();
  switch (itemType) {
   case DETAILS:
    mI.setText(itemLbl);
    mI.setOnAction(handleDetails());
   break;
  case EDIT:
    mI.setText(itemLbl);
    mI.setOnAction(handleEdit());
   break;
   case DELETE:
    mI.setText(itemLbl);
    mI.setOnAction(handleDelete());
   break;
   default:
   break;
  }
  return mI;
 }

 private EventHandler<ActionEvent> handleDetails() {
  return new EventHandler<ActionEvent>() {
   @Override
   public void handle(ActionEvent aE) {
    System.out.println("*** DETAIL REQUEST ***");
   }
  };
 }

 private EventHandler<ActionEvent> handleEdit() {
  return new EventHandler<ActionEvent>() {
   @Override
   public void handle(ActionEvent aE) {
    System.out.println("*** EDIT REQUESTED ***");
    table.getSelectionModel().select(rIndex);
    System.out.println("*** " + table.getSelectionModel().getSelectedItem().toString() + " ***");
   }
  };
 }

 private EventHandler<ActionEvent> handleDelete() {
  return new EventHandler<ActionEvent>() {
   @Override
   public void handle(ActionEvent aE) {
    System.out.println("*** DELETE REQUESTED ***");
    System.out.println("*** " + table.getSelectionModel().getSelectedItem().toString() + " ***");
   }
  };
 }
}

But when i click on the button, i'm getting always last value.

How can i get the object in the row where button is?

Any help or suggestion that point me to right direction is appreciated.

Upvotes: 1

Views: 3838

Answers (1)

fabian
fabian

Reputation: 82491

Simply use the TableCell to retrieve the value in the onAction event handler (or whatever you use in the product of the SplitMenuButtonFactory you're not showing to us).

Simplified example

public static SplitMenuButton createSplitMenuButton(final TableCell cell) {
    SplitMenuButton result = new SplitMenuButton();

    result.setOnAction(evt -> {
        TableRow row = cell.getTableRow();
        System.out.println("row item: " +row.getItem());
    });

    return result;
}

Furthermore it's better to reuse the SplitMenuButton in the cell and updating it instead of recerating it every time the cell item changes.

@Override
public TableCell<S, T> call(TableColumn<S, T> param) {
    return new TableCell<S, T>() {

        private final SplitMenuButton button = createSplitMenuButton(this);

        {
            setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
        }

        @Override
        public void updateItem(T item, boolean empty) {
            super.updateItem(item, empty);

            if (empty) {
                setGraphic(null);
            } else {
                updateMenuButton(button, item); // placeholder for updating the button according to the new item

                setGraphic(button);
            }
        }
    };
}

Upvotes: 1

Related Questions