Java 8 个方法引用与 javafx
Java 8 method references with javafx
我刚刚开发了一个 JavaFX 应用程序这二十个不同的页面。每个页面都有一个 table,我想在每个 table 上放置一个上下文菜单。
基本上,将上下文菜单放置到 table 的代码总是相同的,但我希望方法引用可以在这里提供一点帮助。
这是实际的代码片段:
resultTable.setRowFactory(new Callback<TableView<InterfaceModel>, TableRow<InterfaceModel>>() {
@Override
public TableRow<InterfaceModel> call(TableView<InterfaceModel> tableView) {
final TableRow<InterfaceModel> row = new TableRow<InterfaceModel>();
final ContextMenu rowMenu = new ContextMenu();
MenuItem editItem = new MenuItem("EDIT");
editItem.setOnAction(event -> {
// action if edit was selected
});
我想要这样的东西:
ContextMenuHelper helper = new ContextMenuHelper(resultTable);
helper.addItem("Edit", [referenceToAMethod]);
helper.addItem("Item 2", [referenceToADifferentMethod]);
我的意思是这个助手创建了上下文菜单。这个助手需要的只是条目的标签和在选择此条目后调用的方法。
使用 java 8 中的方法引用可能吗?
谢谢,
豪克
如果您只想定义一个方法来创建一个 MenuItem
,那么这很简单:您只需要决定您需要的功能接口,该接口将采用方法引用(或 lambda)的参数, ETC)。例如。如果方法签名不带参数并且具有 void
return 类型,则可以使用 Runnable
:
public MenuItem createItem(String text, Runnable handler) {
MenuItem item = new MenuItem(text);
item.setOnAction(e -> handler.run());
}
您可能希望菜单项事件处理程序能够访问行中的 table 项,在这种情况下,它需要对该行的引用:
public <T> MenuItem createItem(String text, TableRow<T> row, Consumer<T> handler) {
MenuItem item = new MenuItem(text);
item.setOnAction(e -> handler.accept(row.getItem()));
}
那你可以做
TableView<InterfaceModel> table = new TableView<>();
ContextMenuHelper helper = new ContextMenuHelper();
table.setRowFactory(t -> {
TableRow<InterfaceModel> row = new TableRow<>();
ContextMenu menu = new ContextMenu();
row.setContextMenu(menu);
menu.getItems().addItem(helper.createItem("Edit", row, this::edit));
// etc...
});
和
private void edit(InterfaceModel model) {
// ...
}
你实际上并没有问,但我猜你真的想要的是 "helper" class 实际设置行工厂并创建所有菜单等. 这有点难构造,因为你需要完全在行工厂内部构建上下文菜单,所以你需要知道所有的菜单项,然后才能真正设置行工厂。为此,您可能需要考虑构建器模式:
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.MenuItem;
import javafx.scene.control.TableRow;
import javafx.scene.control.TableView;
import javafx.util.Callback;
public class TableRowContextMenuBuilder<T> {
private final List<MenuItemConfig<T>> items ;
private boolean built ;
public TableRowContextMenuBuilder() {
this.items = new ArrayList<>();
}
public static <T> TableRowContextMenuBuilder<T> create(Class<T> type) {
return new TableRowContextMenuBuilder<>();
}
public TableRowContextMenuBuilder<T> addItem(String text, Consumer<T> handler) {
if (built) {
throw new IllegalStateException("Row factory is already built: cannot add new items");
}
items.add(new MenuItemConfig<T>(text, handler));
return this ;
}
public TableRowContextMenuBuilder<T> addItem(String text, Runnable handler) {
return addItem(text, t -> handler.run());
}
public Callback<TableView<T>, TableRow<T>> build() {
if (built) {
throw new IllegalStateException("Cannot build row factory more than once");
}
built = true ;
return t -> {
TableRow<T> row = new TableRow<>();
ContextMenu menu = new ContextMenu();
row.setContextMenu(menu);
items.stream()
.map(config -> config.asMenuItem(row))
.forEach(menu.getItems()::add);
return row ;
};
}
public void buildForTable(TableView<T> table) {
table.setRowFactory(build());
}
private static class MenuItemConfig<T> {
private final String text ;
private final Consumer<T> handler ;
MenuItemConfig(String text, Consumer<T> handler) {
this.text = text;
this.handler = handler;
}
MenuItem asMenuItem(TableRow<T> row) {
MenuItem item = new MenuItem(text);
item.setOnAction(e -> handler.accept(row.getItem()));
return item ;
}
}
}
现在你可以做到
TableView<InterfaceModel> table = new TableView<>();
TableViewContextMenuBuilder.create(InterfaceModel.class)
.menuBuilder.addItem("Edit", this::edit);
.menuBuilder.addItem("Item 2", this::handleOtherItem);
// ...
.buildForTable(table);
定义了适当的方法:
private void edit(InterfaceModel model) { /* ... */}
private void handleOtherItem(InterfaceModel model) { /* ... */}
我刚刚开发了一个 JavaFX 应用程序这二十个不同的页面。每个页面都有一个 table,我想在每个 table 上放置一个上下文菜单。
基本上,将上下文菜单放置到 table 的代码总是相同的,但我希望方法引用可以在这里提供一点帮助。
这是实际的代码片段:
resultTable.setRowFactory(new Callback<TableView<InterfaceModel>, TableRow<InterfaceModel>>() {
@Override
public TableRow<InterfaceModel> call(TableView<InterfaceModel> tableView) {
final TableRow<InterfaceModel> row = new TableRow<InterfaceModel>();
final ContextMenu rowMenu = new ContextMenu();
MenuItem editItem = new MenuItem("EDIT");
editItem.setOnAction(event -> {
// action if edit was selected
});
我想要这样的东西:
ContextMenuHelper helper = new ContextMenuHelper(resultTable);
helper.addItem("Edit", [referenceToAMethod]);
helper.addItem("Item 2", [referenceToADifferentMethod]);
我的意思是这个助手创建了上下文菜单。这个助手需要的只是条目的标签和在选择此条目后调用的方法。
使用 java 8 中的方法引用可能吗?
谢谢, 豪克
如果您只想定义一个方法来创建一个 MenuItem
,那么这很简单:您只需要决定您需要的功能接口,该接口将采用方法引用(或 lambda)的参数, ETC)。例如。如果方法签名不带参数并且具有 void
return 类型,则可以使用 Runnable
:
public MenuItem createItem(String text, Runnable handler) {
MenuItem item = new MenuItem(text);
item.setOnAction(e -> handler.run());
}
您可能希望菜单项事件处理程序能够访问行中的 table 项,在这种情况下,它需要对该行的引用:
public <T> MenuItem createItem(String text, TableRow<T> row, Consumer<T> handler) {
MenuItem item = new MenuItem(text);
item.setOnAction(e -> handler.accept(row.getItem()));
}
那你可以做
TableView<InterfaceModel> table = new TableView<>();
ContextMenuHelper helper = new ContextMenuHelper();
table.setRowFactory(t -> {
TableRow<InterfaceModel> row = new TableRow<>();
ContextMenu menu = new ContextMenu();
row.setContextMenu(menu);
menu.getItems().addItem(helper.createItem("Edit", row, this::edit));
// etc...
});
和
private void edit(InterfaceModel model) {
// ...
}
你实际上并没有问,但我猜你真的想要的是 "helper" class 实际设置行工厂并创建所有菜单等. 这有点难构造,因为你需要完全在行工厂内部构建上下文菜单,所以你需要知道所有的菜单项,然后才能真正设置行工厂。为此,您可能需要考虑构建器模式:
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.MenuItem;
import javafx.scene.control.TableRow;
import javafx.scene.control.TableView;
import javafx.util.Callback;
public class TableRowContextMenuBuilder<T> {
private final List<MenuItemConfig<T>> items ;
private boolean built ;
public TableRowContextMenuBuilder() {
this.items = new ArrayList<>();
}
public static <T> TableRowContextMenuBuilder<T> create(Class<T> type) {
return new TableRowContextMenuBuilder<>();
}
public TableRowContextMenuBuilder<T> addItem(String text, Consumer<T> handler) {
if (built) {
throw new IllegalStateException("Row factory is already built: cannot add new items");
}
items.add(new MenuItemConfig<T>(text, handler));
return this ;
}
public TableRowContextMenuBuilder<T> addItem(String text, Runnable handler) {
return addItem(text, t -> handler.run());
}
public Callback<TableView<T>, TableRow<T>> build() {
if (built) {
throw new IllegalStateException("Cannot build row factory more than once");
}
built = true ;
return t -> {
TableRow<T> row = new TableRow<>();
ContextMenu menu = new ContextMenu();
row.setContextMenu(menu);
items.stream()
.map(config -> config.asMenuItem(row))
.forEach(menu.getItems()::add);
return row ;
};
}
public void buildForTable(TableView<T> table) {
table.setRowFactory(build());
}
private static class MenuItemConfig<T> {
private final String text ;
private final Consumer<T> handler ;
MenuItemConfig(String text, Consumer<T> handler) {
this.text = text;
this.handler = handler;
}
MenuItem asMenuItem(TableRow<T> row) {
MenuItem item = new MenuItem(text);
item.setOnAction(e -> handler.accept(row.getItem()));
return item ;
}
}
}
现在你可以做到
TableView<InterfaceModel> table = new TableView<>();
TableViewContextMenuBuilder.create(InterfaceModel.class)
.menuBuilder.addItem("Edit", this::edit);
.menuBuilder.addItem("Item 2", this::handleOtherItem);
// ...
.buildForTable(table);
定义了适当的方法:
private void edit(InterfaceModel model) { /* ... */}
private void handleOtherItem(InterfaceModel model) { /* ... */}