#widgets #gui #relm #attributes #model #elm #generation

relm-gen-widget

relm-attributes 和 relm-derive 的实用工具库

52 个版本

使用旧的Rust 2015

0.16.0 2019年4月14日
0.15.3 2019年3月25日
0.15.2 2019年1月15日
0.15.0 2018年9月12日
0.9.10 2017年4月30日

#281 in 过程宏

Download history 109/week @ 2024-03-11 96/week @ 2024-03-18 60/week @ 2024-03-25 219/week @ 2024-04-01 42/week @ 2024-04-08 76/week @ 2024-04-15 99/week @ 2024-04-22 71/week @ 2024-04-29 52/week @ 2024-05-06 87/week @ 2024-05-13 90/week @ 2024-05-20 121/week @ 2024-05-27 90/week @ 2024-06-03 50/week @ 2024-06-10 69/week @ 2024-06-17 49/week @ 2024-06-24

286 每月下载量
6 个crate中使用 (直接使用2个)

MIT 许可证

100KB
2.5K SLoC

Relm

异步、基于GTK+的GUI库,受Elm启发,用Rust编写。

此库处于测试阶段:它尚未经过彻底测试,API可能会随时更改。

link link link link link link link link

要求

由于relm基于GTK+,您需要在该系统上安装此库才能使用它。

有关安装GTK+的信息,请参阅此页面

使用方法

首先,将以下内容添加到您的 Cargo.toml

[source,toml]

gtk = "^0.16.0"
relm = "^0.24.0"
relm-derive = "^0.24.0"

接下来,将以下内容添加到您的crate中

[source,rust]

use relm::{connect, Relm, Update, Widget};
use gtk::prelude::*;
use gtk::{Window, Inhibit, WindowType};
use relm_derive::Msg;

然后,创建您的模型

[source,rust]

struct Model {
    //
}

模型包含与 Widget 相关的数据。它可能由 Widget::update 函数更新。

创建您的消息 enum

[source,rust]

#[derive(Msg)]
enum Msg {
    //
    Quit,
}

消息被发送到 Widget::update 以指示发生了事件。在收到事件时,模型可以更新。

创建一个 struct 来表示包含GTK+小部件(在这种情况下,应用程序的主窗口)和模型的 Widget

[source,rust]

struct Win {
    //
    model: Model,
    window: Window,
}

要使此 struct 成为库可以显示的relm Widget,实现 UpdateWidget 特性

[source,rust]

impl Update for Win {
    // Specify the model used for this widget.
    type Model = Model;
    // Specify the model parameter used to init the model.
    type ModelParam = ();
    // Specify the type of the messages sent to the update function.
    type Msg = Msg;

    // Return the initial model.
    fn model(_: &Relm<Self>, _: ()) -> Model {
        Model {
        }
    }

    // The model may be updated when a message is received.
    // Widgets may also be updated in this function.
    fn update(&mut self, event: Msg) {
        match event {
            Msg::Quit => gtk::main_quit(),
        }
    }
}

impl Widget for Win {
    // Specify the type of the root widget.
    type Root = Window;

    // Return the root widget.
    fn root(&self) -> Self::Root {
        self.window.clone()
    }

    // Create the widgets.
    fn view(relm: &Relm<Self>, model: Self::Model) -> Self {
        // GTK+ widgets are used normally within a `Widget`.
        let window = Window::new(WindowType::Toplevel);

        // Connect the signal `delete_event` to send the `Quit` message.
        connect!(relm, window, connect_delete_event(_, _), return (Some(Msg::Quit), Inhibit(false)));
        // There is also a `connect!()` macro for GTK+ events that do not need a
        // value to be returned in the callback.

        window.show_all();

        Win {
            model,
            window,
        }
    }
}

最后,通过调用 Win::run() 来显示此 Widget

[source,rust]

fn main() {
    Win::run(()).unwrap();
}

#[widget] 属性

提供了一个 #[widget] 属性,以简化小部件的创建。

此属性执行以下操作

  • 提供了一个 view! 宏,以声明性语法创建小部件。
  • 自动创建 fn root()type Msgtype Modeltype ModelParamtype Root 项。
  • 在将属性分配给模型时,自动在 update() 函数中插入对 Widget::set_property() 的调用。
  • 自动创建 Widget 结构体。
  • UpdateWidget 特性可以同时实现。

