《Rust+Slint:跨平台GUI应用》第八章 窗体

在 UI 开发的世界里,交互的流畅度与直观性直接决定着用户体验的上限 ------ 而上下文菜单、对话框、菜单栏、弹出窗口与核心窗体,正是构建这些关键交互的 "基石组件"。它们既是用户与应用沟通的 "入口",也是应用反馈操作结果的 "窗口",从右键唤起的快捷功能,到确认操作的弹窗,再到顶部导航的菜单栏,每一个组件的合理运用,都能让应用更贴合用户习惯、更具专业性。

我在本章,带您聚焦 Slint 框架中这五类核心交互组件,从基础定义、触发逻辑、属性配置,到实际代码示例,层层拆解它们的使用方法。无论你是想实现灵活的右键菜单、适配多平台的对话框,还是搭建规范的菜单栏与轻量弹出窗口,亦或是定制化核心窗体的样式与行为,都能在这里找到清晰的指引。跟着示例动手实践,你将快速掌握这些组件的核心用法,让你的 UI 交互设计既高效又易用。


一、上下文菜单(ContextMenuArea)

使用非视觉元素 ContextMenuArea 可以声明一个区域,用户在该区域内可触发上下文菜单。

上下文菜单的触发方式如下:

  • 用户右键点击 ContextMenuArea 覆盖的区域;
  • 用户在 ContextMenuArea 内的 FocusScope 获得焦点时,按下键盘上的 "Menu" 键;
  • 在 Android 设备上,长按该区域;
  • 编程调用 ContextMenuArea 元素的 show () 方法。

ContextMenuArea 的子元素中必须包含一个 Menu 元素(用于定义要显示的菜单),且最多只能有一个 Menu 子元素;其他子元素需为不同类型,会作为常规视觉元素显示。在 Menu 内部可通过放置 MenuItem 或嵌套 Menu 元素来定义菜单结构。

函数
  • show (Point):通过编程方式在相对于 ContextMenuArea 元素的指定位置显示上下文菜单。
  • close ():如果上下文菜单当前处于打开状态,调用此函数可将其关闭。
属性
  • enabled(bool 类型,默认值为 true):当设为禁用状态时,菜单不会显示。

Menu 元素可放置在 MenuBar、ContextMenuArea 中,或嵌套在另一个 Menu 内部。其可包含以下子元素:

  • MenuItem:用于定义单个菜单项;
  • 嵌套的 Menu:用于创建子菜单;
  • MenuSeparator:用于创建分隔线。
属性
  • title(string 类型,默认值为 ""):在菜单栏或父菜单中显示的菜单标签。
  • enabled(bool 类型,默认值为 true):禁用状态下,菜单可被选中但无法激活。
  • icon(image 类型,默认值为空图像):在父菜单中,显示在标题旁的图标。

MenuItem 代表单个菜单项,必须作为 Menu 元素的子元素存在。

属性
  • title(string 类型,默认值为 ""):菜单项显示的标题。
  • enabled(bool 类型,默认值为 true):禁用状态下,菜单项可被选中但无法激活。
  • checkable(bool 类型,默认值为 true):设为 true 时,菜单项可被勾选;用户激活菜单项时,checked 属性的值会切换。
  • checked(bool 类型,默认值为 true):设为 true 时,菜单项标题旁会显示勾选标记。
  • icon(image 类型,默认值为空图像):显示在标题旁的图标。
回调
  • activated ():菜单项被激活时调用。

MenuSeparator 代表菜单中的分隔线,它不能有子元素,也没有属性和回调。位于菜单开头或结尾的 MenuSeparator 不会显示;连续的多个 MenuSeparator 会合并为一个。

示例

qml

复制代码
export component Example {
    ContextMenuArea {
        Menu {
            MenuItem {
                title: @tr("Cut");
                activated => { debug("Cut"); }
            }
            MenuItem {
                title: @tr("Copy");
                activated => { debug("Copy"); }
            }
            MenuItem {
                title: @tr("Paste");
                activated => { debug("Paste"); }
            }
            MenuSeparator {}
            Menu {
                title: @tr("Find");
                MenuItem {
                    title: @tr("Find Next");
                }
                MenuItem {
                    title: @tr("Find Previous");
                }
            }
        }
    }
}

二、对话框(Dialog)

slint

复制代码
import { StandardButton, Button } from "std-widgets.slint";
export component Example inherits Dialog {
    Text {
      text: "This is a dialog box";
    }
    StandardButton { kind: ok; }
    StandardButton { kind: cancel; }
    Button {
      text: "More Info";
      dialog-button-role: action;
    }
}

slint 对话框示例

Dialog 类似窗口,但它包含的按钮会自动进行布局。

Dialog 应包含一个非按钮的主元素作为子元素。对话框可以有任意数量的 StandardButton 组件,或者其他设置了 dialog-button-role 属性的按钮。这些按钮的排列顺序会根据运行时的目标平台自动调整。

StandardButton 的 kind 属性和按钮的 dialog-button-role 属性需要设置为常量值,不能是任意变量表达式。而且,不允许存在多个同 kind 的 StandardButton。

对于每个没有显式设置回调处理函数的 StandardButton,会自动添加一个<kind>_clicked 回调,方便从原生代码中处理:比如,若有一个 kind 为 cancel 的按钮,就会自动添加 cancel_clicked 回调。这些自动生成的回调都是对应 StandardButton 的 clicked 回调的别名。

属性:

  • icon(image 类型,默认值为空图像):在支持的窗口管理器中,显示在标题栏或任务栏上的窗口图标。
  • title(string 类型,默认值为 ""):显示在标题栏上的窗口标题。

三、MenuBar

在 Window 中使用 MenuBar 元素可以声明菜单栏的结构,包括实际的菜单和子菜单。

