【Rust GUI开发入门】编写一个本地音乐播放器(4. 绘制按钮组件)

本系列教程对应的代码已开源在 Github zeedle

开始介绍播放器UI的构建部分,但是不会详细讲解Slint UI的设计基础,没有意义,因为官方文档介绍的已经十分详细了,一些基本用法需要借助参考文档熟悉。

Slint UI支持使用类SVG指令绘制矢量图标,为了保证UI的风格统一性,这里不使用网络上的图标,直接使用Path指令绘制,具体语法参考Path | Slint Docs

需要绘制的图标如下:

  • 播放/暂停
  • 上一曲
  • 下一曲
  • 播放模式

直接给出.slint代码:

slint 复制代码
import { Palette } from "std-widgets.slint";
export component NextSongButton inherits Window {
    callback clicked();
    TouchArea {
        clicked => {
            root.clicked();
        }
        Path {
            width: 100%;
            height: 100%;
            MoveTo {
                x: 0;
                y: 0;
            }

            LineTo {
                x: 0;
                y: 100;
            }

            LineTo {
                x: 70;
                y: 50;
            }

            Close { }

            MoveTo {
                x: 80;
                y: 0;
            }

            LineTo {
                x: 80;
                y: 100;
            }

            stroke: Palette.control-foreground;
            stroke-width: root.width * 0.1;
        }
    }
}

export component PrevSongButton inherits Window {
    callback clicked();
    TouchArea {
        clicked => {
            root.clicked();
        };
        Path {
            width: 100%;
            height: 100%;
            MoveTo {
                x: 80;
                y: 0;
            }

            LineTo {
                x: 80;
                y: 100;
            }

            LineTo {
                x: 10;
                y: 50;
            }

            Close { }

            MoveTo {
                x: 0;
                y: 0;
            }

            LineTo {
                x: 0;
                y: 100;
            }

            stroke: Palette.control-foreground;
            stroke-width: root.width * 0.1;
        }
    }
}

export component PlayPauseButton inherits Window {
    in-out property <bool> paused:true;
    callback toggled();
    TouchArea {
        clicked => {
            root.toggled();
        }
        if !root.paused:
            Path {
            width: 100%;
            height: 100%;
            MoveTo {
                x: 0;
                y: 0;
            }

            LineTo {
                x: 0;
                y: 100;
            }

            LineTo {
                x: 30;
                y: 100;
            }

            LineTo {
                x: 30;
                y: 0;
            }

            Close { }

            MoveTo {
                x: 50;
                y: 0;
            }

            LineTo {
                x: 50;
                y: 100;
            }

            LineTo {
                x: 80;
                y: 100;
            }

            LineTo {
                x: 80;
                y: 0;
            }

            Close { }

            stroke: Palette.control-foreground;
            stroke-width: root.width * 0.1;
        }
        if root.paused:
            Path {
            width: 100%;
            height: 100%;
            MoveTo {
                x: 0;
                y: 0;
            }

            LineTo {
                x: 0;
                y: 100;
            }

            LineTo {
                x: 80;
                y: 50;
            }

            Close { }

            stroke: Palette.control-foreground;
            stroke-width: root.width * 0.1;
        }
    }
}

export component InOrderButton inherits Window {
    in-out property <bool> selected;
    Path {
        MoveTo {
            x: 90;
            y: 50;
        }

        ArcTo {
            x: 50;
            y: 10;
            radius-x: 40;
            radius-y: 40;
            x-rotation: 0;
            large-arc: true;
            sweep: true;
        }

        LineTo {
            x: 40;
            y: 4;
        }

        MoveTo {
            x: 50;
            y: 10;
        }

        LineTo {
            x: 42;
            y: 18;
        }

        stroke-width: 1px;
        stroke: selected ? Palette.accent-background : Palette.foreground;
    }
}

export component RecursiveButton inherits Window {
    in-out property <bool> selected;
    Path {
        MoveTo {
            x: 90;
            y: 50;
        }

        ArcTo {
            x: 50;
            y: 10;
            radius-x: 40;
            radius-y: 40;
            x-rotation: 0;
            large-arc: true;
            sweep: true;
        }

        LineTo {
            x: 40;
            y: 4;
        }

        MoveTo {
            x: 50;
            y: 10;
        }

        LineTo {
            x: 42;
            y: 18;
        }

        MoveTo {
            x: 50;
            y: 40;
        }

        LineTo {
            x: 50;
            y: 60;
        }

        MoveTo {
            x: 50;
            y: 40;
        }

        LineTo {
            x: 44;
            y: 44;
        }

        stroke-width: 1px;
        stroke: selected ? Palette.accent-background : Palette.foreground;
    }
}