要使用此属性,请添加以下代码

[source,rust]

use relm_derive::widget;

以下是一个使用此属性的示例

[source,rust]

#[derive(Msg)]
pub enum Msg {
    Decrement,
    Increment,
    Quit,
}

pub struct Model {
    counter: u32,
}

#[widget]
impl Widget for Win {
    fn model() -> Model {
        Model {
            counter: 0,
        }
    }

    fn update(&mut self, event: Msg) {
        match event {
            // A call to self.label1.set_text() is automatically inserted by the
            // attribute every time the model.counter attribute is updated.
            Msg::Decrement => self.model.counter -= 1,
            Msg::Increment => self.model.counter += 1,
            Msg::Quit => gtk::main_quit(),
        }
    }

    view! {
        gtk::Window {
            gtk::Box {
                orientation: Vertical,
                gtk::Button {
                    // By default, an event with one paramater is assumed.
                    clicked => Msg::Increment,
                    // Hence, the previous line is equivalent to:
                    // clicked(_) => Increment,
                    label: "+",
                },
                gtk::Label {
                    // Bind the text property of this Label to the counter attribute
                    // of the model.
                    // Every time the counter attribute is updated, the text property
                    // will be updated too.
                    text: &self.model.counter.to_string(),
                },
                gtk::Button {
                    clicked => Msg::Decrement,
                    label: "-",
                },
            },
            // Use a tuple when you want to both send a message and return a value to
            // the GTK+ callback.
            delete_event(_, _) => (Msg::Quit, Inhibit(false)),
        }
    }
}

注意:现在,属性会自动创建 struct Win,以及函数 root() 和相关的类型 ModelModelParamMsg 以及 Container。如果需要,您仍然可以提供方法和相关类型,但不能创建结构体。

警告:#[widget] 使得生成的结构体是公有的:因此,相应的模型和消息类型也必须是公有的。

[警告]

使用此属性时,由于代码生成简单,您的程序可能运行速度较慢。例如,以下代码 [source,rust]

fn update(&mut self, event: Msg) {
    for _ in 0..100 {
        self.model.counter += 1;
    }
}

将生成此函数:[source,rust]

fn update(&mut self, event: Msg) {
    for _ in 0..100 {
        self.model.counter += 1;
        self.label1.set_text(&self.model.counter.to_string());
    }
}

[警告]

此外,当前只有在将属性分配给模型时才会插入对 set_property() 的调用。例如,以下代码 [source,rust]

fn update(&mut self, event: Msg) {
    self.model.text.push_str("Text");
}

将不会按预期工作。

如果需要,请使用以下变体。 [source,rust]

fn update(&mut self, event: Msg) {
    self.model.text += "Text";
}

有关如何使用 relm 的更多信息,您可以查看 示例

捐赠

如果您喜欢这个项目并希望实现新功能,请在我的 Patreon 上支持我。

link

使用 relm 的项目

  • Yellow Pitaya:红色皮塔亚硬件示波器的桌面界面。
  • Game of Life:康威生命游戏模拟器
  • 国家解析器:解析谷歌位置历史并显示访问过的国家的时间线
  • Chessground:一个实验性的棋盘小部件
  • Effitask:基于todo.txt格式的图形任务管理器
  • KS Curve Tracer:AD2曲线追踪器的配套应用
  • Cigale:准备您在工作期间完成的任务时间表的工具
  • Projectpad:作为软件开发人员或系统管理员,管理秘密凭据和服务器信息。
  • TimezoneRS:一个GUI应用程序,可直观地查看不同时区的时间
  • Tubefeeder / Pipeline:在一个地方观看YouTube、LBRY和PeerTube视频。
  • Hotwire:以简单的方式研究一些流行协议的网络流量
  • gue:控制飞利浦hue灯的GUI
  • MyCitadel 钱包:MyCitadel 加密货币钱包应用程序

如果您想将您的项目添加到此列表中,请创建一个拉取请求

依赖项

~2MB
~46K SLoC