目录
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="