JavaFX TableView自定义单元格渲染拆分菜单按钮

时间:2017-06-15 21:31:45

标签: javafx tableview javafx-8

我在java fx表视图组件中使用自定义单元格渲染时出现问题。我能够渲染分割菜单按钮,但只能从第二行表格渲染。

Custom cell render error

下面我将创建的代码生成该图像。

SplitMenuButtonApp.java

package com.example.splimenubtn;

import java.util.ArrayList;
import java.util.List;
import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.SplitMenuButton;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.AnchorPane;
import javafx.stage.Stage;

public class SplitMenuButtonApp extends Application {

 private class Contact {

 private StringProperty firstName;
 private StringProperty lastName;

 public Contact() {}

 public Contact(String fName, String lName) {
  firstName = new SimpleStringProperty(fName);
  lastName = new SimpleStringProperty(lName);
 }

 public String getFirstName() {
  return firstName.get();
 }

 public void setFirstName(String fName) {
  firstName.set(fName);
 }

 public StringProperty firstName() {
  return firstName;
 }

 public String getLastName() {
  return lastName.get();
 }

 public void setLastName(String lName) {
  lastName.set(lName);
 }

 public StringProperty lastName() {
  return lastName;
 }
}

private ObservableList<Contact> data;
protected List<MenuItemFactory<Contact>> menuItemsList;
private TableView<Contact> table;

@Override
public void start(Stage primaryStage) throws Exception {
 // Init data list
 data = FXCollections.observableArrayList();
 data.add(new Contact("Mickey", "Mouse"));
 data.add(new Contact("Donald", "Duck"));
 data.add(new Contact("Fantasy", "Name"));
 initMenuButton();
 SplitMenuButtonFactory<Contact> sMBtn = new SplitMenuButtonFactory<>();
 sMBtn.setMenuItems(menuItemsList);
 SplitMenuButton actions = sMBtn.buildButton();
 // Build the list
 table = new TableView<>();
 TableColumn<Contact, String> col = new TableColumn<>("First Name");
 col.setCellValueFactory(c -> c.getValue().firstName);
 table.getColumns().add(col);
 col = new TableColumn<>("Last Name");
 col.setCellValueFactory(c -> c.getValue().lastName);
 table.getColumns().add(col);
 TableColumn<Contact, SplitMenuButton> aCol = new TableColumn<>("Action");
 aCol.setCellValueFactory(new PropertyValueFactory<>(""));
 aCol.setCellFactory(new ButtonCellFactory<>(actions));
 table.getColumns().add(aCol);
 table.setItems(data);
 AnchorPane root = new AnchorPane();
 AnchorPane.setTopAnchor(table, 5.0);
 AnchorPane.setRightAnchor(table, 5.0);
 AnchorPane.setBottomAnchor(table, 5.0);
 AnchorPane.setLeftAnchor(table, 5.0);
 root.getChildren().add(table);
 Scene s = new Scene(root, 600d, 300d);
 primaryStage.setScene(s);
 primaryStage.setTitle("Split menu button on table row");
 primaryStage.show();
}

public static void main(String[] args) {
 launch(args);
}

private void initMenuButton() {
 if (menuItemsList == null) {
  menuItemsList = new ArrayList<>();
  menuItemsList.add(new MenuItemFactory<Contact>(MenuItemActions.EDIT, "Edit", true).setDataList(table));
menuItemsList.add(new MenuItemFactory<Contact>(MenuItemActions.DELETE, "Delete", false).setDataList(table));
 }
}

}

MenuItemActions.java     package com.example.splimenubtn;

public enum MenuItemActions {
/**
 * Detail item
 */
 DETAILS,
/**
 * Edit/Update item
 */
EDIT,
/**
 * Delete item
 */
 DELETE;
}

MenuItemFactory.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;

 public MenuItemFactory() {}

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

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

 public boolean isDefault() {
  return defaultAction;
 }

 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 REQUESTED ***");
   }
  };
 }

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

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

ButtonCellFactory.java

package com.example.splimenubtn;

import javafx.scene.control.ContentDisplay;
import javafx.scene.control.SplitMenuButton;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.util.Callback;

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

 private SplitMenuButton btn;

 public ButtonCellFactory() {}

 public ButtonCellFactory(SplitMenuButton b) {
  btn = b;
 }

 @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);
     setGraphic(btn);
    }
   }
  };
 }
}

SpliMenuButtonFactory.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;

public SplitMenuButtonFactory() {}

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

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

正如您在图片中看到的那样,使用此代码,我可以创建spli菜单按钮并将其添加到ta表中,但仅在最后一行呈现。

我需要建议在另一行渲染拆分菜单按钮,感谢任何帮助。

1 个答案:

答案 0 :(得分:0)

因为你在每个单元格中使用了相同的按钮,所以它只在单元格值的最后设置一个按钮。

在SplitMenuButtonApp类中删除此行

 SplitMenuButton actions = sMBtn.buildButton();

并替换此行

aCol.setCellFactory(new ButtonCellFactory<>(actions));

以下代码

Callback<TableColumn<Contact, SplitMenuButton>, TableCell<Contact, SplitMenuButton>> actionsCol = new Callback<TableColumn<Contact, SplitMenuButton>, TableCell<Contact, SplitMenuButton>>() {
                @Override
                public TableCell call(final TableColumn<Contact, SplitMenuButton> param) {
                    final TableCell<Contact, SplitMenuButton> cell = new TableCell<Contact, SplitMenuButton>() {
                        SplitMenuButton actions = sMBtn.buildButton();
                        @Override
                        public void updateItem(SplitMenuButton item, boolean empty) {
                            super.updateItem(item, empty);
                            if (empty) {
                                setGraphic(null);
                                setText(null);
                            } else {
                                setGraphic(actions);
                                setText(null);
                            }
                        }
                    };
                    return cell;
            }
 };

aCol.setCellFactory(actionsCol);

我希望这段代码适合你:)