【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修饰符代表可读可写
  • 回调函数:指定用户点击/拖动...该组件时,要执行的任务
相关推荐
暴躁小师兄数据学院8 小时前
【WEB3.0零基础转行笔记】Rust编程篇-第一讲:课程简介
rust·web3·区块链·智能合约
七夜zippoe8 小时前
脉向AI|当豆包手机遭遇“全网封杀“:GUI Agent是通向AGI的必经之路吗?
人工智能·ai·智能手机·agent·gui
E_ICEBLUE12 小时前
PPT 批量转图片:在 Web 预览中实现翻页效果(C#/VB.NET)
c#·powerpoint·svg
Hello.Reader16 小时前
Rocket Fairings 实战把全局能力做成“结构化中间件”
中间件·rust·rocket
Andrew_Ryan16 小时前
rust arena 内存分配
rust
Andrew_Ryan16 小时前
深入理解 Rust 内存管理:基于 typed_arena 的指针操作实践
rust
Highcharts.js18 小时前
如何使用Highcharts SVG渲染器?
开发语言·javascript·python·svg·highcharts·渲染器
微小冷2 天前
Rust异步编程详解
开发语言·rust·async·await·异步编程·tokio
鸿乃江边鸟2 天前
Spark Datafusion Comet 向量化Rust Native--CometShuffleExchangeExec怎么控制读写
大数据·rust·spark·native
明飞19872 天前
tauri
rust