消息元素
消息元素实现
所有的 Message.Element 特殊实现类型均定义在包 love.forte.simbot.component.qguild.message 中。
它们都继承了 love.forte.simbot.component.qguild.message.QGMessageElement。
- QGArk
对 API 模块中 Ark 消息的包装体,可用来发送 Ark 消息。
- QGContentText
- QGMarkdown
- QGAttachmentMessage
- QGEmbed
对 API 模块中 Embed 消息的包装体,可用来发送 Embed 消息。
- QGReference
发送消息时,QQ频道的消息引用。与官方发送消息API中的 reference 对应。
- QGReplyTo
发送消息时,指定一个需要回复的目标消息ID。
- QGMedia
- QGKeyboards
对 API 模块中 MessageKeyboards 的包装体,可用来发送包含多行、多按钮的 Markdown 消息按钮。 旧的 QGKeyboard 只包装单个 MessageKeyboard ,自 4.4.0 起应改用 QGKeyboards。
- QGKeyboard
旧的单按钮包装体,只能包装单个 MessageKeyboard ,无法完整表达官方 keyboard.content.rows[].buttons[] 结构。 请使用 QGKeyboards 替代。
发送消息
在simbot中,使用组件的消息元素与使用其他消息元素别无二致, 通常使用 SendSupport 和 ReplySupport 的实现类中提供的 send(...) 和 reply(..) API 发送消息。
前者多由 行为对象 中的一些类型实现(例如QGMember、 QGTextChannel), 而后者则通常由与消息相关的事件实现(例如 QGAtMessageCreateEvent)。
此处以 QGTextChannel 为例, send 可以使用拼接后的消息链、字符串或单独的消息元素作为参数。
val channel: QGTextChannel = ...
channel.send("消息内容")
channel.send("消息内容".toText() + At("user id".ID))
QGTextChannel channel = ...
var sendTask1 = channel.sendAsync("消息内容");
var sendTask2 = channel.sendAsync(Messages.of(
Text.of("文本消息"),
At.of(Identifies.of("user id"))
));
QGTextChannel channel = ...;
channel.sendBlocking("消息内容");
channel.sendBlocking(Messages.of(
Text.of("文本消息"),
At.of(Identifies.of("user id"))
));
QGTextChannel channel = ...;
channel.sendReserve("消息内容")
.transform(SuspendReserves.mono())
.subscribe(receipt -> { ... });
channel.sendReserve(Messages.of(
Text.of("文本消息"),
At.of(Identifies.of("user id"))
))
.transform(SuspendReserves.mono())
.subscribe(receipt -> { ... });
消息撤回
自 5.0 起,QQ 群消息事件的 messageContent 也支持撤回当前收到的群消息:
process<QGGroupMessageCreateEvent> { event ->
event.messageContent.delete()
}
QGGroupAtMessageCreateEvent 的 messageContent 也具有相同能力。 C2C 单聊消息虽然同样提供 messageContent ,但其中没有可用于撤回的目标消息上下文, 因此调用 delete() 时仍不支持撤回。频道消息使用频道消息撤回接口,具体参见 DeleteChannelMessageApi; 旧的 DeleteMessageApi 仅为兼容保留。
从 QGGroup 或 QGFriend 发送、回复消息得到的 QGMessageReceipt 会保留目标 OpenID, 因此可以撤回机器人刚发送的消息。消息链被拆分为多条消息时,聚合回执的 delete() 会依次撤回其中的消息:
val groupReceipt = group.send("临时提示")
groupReceipt.delete()
val friendReceipt = friend.send("C2C 临时消息")
friendReceipt.delete()
群消息与 C2C 单聊消息通常只能撤回发送时间不超过两分钟的消息。 群管理员可以撤回机器人自身和普通成员的消息,普通成员只能撤回机器人自身发送的消息; C2C 单聊撤回接口只能撤回机器人发送给用户的消息。
如果当前实现没有撤回上下文,默认会抛出 UnsupportedOperationException; 可以传入 StandardDeleteOption.IGNORE_ON_UNSUPPORTED 忽略不支持的场景。 QQ 服务端拒绝撤回时默认继续抛出异常,也可以使用 StandardDeleteOption.IGNORE_ON_FAILURE 忽略失败。
按目的地将普通文本作为 Markdown 发送
自 4.5.0 起,可以通过 Bot 配置文件 的 contentAsMarkdownAll 和 contentAsMarkdown ,分别为 CHANNEL、 DMS、 GROUP、 USER 四种目的地控制普通文本的发送载荷。
启用后,普通 Text 、文本消息链以及其中的 @、表情等文本内容会写入 Markdown 的 content 。这不会替代显式构造 QGMarkdown :当你需要发送模板 Markdown 或自行指定 Markdown 内容时,仍应使用 QGMarkdown。
Markdown 消息按钮
自 4.4.0 起,群聊和单聊 Markdown 消息按钮使用 QGKeyboards/MessageKeyboards 表示。 它支持按行组织多个按钮,并在发送体中仍序列化为官方 API 的 keyboard 字段。
val keyboards = QGKeyboards {
content {
row {
button {
renderData("确认", visitedLabel = "已确认", style = 1)
action {
type = 1
data = "confirm"
unsupportTips = "当前客户端暂不支持"
permissionAllAccessible()
}
}
}
row {
addButton(MessageKeyboard.create("template-id"))
}
}
}
group.send(QGMarkdown.create("请选择") + keyboards)
// 只有一行按钮时,也可以直接包装 MessageKeyboards。
val singleRow = MessageKeyboards.create(
listOf(
MessageKeyboard.create("template-a"),
MessageKeyboard.create("template-b")
)
)
group.send(QGMarkdown.create("请选择") + QGKeyboards.create(singleRow))
var keyboards = MessageKeyboards.create(List.of(
MessageKeyboard.create("template-a"),
MessageKeyboard.create("template-b")
));
var sendTask = group.sendAsync(Messages.of(
QGMarkdown.create("请选择"),
QGKeyboards.create(keyboards)
));
var keyboards = MessageKeyboards.create(List.of(
MessageKeyboard.create("template-a"),
MessageKeyboard.create("template-b")
));
group.sendBlocking(Messages.of(
QGMarkdown.create("请选择"),
QGKeyboards.create(keyboards)
));
var keyboards = MessageKeyboards.create(List.of(
MessageKeyboard.create("template-a"),
MessageKeyboard.create("template-b")
));
group.sendReserve(Messages.of(
QGMarkdown.create("请选择"),
QGKeyboards.create(keyboards)
)).transform(SuspendReserves.mono()).subscribe(receipt -> { ... });
11 September 2026