技术笔记:RustGUI编程

简介: 技术笔记:RustGUI编程

目录


1.可以用iced框架,star比较多,而且在快速发展中,源码跨平台;


2.在main方法文件最上面加上:#!【windows_subsystem = "windows"】,这样Windows平台运行编译好的gui程序时就不会弹出控制台框;


对于Mac OS,Linux可以自己写个图标配置(Linux是.desktop文件)就可以直接双击图标来打开程序而非必须先开一个控制台,所以这两个平台没有这个全局宏。


3.iced使用示例:根据官网示例写一个加减的按钮和显示:


Cargo.toml:(这个配置兼容性不好,换成下面代码块里的)


【package】


name = "demo-iced"


version = "0.1.0"


authors = 【"silentdoer "】


edition = "2018"


# See more keys and their definitions at


【dependencies】


iced = { git = "", features = 【"async-std", "debug"】 } # debug考虑不要


iced_web = "0.2"


serde = { version = "1.0", features = 【"derive"】 }


serde_json = "1.0"


【target.'cfg(not(target_arch = "wasm32"))'.dependencies】


async-std = "1"


directories = "2"


【target.'cfg(target_arch = "wasm32")'.dependencies】


web-sys = { version = "0.3", features = 【"Window", "Storage"】 }


wasm-timer = "0.2"


【package.metadata.deb】


assets = 【


【"target/release/todos", "usr/bin/iced-todos", "755"】,


【"iced-todos.desktop", "usr/share/applications/", "644"】,



上面的Cargo.toml配置有几个问题,第一是必需是vs2017或以上,第二就是debug模式编译的程序运行有问题,第三个就是需要编译的模块很多,第四个是win10编译出的release程序(debug是win10都运行有问题)win10可以用,但是win7运行失败(经过测试win7编译出的win10可以运行,但是win10编译出的在win7上仍然运行失败(2017,2015,gnu三个都失败了,等会再换2013和2012【2012直接编译失败,哪怕是OpenGL的】的C++如果还失败那只能在win7上编译Windows全平台了【或者测试下Ubuntu跨平台编译的gui程序是否可以同时在win10和win7上运行】));(当然也有好处,上面的配置用的GUI后端是DX或vulkan,而接下来的配置用的是OpenGL效率没上面的高【注意,不需要安装OpenGL,win10和win7里都有】)


【这种方式编译出来的程序也有问题,就是它放到一个没有安装过C++环境的系统里运行不了。。。坑啊,目前没有比较好的解决方案,暂时还是用第一种算了,然后win10和win7都以release编译一下(刚才又查了下说也可能是显卡驱动的原因。。)】


【package】


name = "demo-iced"


version = "0.1.0"


authors = 【"silentdoer "】


edition = "2018"


# See more keys and their definitions at


【dependencies】


iced = { git = "", default-features = false, features = 【"async-std", "debug", "glow"】 }


serde = { version = "1.0", features = 【"derive"】 }


serde_json = "1.0"


【target.'cfg(not(target_arch = "wasm32"))'.dependencies】


async-std = "1"


directories = "2"


【target.'cfg(target_arch = "wasm32")'.dependencies】


web-sys = { version = "0.3", features = 【"Window", "Storage"】 }


wasm-timer = "0.2"


【package.metadata.deb】


assets = 【


【"target/release/todos", "usr/bin/iced-todos", "755"】,


【"iced-todos.desktop", "usr/share/applications/", "644"】,



在项目根目录添加fonts目录,里面将Windows的simkai.ttf字体复制进去


main.rs:


#!【windows_subsystem = "windows"】


use iced::{


button, scrollable, text_input, Align, Application, Button, Checkbox,


Column, Command, Container, Element, Font, HorizontalAlignment, Length,


Row, Scrollable, Settings, Text, TextInput,


};


use serde::{Deserialize, Serialize};


pub fn main() {


Todos::run(Settings {


default_font: Some(include_bytes!("../fonts/simkai.ttf")),


..Settings::default()


})


}


#【derive(Debug)】


enum Todos {


Loading,


Loaded(State),


}


#【derive(Debug, Default)】


struct State {


scroll: scrollable::State,


input: text_input::State,


input_value: String,


filter: Filter,


tasks: Vec,


controls: Controls,


dirty: bool,


saving: bool,


}


#【derive(Debug, Clone)】


enum Message {


Loaded(Result),


Saved(Result),


InputChanged(String),


CreateTask,


FilterChanged(Filter),


TaskMessage(usize, TaskMessage),


}


