如何把Rust的 iced从 0.12升级到0.14?

编程语言 2026-07-12

我在iced 0.12中有这段能够正常工作的代码,现在想把它升级到iced 0.14。

use iced::widget::{container, text};
use iced::{Application, Color, Command, Element, Settings, Subscription, Theme};
use std::sync::{Arc, Mutex};
use std::thread;
use std::time::Duration;

#[derive(Debug, Clone)]
pub(crate) enum Message {
    ColorChanged(ColorState),
}

#[derive(Debug, Clone, Copy, PartialEq)]
enum ColorState {
    Red,
    Orange,
    Green,
}

impl ColorState {
    fn next(self) -> Self {
        match self {
            ColorState::Red => ColorState::Orange,
            ColorState::Orange => ColorState::Green,
            ColorState::Green => ColorState::Red,
        }
    }

    fn to_color(self) -> Color {
        match self {
            ColorState::Red => Color::from_rgb(0.8, 0.0, 0.0),
            ColorState::Orange => Color::from_rgb(1.0, 0.5, 0.0),
            ColorState::Green => Color::from_rgb(0.0, 0.8, 0.0),
        }
    }

    fn to_text(self) -> &'static str {
        match self {
            ColorState::Red => "Red",
            ColorState::Orange => "Orange",
            ColorState::Green => "Green",
        }
    }
}

struct ColorCycleApp {
    current_color: ColorState,
    color_state: Arc<Mutex<ColorState>>,
}

impl Application for ColorCycleApp {
    type Message = Message;
    type Theme = Theme;
    type Executor = iced::executor::Default;
    type Flags = ();

    fn new(_flags: Self::Flags) -> (Self, Command<Self::Message>) {
        let color_state = Arc::new(Mutex::new(ColorState::Red));

        // Start the background thread
        let color_state_clone = Arc::clone(&color_state);
        thread::spawn(move || {
            loop {
                thread::sleep(Duration::from_secs(2));

                let mut state = color_state_clone.lock().unwrap();
                *state = state.next();
                println!("Thread changed color to: {:?}", *state);
            }
        });

        (
            Self {
                current_color: ColorState::Red,
                color_state,
            },
            Command::none(),
        )
    }

    fn title(&self) -> String {
        String::from("My GUI")
    }

    fn update(&mut self, message: Self::Message) -> Command<Self::Message> {
        match message {
            Message::ColorChanged(new_color) => {
                self.current_color = new_color;
                println!("New color: {:?}", new_color);
                Command::none()
            }
        }
    }

    fn view(&'_ self) -> Element<'_, Self::Message> {
        let current_color = self.current_color.to_color();

        let label = text(self.current_color.to_text()).size(48);

        let colored_container = container(label)
            .width(iced::Length::Fill)
            .height(iced::Length::Fill)
            .center_x()
            .center_y()
            .style(move |_theme: &Theme| container::Appearance {
                background: Some(iced::Background::Color(current_color)),
                ..Default::default()
            });

        colored_container.into()
    }

    fn subscription(&self) -> Subscription<Self::Message> {
        let color_state = Arc::clone(&self.color_state);

        iced::subscription::unfold("color_monitor", ColorState::Red, move |last_color| {
            let color_state = Arc::clone(&color_state);
            async move {
                loop {
                    std::thread::sleep(Duration::from_millis(100));

                    let current_color = {
                        let state = color_state.lock().unwrap();
                        *state
                    };

                    if current_color != last_color {
                        return (Message::ColorChanged(current_color), current_color);
                    }
                }
            }
        })
    }
}

fn main() -> iced::Result {
    ColorCycleApp::run(Settings {
        window: iced::window::Settings {
            size: iced::Size::new(400.0, 300.0),
            ..Default::default()
        },
        ..Default::default()
    })
}

我遇到4 个错误。