注意事项:

  • 一个 Window 中只能有一个 MenuBar 元素,且它不能位于 for 或 if 语句中。

MenuBar 没有属性,但它必须包含 Menu 作为子元素,这些 Menu 代表菜单栏中的顶级条目。

根据平台不同,菜单栏可能是系统原生的,也可能由 Slint 渲染。例如,在 macOS 上,菜单栏会显示在屏幕顶部。Window 的 width 和 height 属性定义的是客户区(不包含菜单栏),Window 子元素的 x 和 y 坐标也是相对于客户区的。

示例:

slint

复制代码
export component Example inherits Window {
    MenuBar {
        Menu {
            title: @tr("File");
            MenuItem {
                title: @tr("New");
                activated => { file-new(); }
            }
            MenuItem {
                title: @tr("Open");
                activated => { file-open(); }
            }
        }
        Menu {
            title: @tr("Edit");
            MenuItem {
                title: @tr("Copy");
            }
            MenuItem {
                title: @tr("Paste");
            }
            MenuSeparator {}
            Menu {
                title: @tr("Find");
                MenuItem {
                    title: @tr("Find in document...");
                }
                MenuItem {
                    title: @tr("Find Next");
                }
                MenuItem {
                    title: @tr("Find Previous");
                }
            }
        }
    }

    callback file-new();
    callback file-open();

    // ... 实际窗口内容放在这里
}

四、弹出窗口(PopupWindow)

slint

复制代码
export component Example inherits Window {
    width: 100px;
    height: 100px;

    popup := PopupWindow {
        Rectangle { height:100%; width: 100%; background: yellow; }
        x: 20px; y: 20px; height: 50px; width: 50px;
    }

    TouchArea {
        height:100%; width: 100%;
        clicked => { popup.show(); }
    }
}

使用该元素可以显示类似工具提示或弹出菜单的弹出窗口。

注意:不允许从 PopupWindow 外部访问其内部元素的属性。详见 #4438↗。

属性:

  • close-policy(枚举类型 PopupClosePolicy,默认值为 close-on-click)

PopupClosePolicy 包含以下值:

  • close-on-click:用户点击或按 ESC 键时,关闭 PopupWindow。
  • close-on-click-outside:用户点击弹出窗口外部或按 ESC 键时,关闭 PopupWindow。
  • no-auto-close:用户点击时,不会自动关闭 PopupWindow。

默认情况下,点击时 PopupWindow 会关闭。若要阻止这种行为,可将 close-policy 设为 no-auto-close,然后通过 close () 函数手动关闭。

函数:

  • show ():在屏幕上显示弹出窗口。
  • close ():关闭弹出窗口。当 close-policy 设为 no-auto-close 时,可使用此函数手动关闭。

四、窗体(Window)

Window 是屏幕上可见元素树的根节点。

窗口的几何尺寸会受其布局约束限制:设置 width 会固定窗口宽度;窗口管理器会遵循 min-width 和 max-width,因此窗口不能被调整到超出这两个值的大小。初始宽度可通过 preferred-width 属性控制,高度的相关逻辑与此相同。

可使用 MenuBar 元素为窗口声明菜单栏。

属性:

  • always-on-top(bool 类型,默认值为 false):在支持的窗口管理器中,窗口是否始终显示在其他所有窗口之上。

  • full-screen(bool 类型,默认值:若设置了 'SLINT_FULLSCREEN' 环境变量则为 true,否则为 false):窗口是否以全屏模式显示。全屏模式下,窗口会占据整个屏幕,不可调整大小,且不显示标题栏。

  • background(brush 类型,默认值:取决于样式):窗口的背景画刷。

  • default-font-family(string 类型,默认值为 ""):窗口内未设置 font-family 属性的文本元素,会使用此属性作为默认字体家族。

  • default-font-size(length 类型,默认值为 0):窗口内未设置 font-size 属性的文本元素,会使用此属性作为默认字体大小。该值也是相对字体大小的基准。

  • default-font-weight(int 类型,默认值为 0):窗口内未设置 font-weight 属性的文本元素,会使用此属性作为默认字体粗细。取值范围为 100(最细)到 900(最粗),400 为常规粗细。

  • icon(image 类型,默认值为空图像):在支持的窗口管理器中,显示在标题栏或任务栏上的窗口图标。

  • no-frame(bool 类型,默认值为 false):窗口是否为无边框 / 无框架样式。

  • resize-border-width(length 类型,默认值为 0):注意:目前该属性仅支持 winit。无边框 / 无框架窗口中,可调整大小的边框宽度。

  • title(string 类型,默认值为 ""):显示在标题栏上的窗口标题。

相关推荐
森语林溪2 小时前
大数据环境搭建从零开始(十七):JDK 17 安装与配置完整指南
java·大数据·开发语言·centos·vmware·软件需求·虚拟机
lsx2024062 小时前
HTML 音频(Audio)详解
开发语言
woshihonghonga2 小时前
【动手学深度学习】
开发语言·python
威风的虫2 小时前
ES6 数组方法:告别循环,拥抱函数式编程
开发语言·前端·javascript
码界筑梦坊2 小时前
240-基于Python的医疗疾病数据可视化分析系统
开发语言·python·信息可视化·数据分析·毕业设计·echarts
2301_803554523 小时前
C++ 锁类型大全详解
开发语言·c++
wuwu_q3 小时前
用通俗易懂方式,详细讲讲 Kotlin Flow 中的 map 操作符
android·开发语言·kotlin
曼巴UE53 小时前
UE5 C++ Slate 画曲线
开发语言·c++·ue5
向葭奔赴♡3 小时前
Spring IOC/DI 与 MVC 从入门到实战
java·开发语言