@rust-attr(derive(serde::Serialize, serde::Deserialize))
export enum PlayMode { 
    InOrder, 
    Recursive, 
    Random
 }

export component OverlapButton inherits Window {
    in-out property <PlayMode> mode;
    callback clicked();
    TouchArea {
        width: 100%;
        height: 100%;
        clicked => {
            root.clicked();
        }
        if mode == PlayMode.Recursive: RecursiveButton {
            width: 100%;
            height: 100%;
            selected: mode == PlayMode.Recursive || mode == PlayMode.InOrder;
        }
        if mode != PlayMode.Recursive: InOrderButton {
            width: 100%;
            height: 100%;
            selected: mode == PlayMode.Recursive || mode == PlayMode.InOrder;
        }
    }
}

export component RandomButton inherits Window {
    callback clicked();
    in-out property <bool> selected;
    TouchArea {
        clicked => {
            root.clicked();
        };
        Path {
            MoveTo {
                x: 0;
                y: 20;
            }

            LineTo {
                x: 30;
                y: 20;
            }

            LineTo {
                x: 70;
                y: 80;
            }

            LineTo {
                x: 100;
                y: 80;
            }

            LineTo {
                x: 90;
                y: 70;
            }

            MoveTo {
                x: 100;
                y: 80;
            }

            LineTo {
                x: 90;
                y: 90;
            }

            // 第二段
            MoveTo {
                x: 0;
                y: 80;
            }

            LineTo {
                x: 30;
                y: 80;
            }

            LineTo {
                x: 70;
                y: 20;
            }

            LineTo {
                x: 100;
                y: 20;
            }

            LineTo {
                x: 90;
                y: 30;
            }

            MoveTo {
                x: 100;
                y: 20;
            }

            LineTo {
                x: 90;
                y: 10;
            }

            stroke: selected ? Palette.accent-background : Palette.foreground;
            stroke-width: 1px;
        }
    }
}

代码解释

从上述指令可以看出,这里使用的绘图指令还是比较简单的,基本就是画直线,画圆弧:

  • MoveTo:移动到某个点,并按下画笔
  • LineTo:从当前位置绘制直线到目标位置,并松开画笔
  • ArcTo:绘制圆弧,参数比较多,可以参考文档
    • radius-x:X轴半径
    • radius-y:Y轴半径
    • sweep:是否为顺时针方向
    • x, y:目标位置
    • x-rotation:椭圆的X轴旋转角

上面.slint代码中,有一些关于属性<property>和组件回调函数<callback>相关的东西:

  • 属性:可以是组件的外观参数(长,宽等),或者指示组件的内部状态,in修饰符代表只能由外部传入(只写),out修饰符代表只能从内部传出(只读),in-out修饰符代表可读可写
  • 回调函数:指定用户点击/拖动...该组件时,要执行的任务
相关推荐
Ivanqhz6 小时前
Rust &‘static str浅析
java·前端·javascript·rust
记忆着10 小时前
标准库更多介绍
rust
labixiong10 小时前
React Compiler 用 Rust 重写了,编译提速 10 倍——手写 useMemo 的日子到头了
react.js·rust
Ivanqhz11 小时前
Rust Lazy浅析
java·javascript·rust
寒水馨14 小时前
Windows下载、安装 Codex CLI(附安装包codex-x86_64-pc-windows-msvc.exe)
windows·rust·codex·终端工具·自动化编程·codex cli·ai编码代理
k4m7v2pz14 小时前
rvs(rust-verb-shell)v26.7.12 更新:借鉴 ripgrep、自身可观测、修了 mkdir
rust·shell
用户2025829445016 小时前
给下载器写插件:一个 manifest.json + 30 行 JavaScript,做一个 GitHub 下载加速解析器
rust
CappuccinoRose17 小时前
Rust学习文档(四)
开发语言·后端·学习·算法·rust·vector·map
Ivanqhz17 小时前
Rust #[derive(Serialize)]浅析
开发语言·后端·rust
Ivanqhz18 小时前
Rust parse() 浅析
开发语言·后端·rust