  1. 未解析的导入 iced::Command(Rust给出的建议是std::process::Command或 tokio::process::Command)
  2. 无法解析:在 iced 中找不到 subscription
  3. 找不到模块 container 中的结构体、变体或联合类型 Appearance
  4. 预期为trait,但找到了结构体 Application

到目前为止,我尝试了使用iced:Program(用于处理Application)以及使用Container:Style代替Appearance,但还没走到那一步。

解决方案

这是修复后的版本:

use iced::{
    Color, Element, Length, Subscription, Task, Theme,
    widget::{container, text},
};
use std::sync::{Arc, Mutex};
use std::thread;
use std::time::Duration;

#[derive(Debug, Clone)]
pub(crate) enum Message {
    ChangeColor,
}

#[derive(Debug, Clone, Copy, PartialEq)]
enum ColorState {
    Red,
    Orange,
    Green,
}

impl ColorState {
    fn next(self) -> Self {
        match self {
            ColorState::Red => ColorState::Orange,
            ColorState::Orange => ColorState::Green,
            ColorState::Green => ColorState::Red,
        }
    }

    fn to_color(self) -> Color {
        match self {
            ColorState::Red => Color::from_rgb(0.8, 0.0, 0.0),
            ColorState::Orange => Color::from_rgb(1.0, 0.5, 0.0),
            ColorState::Green => Color::from_rgb(0.0, 0.8, 0.0),
        }
    }

    fn to_text(self) -> &'static str {
        match self {
            ColorState::Red => "Red",
            ColorState::Orange => "Orange",
            ColorState::Green => "Green",
        }
    }
}

struct ColorCycleApp {
    current_color: ColorState,
    color_state: Arc<Mutex<ColorState>>,
}

impl ColorCycleApp {
    fn new() -> Self {
        let color_state = Arc::new(Mutex::new(ColorState::Red));

        // Start the background thread
        let color_state_clone = Arc::clone(&color_state);
        thread::spawn(move || {
            loop {
                thread::sleep(Duration::from_secs(2));

                let mut state = color_state_clone.lock().unwrap();
                *state = state.next();
                println!("Thread changed color to: {:?}", *state);
            }
        });

        Self {
            current_color: ColorState::Red,
            color_state,
        }
    }

    fn title(&self) -> String {
        String::from("My GUI")
    }

    fn update(&mut self, message: Message) -> Task<Message> {
        match message {
            Message::ChangeColor => {
                let new_color = *self.color_state.lock().unwrap();

                if self.current_color != new_color {
                    self.current_color = new_color;
                    println!("New color: {:?}", new_color);
                }

                Task::none()
            }
        }
    }

    fn view(&'_ self) -> Element<'_, Message> {
        let current_color = self.current_color.to_color();

        let label = text(self.current_color.to_text()).size(48);

        let colored_container = container(label)
            .width(iced::Length::Fill)
            .height(iced::Length::Fill)
            .center(Length::Fill)
            .style(move |_theme: &Theme| container::Style {
                background: Some(iced::Background::Color(current_color)),
                ..Default::default()
            });

        colored_container.into()
    }

    fn subscription(&self) -> Subscription<Message> {
        iced::time::every(Duration::from_millis(100)).map(|_| Message::ChangeColor)
    }
}

fn main() -> iced::Result {
    iced::application(
        ColorCycleApp::new,
        ColorCycleApp::update,
        ColorCycleApp::view,
    )
    .subscription(ColorCycleApp::subscription)
    .title(ColorCycleApp::title)
    .window(iced::window::Settings {
        size: (400.0, 300.0).into(),
        ..Default::default()
    })
    .run()
}

它需要 tokio 功能:

[dependencies]
iced = { version = "0.14", features = ["tokio"] }

解释

  1. iced::Command 未找到。
    iced::Command 大致被 iced::Task 取代,过程中有一些小的变动。
  2. iced::subscription 无法解析。
    虽然 iced::subscription 模块被移除了,但 iced::Subscription 仍然存在于根模块中。然而 iced::subscription::unfold 也被移除了,因此需要大幅重构上文所示的订阅逻辑。
  3. iced::widget::container::Appearance 未找到。
    iced::widget::container::Appearance 结构体本质上被重命名为 iced::widget::container::Style,并新增了 snap 字段。
  4. 预期的trait,找到了结构体 Application
    iced::application::Application trait已被移除,相应地,主应用程序结构体需要的方法应当「自由地定义」(如上所示)。iced 0.14中的 Application 结构体仍然提供关于应用可用内容的一些指引。
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章