Repository navigation
Click Callbacks
HimDSL 的槽位支持四种点击回调:
A slot supports four click callbacks:
| 字段 | 触发时机 |
|---|---|
onLeftClick |
普通左键点击 |
onRightClick |
普通右键点击 |
onShiftLeftClick |
Shift + 左键 |
onShiftRightClick |
Shift + 右键 |
| Field | Trigger |
|---|---|
onLeftClick |
plain left-click |
onRightClick |
plain right-click |
onShiftLeftClick |
shift + left-click |
onShiftRightClick |
shift + right-click |
只注册你要用的。没注册的点击不做任何事——注意这是"不做任何事",不是"触发其他回调"。
Register only what you need. Unregistered clicks do nothing — note: they do nothing, they do not fall through to another callback.
回调是一个 lambda,点击时执行:
A callback is a lambda executed on click:
var slot = new GUISlot(Material.DIAMOND);
slot.name = "§a点击领取";
slot.onLeftClick = () -> {
player p = @s;
runcmd(p.name, "give " + p.name + " diamond 1");
runcmd(p.name, "msg §a你获得了钻石!");
gui.close(p);
};
回调 lambda 没有参数,用 @s 拿点击的玩家。
The lambda takes no arguments; use @s to get the clicking player.
在 GUI 点击回调里,@s 是点击者。这是 GUI 交互的核心——每个玩家打开同一个 GUI,点击时回调里的 @s 指向那个点击的玩家。
Inside a GUI click callback, @s is the clicker. This is central to GUI interaction: multiple players may have the same GUI open, and @s inside the callback refers to the one who clicked.
slot.onLeftClick = () -> {
player p = @s; // 点击的玩家
runcmd(p.name, "msg 你点了我");
};
不需要在 GUI 上"记住当前玩家"——@s 自动处理。
No need to track "the current player" on the GUI — @s handles it.
同一个槽位可以注册多种点击:
One slot may register several click types:
slot.onLeftClick = () -> {
player p = @s;
runcmd(p.name, "msg 左键:购买");
};
slot.onRightClick = () -> {
player p = @s;
runcmd(p.name, "msg 右键:查看详情");
};
两种点击各自触发各自的逻辑,互不干扰。
Each click type fires its own logic independently.
回调里可以访问闭包捕获的变量,包括 gui 和 slot 本身:
Callbacks capture enclosing variables by closure, including gui and slot:
var gui = new GUI(1, "菜单");
slot.onLeftClick = () -> {
player p = @s;
gui.close(p); // 关闭这个 GUI
};
这让你可以在回调里调用 gui.close、修改槽位显示、重新刷新界面。
This lets callbacks call gui.close, change slot display, or refresh the interface.
slot.onLeftClick = () -> {
player p = @s;
runcmd(p.name, "msg 操作完成");
gui.close(p);
};
slot.onLeftClick = () -> {
player p = @s;
// 假设有经济系统
runcmd("CONSOLE", "eco take " + p.name + " 100");
runcmd("CONSOLE", "give " + p.name + " diamond 1");
runcmd(p.name, "msg §a购买成功");
};
slot.onLeftClick = () -> {
player p = @s;
gui.close(p);
// 假设 menu2 是另一个已定义的 GUI
// menu2.open(p);
};
int count;
slot.onLeftClick = () -> {
count += 1;
slot.lore = {
"§7已点击: §e" + count,
"§7再点一次试试"
};
gui.update(0, 4);
};
修改槽位后必须 update,否则玩家看不到变化。
Must update after modifying a slot, or the player sees no change.
int main() {
var gui = new GUI(3, "§6简易商店");
// 商品槽位
var diamondSlot = new GUISlot(Material.DIAMOND);
diamondSlot.name = "§b钻石";
diamondSlot.lore = {
"§7价格: §e100 金币",
"§a左键购买"
};
diamondSlot.onLeftClick = () -> {
player p = @s;
runcmd("CONSOLE", "eco take " + p.name + " 100");
runcmd("CONSOLE", "give " + p.name + " diamond 1");
runcmd(p.name, "msg §a购买成功");
gui.close(p);
};
gui[1][4] = diamondSlot;
// 关闭按钮
var closeSlot = new GUISlot(Material.BARRIER);
closeSlot.name = "§c关闭";
closeSlot.onLeftClick = () -> {
gui.close(@s);
};
gui[2][8] = closeSlot;
// 装饰玻璃
var glass = new GUISlot(Material.GRAY_STAINED_GLASS_PANE);
glass.name = " ";
for (int r = 0; r < 3; r = r + 1) {
for (int c = 0; c < 9; c = c + 1) {
if (gui[r][c].icon == Material.AIR) {
// 只在空格上铺玻璃,避免覆盖已有物品
gui[r][c] = glass;
}
}
}
gui.updateAll();
gui.open(@p);
}
注意最后一段:先放商品,后铺装饰,装饰时检查 gui[r][c].icon == Material.AIR 才写入,避免覆盖。顺序很重要。
Note the ordering: place products first, then decorate, checking gui[r][c].icon == Material.AIR before writing. Order matters.
HimDSL 不会把 Shift 点击回退到普通点击。如果你只注册了 onLeftClick:
HimDSL does not fall back from shift-clicks to plain clicks. With only onLeftClick registered:
-
左键 → 触发
onLeftClick。 -
Shift + 左键 → 什么也不做。
-
Left-click → fires
onLeftClick. -
Shift + left-click → does nothing.
想要 Shift + 左键也响应,就显式注册:
To respond to shift-left too, register it explicitly:
slot.onLeftClick = () -> { /* 普通左键 */ };
slot.onShiftLeftClick = () -> { /* Shift 左键 */ };
或者,如果两种点击效果相同,在 lambda 里写一份逻辑,两处引用它(通过具名函数)。
Or, if both clicks do the same, put the logic in a named function and reference it from both.
slot.onLeftClick = () -> {
player p = @p; // ✗ 可能拿到别人
};
@p 是最近的玩家,不一定是点击者。用 @s。
slot.onLeftClick = () -> {
slot.name = "已购买";
// ✗ 忘记 gui.update(...)
};
slot.onLeftClick = () -> {
runcmd(p.name, "msg 处理中...");
sleep(2000); // ✗ 卡主线程
runcmd(p.name, "msg 完成");
};
sleep 会阻塞服务器。用 @BukkitRunnable 拆分执行。
@p is the nearest player, not necessarily the clicker. Use @s.
After modifying the slot, call gui.update(...).
Blocks the server. Use @BukkitRunnable instead.
-
四种回调:
onLeftClick、onRightClick、onShiftLeftClick、onShiftRightClick。 -
用无参 lambda 赋值。
-
@s在回调里是点击者。 -
未注册的点击什么也不做,不会回退。
-
修改槽位后要
update。 -
不要在回调里
sleep。 -
Four callbacks:
onLeftClick,onRightClick,onShiftLeftClick,onShiftRightClick. -
Assign a no-arg lambda.
-
@sinside the callback is the clicker. -
Unregistered clicks do nothing; no fallback.
-
updateafter modifying the slot. -
No
sleepinside callbacks.
下一章 [onClose 回调 / onClose] 讲界面被玩家关闭时如何响应。
Next, [onClose 回调 / onClose] covers reacting when the player closes the GUI.
- 首页 / Home
- 安装与快速开始 / Installation & Quick Start
- 第一个脚本 / Your First Script
- 命令速查 / Command Reference
- 自动执行脚本 / Auto-run Scripts
- 定义函数 / Defining Functions
- 函数重载 / Function Overloading
- Lambda 表达式 / Lambda Expressions
- 函数式接口 / Functional Interfaces
- 选择器总览 / Selectors Overview
- 选择器过滤器 / Selector Filters
- EntityRef 引用 / EntityRef
- 占位符参考 / Placeholders Reference
- PlaceholderAPI 桥接 / PAPI Bridge
- 创建 GUI / Creating a GUI
- GUISlot 槽位 / GUISlot
- 点击回调 / Click Callbacks
- onClose 回调 / onClose Callback
- GUI 刷新 / GUI Refresh
- 数学函数 / Math Built-ins
- 高精度计算 / BigDecimal Built-ins
- 字符串函数 / String Built-ins
- 集合函数 / Collection Built-ins
- 文件 I/O / File I/O
- 命令与 sleep / Commands & sleep