组件方法速查
用法总述(两种写法)见 README.md;所有类型经 @yue 引用。
通用约定:
- 除单独说明外,所有
make均有可选参数style : Array[(String, &StyVal)]—— 单个数组混装数值(Double)与字符串值 (创建即应用的样式键值对),下表不再重复列出。 on_*为回调注册方法。
窗口 Window
let win = @yue.Window::make(
title="主窗口",
size=Some((960.0, 640.0)),
center=true)
win.on_close(fn(_w) { @yue.quit() })
win.set_content(content_view)Window::make 入参(无 style,窗口没有父布局):
| 参数 | 类型 | 默认 | 说明 |
|---|---|---|---|
| title | String | "" | 标题 |
| size | (Double, Double)? | None | 内容区尺寸(宽, 高) |
| on_close | (Window) -> Unit | 空操作 | 关闭回调 |
| center | Bool | false | 创建后居中 |
常用方法:
| 方法 | 用途 |
|---|---|
| set_title(t) | 设标题 |
| set_content(v) | 设内容视图 |
| set_content_size(w, h) / get_content_size() | 设 / 读内容区尺寸 |
| center() / activate() | 居中 / 激活到前台 |
| maximize() / unmaximize() / is_maximized() | 最大化 |
| set_fullscreen(b) / is_fullscreen() | 全屏 |
| set_always_on_top(b) | 置顶 |
| set_resizable(b) / is_resizable() | 可缩放 |
| set_maximizable(b) / set_minimizable(b) | 标题栏按钮开关 |
| set_has_shadow(b) / has_shadow() | 窗口阴影 |
| set_menubar(mb) | 挂菜单条 |
| on_close(fn(_w)) | 关闭回调 |
| set_should_close(fn() -> Bool) | 返回 false 拦截关闭 |
Window::new_with_options 入参(无边框 / 透明 / 浮层窗口):
| 参数 | 类型 | 默认 | 说明 |
|---|---|---|---|
| frame | Bool | true | false 为无边框 |
| transparent | Bool | false | 透明背景 |
| no_activate | Bool | false | 不抢焦点(浮层 / 面板类窗口) |
容器 Container
let col = @yue.Container::make(style=[("padding", 12.0)])
col.add_child(child)入参只有 style(见文首)。默认 flexDirection=column、 alignItems=stretch,水平排列在 style 里传 ("flexDirection", "row"); 键的解析规则见 docs/layout.md。
| 方法 | 用途 |
|---|---|
| add_child(v) | 添加子视图(任何 ViewLike) |
| on_draw(fn(painter)) | 自绘 |
标签 Label
let l = @yue.Label::make("文本", style=[("color", "#356AA0")])
l.set_text("新文本")| 参数 | 类型 | 默认 | 说明 |
|---|---|---|---|
| text | String | 必填 | 初始文本 |
| 方法 | 用途 |
|---|---|
| set_text(t) | 改文本 |
按钮 Button(含复选框 / 单选框)
let b = @yue.Button::make("确定", on_click=fn() { ... })
let c = @yue.Button::make("启用", button_type=Checkbox, checked=false,
on_click=fn() { ... }) // 回调里用 is_checked() 读状态
let r = @yue.Button::make("主题甲", button_type=Radio, checked=true, on_click=...)
b.set_title("新标题")| 参数 | 类型 | 默认 | 说明 |
|---|---|---|---|
| title | String | 必填 | 按钮文本 |
| button_type | ButtonType | Normal | Normal / Checkbox / Radio |
| on_click | () -> Unit | 空操作 | 点击回调 |
| checked | Bool | false | 初始勾选(Checkbox / Radio) |
同一父容器内的 Radio 自动互斥;初始回调与双通知见文末「固有坑」。
| 方法 | 用途 |
|---|---|
| set_title(t) | 改文本 |
| is_checked() / set_checked(b) | 读 / 设勾选 |
| on_click(fn()) | 点击回调 |
单行输入 Entry
let e = @yue.Entry::make(text="预填", entry_type=Password)
e.on_activate(fn() { check(e.get_text()) })| 参数 | 类型 | 默认 | 说明 |
|---|---|---|---|
| text | String | "" | 初始文本 |
| entry_type | EntryType | Normal | Normal / Password |
| width_chars | Int | -1 | 初始宽度(字符数;-1 为不限制) |
| on_activate | () -> Unit | 空操作 | 回车回调(不带参数,取文本用 get_text) |
| on_text_change | () -> Unit | 空操作 | 内容变化回调(同上) |
| 方法 | 用途 |
|---|---|
| get_text() / set_text(t) | 读 / 设文本 |
| on_activate(fn()) | 回车回调 |
| on_text_change(fn()) | 内容变化回调 |
多行文本 TextEdit
let t = @yue.TextEdit::make(text="正文")
t.on_text_change(fn() { sync(t.get_text()) })| 参数 | 类型 | 默认 | 说明 |
|---|---|---|---|
| text | String | "" | 初始文本 |
| on_text_change | () -> Unit | 空操作 | 内容变化回调 |
| 方法 | 用途 |
|---|---|
| get_text() / set_text(t) | 读 / 设全文 |
| undo() / redo() / can_undo() / can_redo() | 撤销重做 |
| cut() / copy() / paste() | 剪贴板编辑 |
| select_all() / select_range(start, end) | 选区 |
| get_text_in_range(start, end) | 读区间文本 |
| insert_text(t) / insert_text_at(t, pos) | 插入 |
| delete() / delete_range(start, end) | 删除 |
| get_text_bounds_height() | 文本实际高度(自适应高度布局用) |
| on_text_change(fn()) | 内容变化回调 |
滑块 Slider
let s = @yue.Slider::make(value=0.0, range=Some((0.0, 100.0)), step=Some(1.0))
s.on_value_change(fn() { update(s.get_value()) })| 参数 | 类型 | 默认 | 说明 |
|---|---|---|---|
| value | Double | 0.0 | 初值 |
| range | (Double, Double)? | None | 量程(min, max) |
| step | Double? | None | 步长 |
| on_value_change | () -> Unit | 空操作 | 值变化回调(不带参数,取值用 get_value) |
| 方法 | 用途 |
|---|---|
| get_value() / set_value(v) | 读 / 设当前值 |
| set_range(min, max) / set_step(d) | 量程 / 步长 |
| on_value_change(fn()) | 值变化回调 |
| on_sliding_complete(fn()) | 拖动结束回调 |
进度条 ProgressBar
let p = @yue.ProgressBar::make(value=0.43)| 参数 | 类型 | 默认 | 说明 |
|---|---|---|---|
| value | Double | 0.0 | 初值,取值 0..1 |
| indeterminate | Bool | false | 往返滚动模式 |
| 方法 | 用途 |
|---|---|
| set_value(v) | 设值(0..1) |
| set_indeterminate(b) | 往返滚动模式 |
选择器 Picker
let p = @yue.Picker::make(items=["甲", "乙", "丙"], selected=0)
p.on_selection_change(fn() { refresh(p.get_selected_item_index()) })| 参数 | 类型 | 默认 | 说明 |
|---|---|---|---|
| items | Array[String] | [] | 选项列表 |
| selected | Int | 0 | 初始选中下标 |
| on_selection_change | () -> Unit | 空操作 | 选择变化回调 |
| 方法 | 用途 |
|---|---|
| add_item(t) / remove_item_at(i) / clear() | 维护选项 |
| select_item_at(i) | 选中 |
| get_selected_item() / get_selected_item_index() | 读选中项 |
| on_selection_change(fn()) | 选择变化回调 |
组合框 ComboBox(可编辑)
let c = @yue.ComboBox::make(items=["红", "绿"])
c.on_text_change(fn() { refresh(c.get_text()) })| 参数 | 类型 | 默认 | 说明 |
|---|---|---|---|
| items | Array[String] | [] | 选项列表 |
| selected | Int | 0 | 初始选中下标 |
| on_selection_change | () -> Unit | 空操作 | 选项变化回调 |
| on_text_change | () -> Unit | 空操作 | 编辑区文本变化回调 |
| 方法 | 用途 |
|---|---|
| add_item(t) / select_item_at(i) / get_selected_item() | 同 Picker |
| get_text() / set_text(t) | 读 / 设编辑区文本 |
| on_selection_change(fn()) / on_text_change(fn()) | 两个变化回调 |
日期 DatePicker
let d = @yue.DatePicker::make(epoch=Some(1700000000L))
d.on_date_change(fn() { show(d.get_date()) })| 参数 | 类型 | 默认 | 说明 |
|---|---|---|---|
| epoch | Int64? | None | 初始日期(Unix epoch 秒) |
| on_date_change | () -> Unit | 空操作 | 日期变化回调 |
| 方法 | 用途 |
|---|---|
| get_date() / set_date(epoch_seconds) | 读 / 设日期(epoch 秒) |
| on_date_change(fn()) | 日期变化回调 |
隐藏步进器等定制用 DatePicker::new_with(DatePickerOptions)。
分组 Group / 滚动 Scroll / 分隔线 Separator
let g = @yue.Group::make("标题", content_view)
let sc = @yue.Scroll::make(content_view, policy=Some((Automatic, Automatic)))
let sep = @yue.Separator::make(Horizontal) // 或 VerticalGroup::make 入参:
| 参数 | 类型 | 默认 | 说明 |
|---|---|---|---|
| title | String | 必填 | 标题 |
| content | T : ViewLike | 必填 | 内容视图(内部走 set_content) |
Scroll::make 入参:
| 参数 | 类型 | 默认 | 说明 |
|---|---|---|---|
| content | T : ViewLike | 必填 | 内容视图 |
| content_size | (Double, Double)? | None | 内容尺寸;不传则整页滚动跟随内容自然高度 |
| policy | (ScrollPolicy, ScrollPolicy)? | None | 平台滚动条策略(水平, 垂直):Always / Never / Automatic;显式传入时保留平台滚动条 |
| overlay | Bool | true | 滚动条形态:Linux/macOS 请求平台悬浮样式;Windows 默认形态为自绘悬浮细条(overlay=false 或显式 policy 时保留平台经典条) |
Separator::make 入参:orientation : Orientation = Horizontal(Horizontal / Vertical)。
| 方法 | 用途 |
|---|---|
| Group::set_title(t) | 改标题 |
| Scroll::set_content(v) | 换内容 |
| Scroll::set_content_size(w, h) | 显式设内容尺寸 |
| Scroll::refresh_content_size() | 按当前内容重算滚动范围(内容在 set_content 之后才挂入或明显长高时调用) |
| Scroll::set_scroll_position(h, v) | 设滚动位置 |
| Scroll::set_scrollbar_policy(h, v) / set_overlay_scrollbar(b) | 滚动条 |
| Scroll::get_scroll_position_x/y() / get_max_scroll_position_x/y() | 读位置与最大滚动量 |
| Scroll::on_scroll(fn() -> Bool) | 滚动位置变化(滚轮/拖拽/程序滚动统一触发;返回 true 拦截默认处理) |
Hover 组 HoverGroup
组内任意位置(含全部子控件)悬停即整组进入 hover 态——子控件触发的事件同样改变组的样式。
@declarative.hover_group(
@declarative.vbox([ /* 卡片内容:标题 / 按钮 / 输入框等 */ ], style=[("padding", 14.0)]),
radius=8.0,
on_change=fn(h, host) {
// 底色高亮已内置;光标等额外反馈在回调里对 host 应用
@yue.View::set_cursor(host, @yue.Cursor::new(if h { @yue.Hand } else { @yue.Default }))
},
)| 参数 | 类型 | 默认 | 说明 |
|---|---|---|---|
| child | Node | 必填 | 组内容 |
| hover_bg / base_bg | String | 主题 fill_hover / 空(透明) | 悬停 / 常态底色(自绘) |
| radius | Double | 0 | 底色圆角 |
| on_change | (Bool, Container) -> Unit | 空函数 | hover 态翻转时回调(仅变化时),携带组容器 |
| style | 数组 | [] | 组容器布局样式 |
判定机制是指针位置轮询(100ms,读全局指针坐标与组屏幕矩形比对),不依赖容器的 enter/leave——GTK 下子容器/原生控件的事件窗口会独占指针事件,容器层收不到 enter;Windows 下同一机制工作,行为跨平台一致。
悬浮滚动条 OverlayScroll
Windows 上 scroll() 的默认形态(overlay=true 且未显式 policy)即走这条自绘悬浮细条;本组件是其显式选用入口——需要在 Linux/macOS 上使用同款自绘悬浮细条(替代平台悬浮样式)时采用,三平台形态统一。行为:隐藏平台滚动条,自绘主题色细条叠在内容右缘——滚动/悬停浮现,停顿约 1 秒两级渐隐,可沿轨道拖拽,窄条上滚轮转发给内容滚动。
独立使用(内容已是 Node 时):
@declarative.overlay_scroll(
@declarative.vbox([@declarative.label("第 1 行"), /* … */]),
style=[("height", 180.0)], // 容器样式;高度由外层布局或显式给定
)| 参数 | 类型 | 默认 | 说明 |
|---|---|---|---|
| content | Node | 必填 | 滚动内容(声明式节点) |
| style | 数组 | [] | 外层容器样式 |
| handle | (Scroll) -> Unit | 空函数 | 拿内部 Scroll 做程序化滚动 |
页签 Tab
let t = @yue.Tab::make(pages=[("第一页", page1), ("第二页", page2)])
t.on_selected_page_change(fn() { switch_to(t.get_selected_page_index()) })| 参数 | 类型 | 默认 | 说明 |
|---|---|---|---|
| pages | Array[(String, Container)] | [] | 页标题与页内容(每页通常一个 Container) |
| on_change | () -> Unit | 空操作 | 切页回调 |
| 方法 | 用途 |
|---|---|
| add_page(title, v) / remove_page(v) | 维护页 |
| select_page_at(i) / get_selected_page_index() / page_count() | 选中与查询 |
| on_selected_page_change(fn()) | 切页回调 |
页内容器是独立 yoga 子树的根;声明式建页见 docs/declarative.md 的 tab 节点。
表格 Table
let t = @yue.Table::new()
t.add_column_text("姓名", 120)
t.add_column_checkbox("启用", 60)
t.set_model(my_model, column_count=2) // 模型见下列类型:add_column_text(title, width) / add_column_edit(title, width)(编辑结果经 set_value 回写模型)/ add_column_checkbox(title, width)(切换经 set_value 回写)/ add_column_custom(title, width, draw)(draw 收 Painter、单元格矩形与模型给出的 ColorText 文本/颜色,逐格自绘)。完整列选项用 add_column_with_options(title, ColumnOptions)。
数据模型走 MoonBit trait 桥,行数再大也只按需取数:
trait TableModel {
fn row_count(Self) -> Int
fn get_value(Self, column : Int, row : Int) -> TableValue // Str / Flag / ColorText
fn set_value(Self, column : Int, row : Int, value : TableValue) -> Unit
}| 方法 | 用途 |
|---|---|
| set_model(m, column_count) | 挂数据模型 |
| on_row_activate(fn(row)) / on_selection_change(fn()) / on_toggle_checkbox(fn(column, row)) | 行激活 / 选中变化 / 勾选切换 |
| enable_multiple_selection(b) / select_row(i) / get_selected_row() | 多选与选中行 |
| set_has_border(b) | 边框 |
| notify_row_insertion(i) / notify_row_deletion(i) / notify_value_change(row, col) | 模型变更后刷新三件套 |
画布与图片
任意视图绘制:
view.on_draw(fn(painter) {
painter.set_fill_color("#FF8800")
painter.fill_rect(0.0, 0.0, 80.0, 80.0)
painter.set_blend_mode(@yue.Multiply) // 25 种混合模式
})Painter 常用方法:
| 方法 | 用途 |
|---|---|
| set_fill_color(hex) / set_stroke_color(hex) | 颜色 |
| fill_rect / stroke_rect / clip_rect(x, y, w, h) | 矩形绘制 / 裁剪 |
| begin_path / close_path / move_to / line_to / arc / bezier_curve_to | 路径 |
| fill() / stroke() | 提交路径 |
| save() / restore() / translate / scale / rotate | 变换 |
| draw_text(...) / draw_attributed_text(...) | 文本 |
| draw_image(...) / draw_image_from_rect(...) | 图片 |
| draw_canvas(...) / draw_canvas_from_rect(...) | 离屏画布 |
| set_blend_mode(m) | 混合模式(BlendMode) |
图片与离屏位图:
let img = @yue.Image::new_from_file("a.png")
let slot = @yue.ImageSlot::new() // 显示图片的控件
slot.set(Some(img))| API | 用途 |
|---|---|
| Image::new_from_file(path) / new_from_png(bytes, scale?) | 加载 |
| img.resize(w, h, scale?) / get_width() / get_height() | 缩放与尺寸 |
| img.write_to_file(format, path) | 导出 |
| img.is_empty() / get_scale_factor() | 状态 |
| Canvas::new(w, h) + get_painter() | 离屏位图 |
| ImageSlot::new() + set(img?) / get() | 图片显示控件 |
富文本:
let at = @yue.AttributedText::new("一段文本", wrap=true, ellipsis=false)
at.set_color_for("#FF0000", 0, 2)| API | 用途 |
|---|---|
| AttributedText::new(text, align?, valign?, wrap?, ellipsis?) | 创建 |
| set_font_for(font, start, end) / set_color_for(hex, start, end) | 按区间设属性(三平台一致) |
| set_font(f) / set_color(hex) / set_text / set_format | 全文属性 |
| get_bounds_for(w, h) | 布局包围盒 |
| Font::new(name, size, weight?, style?) | 字体 |
动图 GifPlayer
let g = @yue.GifPlayer::make(image=Some(img))
g.set_animating(true)| 参数 | 类型 | 默认 | 说明 |
|---|---|---|---|
| image | Image? | None | 初始图片(GIF 动图) |
| scale | ImageScale | Down | 缩放策略:None / Fill / Down / UpOrDown |
| 方法 | 用途 |
|---|---|
| set_image(img) | 换图片 |
| set_scale(s) / get_scale() | 缩放策略 |
| set_animating(b) / is_animating() | 播放 / 暂停 |
| is_playing() / stop_animation_timer() | 播放状态 / 停止 |
浏览器 Browser
// Browser 在独立包 yue/browser(moon.pkg import "NoahLiu/moonbit-libyue/yue/browser")
let b = @browser.Browser::make(url="https://example.com") // 或 html="<h1>本地</h1>"| 参数 | 类型 | 默认 | 说明 |
|---|---|---|---|
| url | String | "" | 加载的地址 |
| html | String | "" | 加载的 HTML;url 与 html 都给时以 url 为准 |
| 方法 | 用途 |
|---|---|
| load_url(u) / load_html(html, base_url?) | 加载 |
| get_url() / get_title() / reload() / stop() | 当前地址 / 页面标题 / 重载 / 停止 |
| go_back() / go_forward() / can_go_back() / can_go_forward() | 导航 |
| is_loading() | 加载状态 |
| set_user_agent(s) | UA |
| execute_javascript(code) / execute_javascript_with_result(code, fn(ok, json)) | 执行 JS;后者异步取回结果(ok=成功,json 为结果 JSON 文本) |
| add_raw_binding(name, fn(json)) / remove_binding(name) / has_bindings() | JS↔原生绑定(网页调 name(...) 时收到 JSON 参数文本) |
| register_protocol(scheme, fn(url) -> (mime, content)?) | 自定义协议(返回 None 拒绝) |
| unregister_protocol(scheme) | 注销协议 |
| get_cookies_for_url(url, fn(cookies)) | 查 Cookie |
| on_change_loading / on_update_title / on_update_command / on_commit_navigation / on_finish_navigation | 事件 |
定制选项用 Browser::new_with_options(BrowserOptions)。
0.5.0 起 Browser 迁入独立包
NoahLiu/moonbit-libyue/yue/browser(API 不变,@browser.Browser改@browser.Browser);未 import 该包的程序不再链接 WebKit/WebView2。
剪贴板 Clipboard
let clip = @yue.Clipboard::get()
clip.set_text("文本")| 方法 | 用途 |
|---|---|
| Clipboard::get() | 默认剪贴板 |
| set_text(t) / get_text() | 文本 |
| set_data(kind, t) / get_data(kind) / set_data_image(img) | 结构化数据 |
| clear() | 清空 |
通知 Notification / 通知中心
let n = @yue.Notification::new()
n.set_title("标题"); n.set_body("正文")
n.show()| 方法 | 用途 |
|---|---|
| set_title(t) / set_body(s) | 内容 |
| set_silent(b) | 静默 |
| set_actions([(id, 标题)]) | 按钮(配合 NotificationCenter 的 action 回调) |
| show() | 发送(Linux 必须经此,见 docs/adaptation.md) |
| close() | 关闭 |
| NotificationCenter::get() + add(n) | 经通知中心发送 |
消息框 MessageBox
let box = @yue.MessageBox::new(Information)
box.add_button("好", 1)
box.on_response(fn(response) { ... })
box.show_for_window(win)| 方法 | 用途 |
|---|---|
| MessageBox::new(type_) | 类型(MessageBoxType) |
| set_title / set_text / set_informative_text | 文本 |
| add_button(title, response) | 自定义按钮 |
| on_response(fn(response)) | 按钮响应(response 为按钮编号) |
| show() / show_for_window(win) / close() | 弹出(模态)/ 关闭 |
文件对话框 FileDialog
let fd = @yue.FileDialog::new_open()
fd.set_filters("图片:png,jpg|全部:*")
if fd.run_for_window(win) { fd.get_result() }| 方法 | 用途 |
|---|---|
| new_open() / new_save() | 打开 / 保存 |
| set_filters("描述:扩展1,扩展2|描述2:扩展3") | 过滤器(* 匹配全部) |
| set_folder(path) / set_filename(name) | 初始目录 / 文件名 |
| set_options(FILE_OPTION_PICK_FOLDERS | MULTI_SELECT | SHOW_HIDDEN) | 选项位组合 |
| run_for_window(win) -> Bool | 模态运行 |
| get_result() | 结果路径 |
文件读写:read_text_file(path) -> String?、read_binary_file(path) -> Bytes?、 write_text_file(path, content) -> Bool。
菜单 MenuBar / Menu / MenuItem
let mb = @yue.MenuBar::new()
let m = mb.add_menu("文件")
m.add_label_item("打开").on_click(fn() { ... })
win.set_menubar(mb)| API | 用途 |
|---|---|
| MenuBar::new() + add_menu(title) -> Menu | 菜单条 |
| Menu::new() | 弹出菜单(配 popup_at(x, y)) |
| add_label_item(t) / add_check_item(t) / add_radio_item(t) | 普通项 / 复选 / 单选 |
| add_role_item(role) / add_submenu(title) / add_separator() | 系统角色项 / 子菜单 / 分隔线 |
| MenuItem::on_click(fn()) | 点击回调 |
| MenuItem::is_checked() / set_checked(b) | 勾选 |
| MenuItem::get_label() / set_label(t) / set_accelerator(s) | 文本与快捷键 |
| Menu::item_count() / item_at(i);MenuBar 同 | 遍历 |
托盘 Tray
let tray = match @yue.Tray::new("icon.png") {
Ok(t) => t
Err(e) => ... // 后端缺失或图标读取失败
}| API | 用途 |
|---|---|
| Tray::is_supported() | 后端是否可用 |
| Tray::new(icon_path) -> Result[Tray, TrayError] | 创建(结构化报错) |
| set_icon(path) / set_icon_name(name) | 换图标(主题名仅 Linux SNI) |
| set_title(t) | 部分平台无此概念,空操作 |
| set_tooltip(title, body) | 悬浮提示(仅 Linux SNI) |
| on_click(fn()) | 点击回调 |
| set_menu(menu) | 挂右键菜单 |
| remove() | 移除图标 |
Linux 推荐纯 MoonBit 的 yue/traybus 后端(Tray 统一 API 内部自动选择), 方案见 docs/tray.md。
系统集成(单实例 / 自启动 / 电源 / 会话 / 网络)
桌面应用的系统级能力,统一入口、统一错误风格(Err(Unsupported) 与 xxx_supported() 先行判定)。完整演示见 showcase「系统集成」页。
单实例与二次唤起
match @system.SingleInstance::acquire("org.example.MyApp") {
Ok(Some(handle)) => {
// 本进程是首实例,继续启动
handle.on_activate(fn(args) {
// 第二实例启动时收到其命令行参数:恢复 / 置前窗口
})
}
Ok(None) => return // 已有实例,唤醒已发,本进程退出
Err(_) => () // 单实例不可用,调用方决定降级或退出
}| API | 用途 |
|---|---|
| SingleInstance::acquire(app_id) -> Result[SingleInstance?, SingleInstanceError] | 尝试成为首实例(app_id 须为合法 DBus 总线名:点分层段、字母/下划线开头) |
| handle.on_activate(cb : (Array[String]) -> Unit) | 注册第二实例唤起回调(透传其命令行,含 argv[0]) |
| set_instance_window_title(title) | 设置窗口标题(Windows 置前兜底按标题查找;运行时改标题会破坏兜底) |
Linux 经会话总线声称应用专属名,Windows 经命名互斥体 + 消息窗口。
开机自启动
let auto = match @system.Autostart::new("org.example.MyApp") {
Ok(a) => a
Err(_) => ... // 平台不支持(macOS 暂缓)
}
auto.enable() // Ok 后重新登录 / 重启即拉起
auto.disable() // 取消(幂等)| API | 用途 |
|---|---|
| Autostart::new(app_id) -> Result[Autostart, AutostartError] | 句柄(app_id 同单实例约束) |
| Autostart::is_supported() | 平台是否支持 |
| handle.is_enabled() -> Result[Bool, AutostartError] | 查询当前状态 |
| handle.enable() / disable() -> Result[Unit, AutostartError] | 设置 / 取消(均幂等) |
| handle.path() -> Result[String, AutostartError] | 自启动项文件路径(Linux .desktop) |
Linux 写 $XDG_CONFIG_HOME/autostart 的 .desktop(exe 路径取 /proc/self/exe),Windows 写 HKCU Run 键。
打开外部
| API | 用途 |
|---|---|
| open_url(url) -> Result[Unit, OpenUrlError] | 交默认浏览器打开 |
| reveal_in_file_manager(path) -> Result[Unit, FileManagerError] | 文件管理器中打开并选中(相对路径按工作目录解析;Linux FileManager1 不在线回退打开父目录,选中态丢失) |
Ok 只表示已交给系统;系统侧成败不回传(浏览器是否真打开由桌面决定)。
屏幕常亮与用户空闲
match @system.KeepAwake::enable("org.example.MyApp") {
Ok(k) => { /* 保持常亮 */ ignore(k.release()) } // 解除
Err(_) => ()
}
match @system.idle_seconds() {
Ok(sec) => ... // 自最后一次输入起的秒数(阈值判定由调用方比较)
Err(_) => ()
}| API | 用途 |
|---|---|
| KeepAwake::is_supported() | 抑制服务 / 系统能力是否可用 |
| KeepAwake::enable(app_id) -> Result[KeepAwake, KeepAwakeError] | 申请常亮(Ok 只表示系统受理;是否真不熄屏由平台策略决定) |
| handle.release() | 解除(幂等) |
| keep_awake_active() | 当前是否持有常亮 |
| idle_supported() / idle_seconds() -> Result[Double, IdleError] | 用户空闲秒数(Linux X11;Wayland 会话显式 Unsupported) |
电量与电源事件
| API | 用途 |
|---|---|
| battery_supported() / battery_query() -> Result[BatteryInfo?, PowerError] | 电量读数(百分比 / 充电中 / 距充满与放空秒数;无电池返回 Ok(None)) |
| power_source() -> Result[PowerSource, PowerError] | 查询当前电源来源(台式机无电池,来源恒为交流在线) |
| power_event_supported() / on_power_source_change(cb) | 交直流切换事件(PowerSource::Ac / OnBattery;Windows 事件接入后置,先判 supported) |
| suspend_resume_supported() / on_suspend_resume(cb) | 休眠唤醒事件(SleepEvent::Suspending / Resuming;快速挂起唤醒可能连收两条 Resuming,库内不去抖) |
Linux 电量走 UPower(系统总线),Windows 走 GetSystemPowerStatus; 休眠唤醒 Linux 走 logind PrepareForSleep,Windows 走电源广播。
锁屏解锁
| API | 用途 |
|---|---|
| session_lock_supported() | 是否可用(锁屏工具不调 logind 的桌面收不到信号) |
| session_lock_watch(cb) -> Result[Unit, SystemError] | 订阅锁屏 / 解锁(SessionLockEvent::Locked / Unlocked;失败给结构化错误,不静默) |
网络在线状态
| API | 用途 |
|---|---|
| network_supported() / network_status() -> Result[NetworkStatus, NetworkError] | 当前在线状态(Online = 可达互联网;门户劫持按 Offline) |
| on_network_status_change(cb) | 变化事件(仅变化时派发;Linux 信号驱动,Windows 5 秒轮询) |
Linux 走 NetworkManager(系统总线);首次 network_status() 同步建缓存, 最坏阻塞 1.5 秒——回调与定时器内请用事件或缓存,勿反复查询。
气泡 Popover
let pop = @yue.Popover::new()
pop.set_content(view)
pop.show_relative_to(anchor_view)| 方法 | 用途 |
|---|---|
| set_content(v) / set_content_size(w, h) | 内容与尺寸 |
| show_relative_to(v) | 弹出到目标视图附近 |
| close() / on_close(fn()) | 关闭 |
全局快捷键 / 光标 / 系统
| API | 用途 |
|---|---|
| register_global_shortcut("CmdOrCtrl+Shift+M", fn()) -> Int | 注册,返回 id;-1 为被占用(需换键) |
| unregister_global_shortcut(id) | 注销 |
| Cursor::new(type_) + view.set_cursor(c) | 光标(CursorType) |
| Appearance::is_dark() | 深色外观 |
| locale() | 区域 |
| Screen::scale_factor() / primary_size() | 缩放 / 主屏尺寸 |
| App::set_name(s) / App::get_name() | 应用名 |
| desktop_environment() | 桌面环境名(诊断用) |
事件(所有控件通用)
所有控件(ViewLike)支持:
| 方法 | 用途 |
|---|---|
| on_mouse_down / up / move / enter / leave | 鼠标 |
| on_key_down / up | 键盘 |
| on_size_changed | 尺寸变化 |
| set_capture() / release_capture() / has_capture() | 鼠标捕获 |
| set_style(k, v) / set_style_str(k, v) | 布局样式(运行期底层原语) |
| 拖拽注册与拖放回调 | 拖放(接收方必须注册 handle_drag_update 返回允许的操作位,缺省一律拒绝;发起方 do_drag_file_paths / do_drag_data_full 须在 on_mouse_down 回调内调用才生效;演示见 components「窗口」页) |
事件载荷字段:
| 结构 | 字段 |
|---|---|
| MouseEvent | kind、button(1=左 2=右 3=中)、view_x/view_y(相对视图)、window_x/window_y(相对窗口)、screen_x/screen_y(屏幕全局坐标,右键菜单等按事件位置弹出直接用)、modifiers、timestamp |
| KeyEvent | kind、code(VKEY_* 常量)、modifiers、timestamp |
modifiers 位:1=Shift 2=Ctrl 4=Alt 8=Meta;KeyEvent::describe() 输出 "Ctrl+A" 形式。键码常量表跨平台统一(Windows VK 码在事件入口归一化), 见 yue/events.mbt;连击计数用 ClickTracker(默认 400ms / 5px)。
固有坑
上游 libyue 或平台行为带来,使用对应 API 前先读:
- Browser 导航会改写窗口标题(Windows):WebView2 宿主控件加载网页后把页面
<title>同步为宿主窗口标题(Linux/GTK 无此现象,2026-09-19 实测)。依赖窗口 标题做窗口管理的工具会受影响,需要时用on_update_title自行管理标题显示。 - 复选/单选的初始化回调:以
checked=true创建的 Checkbox/Radio, 挂载完成进入事件循环后会异步收到一次回调(GTK toggled 信号语义)。 回调逻辑依赖状态时先is_checked()判断,或容忍这次初始通知。 - 单选组切换是双通知:点选新项时,被取消选中的旧项也会收到一次回调 (此时旧项
is_checked()==false)。按"新选中的那个"处理业务即可。 - 虚拟键码是 GTK 表:
VKEY_ESCAPE = 0xFF1B(65307),不是 Windows VK 值;字母与数字与 ASCII 相同。跨平台代码不要混用两张表。 - 样式键的解析规则:键名只保留 ASCII 字母并转小写,
flexDirection/flex-direction/flexdirection等价;数字、连字符与其他符号一律丢弃, 不要用特殊字符拼键名。键值全集见 docs/layout.md。 - 回调自动保活,但别在回调里同步弹事件循环:
on_*注册的闭包由库持有 强引用;Store订阅同理。回调里调用@yue.quit()等终止流程后不要再 操作控件。 - 平台专属 API 未封装:Toolbar / Vibrant(Linux 静态库无符号)、 Button 样式与 ControlSize、Scroll 弹性、App 激活策略、Browser 缩放、 Image 模板图(macOS),ShortcutOptions / Lifetime::Reply / 通知 COMServerOptions(Windows)等,完整清单见 docs/adaptation.md。