使用javafx引用Java 8方法 [英] Java 8 method references with javafx

查看:131
本文介绍了使用javafx引用Java 8方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我刚开发了这个二十个不同页面的JavaFX应用程序。每个页面都有一个表格,我想在每个表格上放置一个上下文菜单。

I just developed a JavaFX applications this twenty different pages. Each page has a table and I wanted to place a context menu on each table.

基本上,它总是将上下文菜单放到表中的相同代码,但我希望方法引用可以帮助一点点。

Basically its always the same code for placing the context menu to the table but I am hoping that method references can help here a little bit.

这是实际的代码片段:

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
        });

我想要类似的东西那个:

And I want something like that:

ContextMenuHelper helper = new ContextMenuHelper(resultTable);
helper.addItem("Edit", [referenceToAMethod]);
helper.addItem("Item 2", [referenceToADifferentMethod]);

我的意思是这个助手创建了上下文菜单。所有这些帮助程序需要的是条目的标签和选择此条目后调用的方法。

What I mean is that this helper creates the context menu. All this helper needs is the label for the entry and a method to call after selection of this entry.

使用java 8中的方法引用是否可行?

Is that possible with the method-refereces from java 8?

谢谢,
Hauke

Thanks, Hauke

推荐答案

如果您只想定义一种创建 MenuItem 的方法,那么它很容易:你只需要决定你需要的参数的功能接口,该参数采用方法引用(或lambda等)。例如。如果方法签名没有参数并且 void 返回类型,则可以使用 Runnable

If you just want to define a method for creating a MenuItem, then it's easy enough: you just need to decide on the functional interface you will need for the parameter that takes the method reference (or lambda, etc). E.g. if the method signature takes no parameters and has void return type, you could use Runnable:

public MenuItem createItem(String text, Runnable handler) {
    MenuItem item = new MenuItem(text);
    item.setOnAction(e -> handler.run());
}

您可能希望菜单项事件处理程序能够访问表中的项目该行,在这种情况下,它需要对该行的引用:

You probably want the menu item event handler to have access to the table item in the row, in which case it would need a reference to the row:

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...
});

with

private void edit(InterfaceModel model) {
    // ...
}

你实际上没有问过什么,但我猜你真的想要,是为了帮助类实际设置行工厂并创建所有菜单等等。这有点难构造,因为您需要在行工厂内完全构建上下文菜单,因此您需要知道所有菜单项才能实际设置行工厂。为此,您可能需要考虑构建器模式:

What you didn't actually ask, but I'm sort of guessing you really want, is for the "helper" class to actually set the row factory and create all the menus, etc. This is a bit harder to structure, because you need to entirely build the context menu inside the row factory, so you need to know all the menu items before you can actually set the row factory. For this, you probably want to consider a builder pattern:

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引用Java 8方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