来自字符串列表的 ContextMenu 子菜单

ContextMenu sub-menus from a List of Strings

我正在尝试制作一个类似于下图中的上下文菜单:

我想显示其中一个组中的字符串列表。

这可以通过使用 controlsFX 库中的 ActionGroup 来实现。为了重现图片中的示例,请使用该代码:

    public class HelloActionGroup{
            Label label = new Label("hello world, I'm a label");
            label.setContextMenu(ActionUtils.createContextMenu(action));
                    private Collection<? extends Action> action = Arrays.asList(
                            new ActionGroup("Group 1", new DummyAction("Action 1")),
                                                       new DummyAction("Action 2"),
                                                       new DummyAction("Action 3"))
                    );
                
                private static class DummyAction extends Action{
                        public DummyAction(String name){
                            super(name);
                        }
                    }
}

为了在您的代码中制作该代码 运行,只需将该标签放在您的根父级中:

yourPaneName.getChildren().add(label);

如您所见,我必须对“第 1 组”中显示的所有项目进行硬编码,即“Action1”、“Action2”和“Action3”。如何在“第 1 组”中放置一个字符串列表?

类似于:

List<String> list = new ArrayList<>();
list.add("Action1");
list.add("Action2");
list.add("Action3");
private Collection<? extends Action> action = Arrays.asList(
                                new ActionGroup("Group 1", new DummyAction(list)));

更新:使用循环在上下文菜单中插入列表项,设法真正接近:

List<String> list = new ArrayList<>();
        list.add("string1");
        list.add("string2");
        for (String str: list) {
            action2.add(new ActionGroup("action1",new DummyAction(str)));
        }

结果: string2 显示在所选 (action1)

下方

我知道它正在创建多个 ActionGroup 因为语句“new ActionGroup”,现在我只需要找到一种方法来只创建一个 ActionGroup 并向其中添加多个 DummyAction(strings from list)

菜单只是一种 MenuItem,所以只要可以放置 MenuItem,就可以放置 Menu,而 Menu 又可以有子菜单项。

就 ControlsFX 控件而言,我不知道它们,因为我不使用它们。但是对于您所描述的问题,我看不出需要它们。如果在您的应用程序中,您确实需要使用 ControlsFX 来实现其他功能,也许您可​​以调整此解决方案中的信息来实现这一点。

例子

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.stage.Stage;

import java.util.stream.IntStream;

public class SubContext extends Application {
    private static final int N_ITEMS_PER_MENU = 5;

    @Override
    public void start(Stage stage) {
        MenuGenerator menuGenerator = new MenuGenerator();

        Menu[] contextTopicMenus = menuGenerator.generateMenus(
                N_ITEMS_PER_MENU
        );

        for (Menu menu: contextTopicMenus) {
            menu.getItems().setAll(
                    menuGenerator.generateMenuItems(
                            N_ITEMS_PER_MENU
                    )
            );
        }

        ContextMenu contextMenu = new ContextMenu(contextTopicMenus);

        Label label = new Label("Click for context");
        label.setContextMenu(contextMenu);

        Pane layout = new VBox(label);
        layout.setPadding(new Insets(10));

        stage.setScene(new Scene(layout));
        stage.show();
    }

    private static final class MenuGenerator {
        private final Lorem lorem = new Lorem();
        
        public Menu generateMenu() {
            return new Menu(lorem.nextString());
        }

        public MenuItem generateMenuItem() {
            return new MenuItem(lorem.nextString());
        }

        public Menu[] generateMenus(int n) {
            return IntStream.range(0, n)
                    .mapToObj(i -> generateMenu())
                    .toArray(Menu[]::new);
        }

        public MenuItem[] generateMenuItems(int n) {
            return IntStream.range(0, n)
                    .mapToObj(i -> generateMenuItem())
                    .toArray(MenuItem[]::new);
        }
    }
    
    private static final class Lorem {
        private static final String[] lorem = "lorem ipsum dolor sit amet consectetur adipiscing elit sed do eiusmod tempor incididunt ut labore et dolore magna aliqua".split(" ");
        private int idx = 0;

        public String nextString() {
            return lorem[getAndIncrementIdx()];
        }

        private int getAndIncrementIdx() {
            int retVal = idx;

            idx = (idx + 1) % lorem.length;

            return retVal;
        }
    }

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

示例中花哨的菜单生成器和 lorem 只是为了便于数据生成。对于您的实际应用程序,您不需要它,相反,您将创建适用的菜单、菜单项及其适当的操作函数并使用它们而不是生成的。

首先,创建一个ActionGroup的集合,然后从同类型的集合(ActionGroup)中创建一个单独的实例。之后,运行 一个循环,以便将列表中的每个项目插入到 ActionGroup 实例中。它是这样的:

Collection<ActionGroup> action = new LinkedList<>();
        ActionGroup actionGroup = new ActionGroup("My list items:");
        List<String> list = new ArrayList<>();
        list.add("string 1");
        list.add("string 2");
        list.add("string 3");
        for (String str : list) {
            actionGroup.getActions().add(new DummyAction(str));
        }
        action.add(actionGroup);
        node.setContextMenu(ActionUtils.createContextMenu(action));

结果: