第三节 使用外部库GUI创建UI

上一节

第三章 第三节 使用外部库GUI创建UI

参与编写者:iGxnon

建议学习时间:20分钟

学习要点:掌握GUI创建三种Form的方式以及对交互数据的处理

上一节中我们学习了如何使用NukkitX自带的三种Form表格和组件创建UI,三种Form创建流程都不外乎:

写UI视图 ——> 监听交互并处理。可是人类总是想着各种方法偷懒,这一节就引出外部库 GUI (作者: him188)

GUI: Github地址 ,使创建UI的方式变得更加简洁 注: GUI的maven仓库已经失效,只能下载jar依赖。

有个代替的仓库地址可以用,如下: (smartcmd的仓库)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<repositories>
<repository>
<id>ck</id>
<url>http://finalgame.cn:51460/repository/cookiestudio/</url>
</repository>
</repositories>

<dependencies>
<dependency>
<groupId>moe.him188</groupId>
<artifactId>gui</artifactId>
<version>1.15.1</version>
</dependency>
</dependencies>

另外介绍一下 FormAPI GitHub地址 使用这个依赖也可以达到更简洁创建UI,不过它可能会有一种打不开UI的bug

如图:

这种神秘力量只能用"我代码写错了"才能解释清楚,所以建议使用GUI

注意: 学习本节之前,你得完全掌握 匿名内部类 或者 lambda 表达式 的使用

一: GUI的简单实现原理(没有兴趣的可以直接跳过):

  • GUI提供了不止三种Form表格 (但往上追溯还是那三种)

  • 例如:FormSimple 提供给了一个 onClicked

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    /**
    * 在玩家提交表单后调用 <br>
    * Called on submitted
    *
    * @param listener 调用的方法
    */
    public final ResponsibleFormWindowSimple onClicked(@NotNull BiConsumer<Integer, Player> listener) {
    Objects.requireNonNull(listener);
    this.buttonClickedListener = listener;
    return this;
    }
    /**
    * 在玩家提交表单后调用 <br>
    * Called on submitted
    *
    * @param listener 调用的方法(无 Player)
    */
    public final ResponsibleFormWindowSimple onClicked(@NotNull Consumer<Integer> listener) {
    Objects.requireNonNull(listener);
    this.buttonClickedListener = (id, player) -> listener.accept(id);
    return this;
    }
    /**
    * 在玩家提交表单后调用 <br>
    * Called on submitted
    *
    * @param listener 调用的方法(无参数)
    */
    public final ResponsibleFormWindowSimple onClicked(@NotNull Runnable listener) {
    Objects.requireNonNull(listener);
    this.buttonClickedListener = (id, player) -> listener.run();
    return this;
    }
  • ConsumerBiConsumer都是接口Interface,我们可以使用 lambda 表达式直接写它的实现类。也可以用 匿名内部类去编写。

  • 最后 GUI 帮我们监听事件并执行我们在 ConsumerBiConumer的实现类中的accept方法。

  • 综上:我们无需监听事件,在写UI视图的同时也能将用户交互后的处理写完。