impl Application for Todos {


type Executor = iced::executor::Default;


type Message = Message;


type Flags = ();


fn new(_flags: ()) -> (Todos, Command) {


(


Todos::Loading,


Command::perform(SavedState::load(), Message::Loaded),


)


}


fn title(&self) -> String {


let dirty = match self {


Todos::Loading => false,


Todos::Loaded(state) => state.dirty,


};


format!("Todos{} - Iced", if dirty { "" } else { "" })


}


fn update(&mut self, message: Message) -> Command {


match self {


Todos::Loading => {


match message {


Message::Loaded(Ok(state)) => {


self = Todos::Loaded(State {


input_value: state.inputvalue,


filter: state.filter,


tasks: state.tasks,


..State::default()


});


}


Message::Loaded(Err()) => {


self = Todos::Loaded(State::default());


}


_ => {}


}


Command::none()


}


Todos::Loaded(state) => {


let mut saved = false;


match message {


Message::InputChanged(value) => {


state.input_value = value;


}


Message::CreateTask => {


if !state.input_value.is_empty() {


state


.tasks


.push(Task::new(state.input_value.clone()));


state.input_value.clear();


}


}


//代码效果参考:http://www.lyjsj.net.cn/wx/art_23238.html

Message::FilterChanged(filter) => {

state.filter = filter;


}


Message::TaskMessage(i, TaskMessage::Delete) => {


state.tasks.remove(i);


}


Message::TaskMessage(i, task_message) => {


if let Some(task) = state.tasks.get_mut(i) {


task.update(taskmessage);


}


}


Message::Saved() => {


state.saving = false;


saved = true;


}


_ => {}


}


if !saved {


state.dirty = true;


}


if state.dirty && !state.saving {


state.dirty //代码效果参考:http://www.lyjsj.net.cn/wz/art_23236.html

= false;

state.saving = true;


Command::perform(


SavedState {


input_value: state.input_value.clone(),


filter: state.filter,


tasks: state.tasks.clone(),


}


.save(),


Message::Saved,


)


} else {


Command::none()


}


}


}


}


fn view(&mut self) -> Element {


match self {


Todos::Loading => loading_message(),


Todos::Loaded(State {


scroll,


input,


input_value,


filter,


tasks,


controls,


..


}) => {


let title //代码效果参考:http://www.lyjsj.net.cn/wz/art_23226.html

= Text::new("todos")

.width(Length::Fill)


.size(100)


.color(【0.5, 0.5, 0.5】)


.horizontal_alignment(HorizontalAlignment::Center);


let input = TextInput::new(


input,


"What needs to be done?",


input_value,


Message::InputChanged,


)


.padding(15)


.size(30)


.on_submit(Message::CreateTask);


let controls = controls.view(&tasks, filter);


let filtered_tasks =


tasks.iter().filter(|task| filter.matches(task));


let tasks: Element = if filtered_tasks.count() > 0 {


tasks


.itermut()


.enumerate()


.filter(|(, task)| filter.matches(task))


.fold(Column::new().spacing(20), |column, (i, task)| {


column.push(task.view().map(move |message| {


Message::TaskMessage(i, message)


}))


})


.into()


} else {


empty_message(match filter {


Filter::All => "You have not created a task yet...",


Filter::Active => "All your tasks are done! :D",


Filter::Completed => {


"You have not completed a task yet..."


}


})


};


let content = Column::new()


.max_width(800)


.spacing(20)


.push(title)


.push(input)


.push(controls)


.push(tasks);


Scrollable::new(scroll)


.padding(40)


.push(


Container::new(content).width(Length::Fill).center_x(),


)


.into()


}


}


}


}


#【derive(Debug, Clone, Serialize, Deserialize)】


struct Task {


description: String,


completed: bool,


#【serde(skip)】


state: TaskState,


}


#【derive(Debug, Clone)】


pub enum TaskState {


Idle {


edit_button: button::State,


},


Editing {


text_input: text_input::State,


delete_button: button::State,


},


}


impl Default for TaskState {


fn default() -> Self {


TaskState::Idle {


edit_button: button::State::new(),


}


}


}


#【derive(Debug, Clone)】


pub enum TaskMessage {


Completed(bool),


Edit,


DescriptionEdited(String),


FinishEdition,


Delete,


}