二. 代码部分

  • FormSimple 构造方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    public FormSimple() {
    }

    public FormSimple(String content) {
    super(content);
    }

    public FormSimple(String title, String content) {
    super(title, content);
    }

    public FormSimple(String title, String content, String... buttons) {
    super(title, content, buttons);
    }

    public FormSimple(String title, String content, ElementButton... buttons) {
    super(title, content, buttons);
    }

    public FormSimple(String title, String content, @NotNull List<ElementButton> buttons) {
    super(title, content, buttons);
    }

    构造方法与NukkitX自带的FormWindowSimple差不多。所以不必赘述。

    FormSimple 继承了ResponsibleFormWindowSimple,在 ResponsibleFormWindowSimple 我们常常用的方法有:

    • addButton(ElementButton btn) 添加一个按钮

    • addButton(ElementButton btn, @NotNull ClickListenerSimple clickListener) 添加一个按钮,并在ClickListenerSimple中写入按下这个按钮的处理

      ClickListenerSimple: 最终继承了 Consumer 并且传入了Player这个泛型,我们可以获取player并且操作

      这个方法可以通过添加 ResponsibleButton 来代替。ResponsibleButton是一种可传入点击后处理的特殊按钮

    • setParent(FormWindow form) 设置父表格,用于 goBack(Player player) 这个方法返回上一个表格

    • onClicked(@NotNull Consumer<Integer> listener) 写入处理交互事件的匿名实现类 Integer 返回被按的按钮id-

  • Demo

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    import moe.him188.gui.window.FormSimple; //导入依赖

    class UI {
    public static void menu(Player player) {
    FormSimple form = new FormSimple("我是标题", "我是内容");
    form.addButton(new ElementButton("我是普通按钮")); // 角标 0
    form.addButton(new ResponsibleButton("我是特殊按钮还带图标",
    new ElementButtonImageData("path", "textures/blocks/bedrock.png"),
    () -> player.sendMessage("你按了特殊按钮"))); // 这一行是lambda表达式,如果不清楚使用idea new 一下ClickListenerSimple, 会弹出提示使用匿名内部类 角标 1
    player.showFormWindow(form.onClicked(id -> { //这里也用了lambda
    if(id == 0) player.sendMessage("你按了普通按钮");
    }));
    // 上面onClicked内只需写入第一个按钮的处理方法。因为第二个按钮的处理方法在添加的时候就写了,无需重复!
    }
    }
    • 完成上述代码后,即可达到使用NukkitX自带的Form创建UI的所有流程
    • 综上: 人类的偷懒是永无止境的
  • FormCustom 构造方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    public FormCustom() {
    }

    public FormCustom(String title) {
    super(title);
    }

    public FormCustom(String title, Element... contents) {
    super(title, contents);
    }

    public FormCustom(String title, @NotNull List<Element> contents) {
    super(title, contents);
    }

    public FormCustom(String title, @NotNull List<Element> contents, @NotNull String icon) {
    super(title, contents, icon);
    }

    又是和NK自带的差不多,所以不用多说

    FormCustom内常用方法和FormSimple的差不多,不同点:

    • onResponded(@NotNull Consumer<FormResponseCustom> listener) 这个类似FormSimple中的onClicked。只不过泛型变成了FormResponseCustom 这个上一节我们已经了解,是Custom这个表格的Response,可以获得交互数据
    • 没有了 addButton ,我们讲过: 无法在Custom类型的Form中添加 按钮
    • addElement(Element element) 这个甚至在ResponsibleFormWindowCustom中没有重写,也就意味着这个和NK自带的Custom类型的Form添加组件是一样的。
  • Demo

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    import moe.him188.gui.window.FormCustom; //导入依赖

    class UI {
    public static void menu(Player player) {
    FormCustom form = new FormCustom("我是标题");
    form.addElement(new ElementInput("文本输入框")); //角标 0
    player.showFormWindow(form.onResponded(response -> { //这里也用了lambda
    player.sendMessage(response.getInputResponse(0));
    }));
    }
    }
    • 简洁,明了
  • FormModal 构造方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    public FormModal(String trueButtonText, String falseButtonText) {
    super(trueButtonText, falseButtonText);
    }

    public FormModal(String content, String trueButtonText, String falseButtonText) {
    super(content, trueButtonText, falseButtonText);
    }

    public FormModal(String title, String content, String trueButtonText, String falseButtonText){
    super(title, content, trueButtonText, falseButtonText);
    }

    和NK自带的也是差不多的

    FormModal 常用方法和FormCustom几乎一样,不同点

    • onResponded(@NotNull Consumer<Boolean> listener) 可以看出,这里的泛型是Boolean,于是我们可以直接放到 if 内判断
    • 没有 addElementaddButton
  • Demo

    1
    2
    3
    4
    5
    6
    7
    8
    import moe.him188.gui.window.FormModal; //导入依赖

    class UI {
    public static void menu(Player player) {
    // 一行写完
    player.showFormWindow((new FormModal("标题","内容","确定","取消")).onResponded(bool -> player.sendMessage(bool ? "确定" : "取消")));
    }
    }
    • 压缩再压缩!

三. 结语

  • 学到此处,你应当能够熟练的操控UI,和之前学到的知识结合,写出一个漂亮的公会插件!
  • GUI的表格不止这三种,但是对于我们来说,这三种已经完全够用了,感兴趣的话可以去看看GUI的github上的README,里面写了更多表格的使用方式

上一节

另外附上GUI教程传播授权图