impl Task {


fn new(description: String) -> Self {


Task {


description,


completed: false,


state: TaskState::Idle {


edit_button: button::State::new(),


},


}


}


fn update(&mut self, message: TaskMessage) {


match message {


TaskMessage::Completed(completed) => {


self.completed = completed;


}


TaskMessage::Edit => {


self.state = TaskState::Editing {


text_input: text_input::State::focused(),


delete_button: button::State::new(),


};


}


TaskMessage::DescriptionEdited(new_description) => {


self.description = new_description;


}


TaskMessage::FinishEdition => {


if !self.description.is_empty() {


self.state = TaskState::Idle {


edit_button: button::State::new(),


}


}


}


TaskMessage::Delete => {}


}


}


fn view(&mut self) -> Element {


match &mut self.state {


// 重要


TaskState::Idle { edit_button } => {


let checkbox = Checkbox::new(


self.completed,


&format!("{}{}", self.description, "*").to_string(),


TaskMessage::Completed,


)


.width(Length::Fill);


Row::new()


.spacing(20)


.align_items(Align::Center)


// 空闲状态时,左侧一个checkbox,右侧的button样式是Icon


.push(checkbox)


.push(


// edit_button是state数据,edit_icon()返回的是一个Unicode字符作为显示字符(浏览器上不一致应该是fonts的原因)


Button::new(edit_button, edit_icon())


.on_press(TaskMessage::Edit)


.padding(10)


.style(style::Button::Icon),


)


.into()


}


// 当变为Editing状态时的view变化(要变成红色Delete)


TaskState::Editing {


text_input,


delete_button,


} => {


let text_input = TextInput::new<span style="

目录
打赏
0
0
0
0
0
分享
相关文章
探索编程世界的奇妙之旅:从初学者到小有成就
【10月更文挑战第14天】探索编程世界的奇妙之旅:从初学者到小有成就
40 0
|
3月前
编程之路:从代码到哲学的思考之旅
在数字世界的编织中,每一行代码都是我们与机器对话的语言。本文将带领读者穿梭于编程的世界,探索技术背后的深层意义,以及如何通过代码实现个人成长和对世界的理解。我们将一起走进编程的内在逻辑,解锁那些隐藏在键盘敲击声中的哲理,并分享一些实用的编程技巧。
46 3
探索编程之海:我的技术感悟之旅
【9月更文挑战第14天】在编程的浩瀚海洋中,我是一位勇敢的探险者。每一次代码的编写,都是对未知领域的挑战。本文将分享我在技术探索中的心得体会,从初识编程的迷茫到逐渐找到自己的航线,再到不断精进技艺的过程。通过这段旅程,我深刻理解了“你必须成为你希望在世界上看到的改变”这句话的内涵,并将它融入到我的学习和实践中。让我们一起跟随这篇文章,揭开编程世界的神秘面纱,找到属于自己的航道。
51 9
探索代码之美:编程的艺术与实践
【7月更文挑战第31天】在数字世界的构建中,编程不仅仅是一项技术工作,它更是一种艺术。本文将带领读者深入编程的核心,从基础语法到设计模式,再到软件架构,探索如何通过代码表达创造性思维和解决实际问题。我们将一起见证编程如何从枯燥的指令序列转变为优雅的解决方案,以及这一过程如何影响我们的思考方式和解决问题的策略。
代码之美:探索编程的艺术与实践
【8月更文挑战第8天】 在数字化时代,编程已成为一门不可或缺的技艺。它不仅仅是一种工具,更是一种艺术形式。通过这篇文章,我们将深入探讨编程的美学原则,以及如何将这些原则应用于实际开发中,从而提升代码的质量和可维护性。文章将结合具体案例,展示优雅代码的力量,并讨论如何培养良好的编程习惯和持续学习的重要性。
56 3
计算机编程:从基础到实践,探索编程的奥秘
计算机编程:从基础到实践,探索编程的奥秘
92 1
|
9月前
|
编程入门(二)【计算机基础三】
编程入门(二)【计算机基础三】
67 1
技术经验分享:Delphi下的GDI+编程【2】DrawLine
技术经验分享:Delphi下的GDI+编程【2】DrawLine
153 0
探索代码之美:我的编程思考之旅
【5月更文挑战第8天】 在数字化的浪潮中,编程已成为一种艺术,一种用逻辑与创造力编织的语言。本文将分享我在编程实践中的一些技术感悟,从最初的困惑到逐渐的深入理解,再到最后的灵活应用,我经历了一段充满挑战与收获的旅程。文章不仅探讨了编程技巧的提升,还涉及了对软件设计原则的认识,以及如何通过不断学习来适应快速变化的技术环境。
编程入门(二)【计算机基础一】
编程入门(二)【计算机基础一】
50 0