[Aprender Rust juntos | Marco | marco helado] Marco de GUI nativo multiplataforma oxidado - helado


prefacio

Para aprender un lenguaje de programación, nunca debes abandonar la aplicación del lenguaje de programación. Al aprender otros lenguajes de programación, como C++, es bastante aburrido aprender solo gramática, estructura de datos y algoritmos, es cuestión de perseverancia. La mejor manera en este momento es hacer que el aprendizaje sea interesante. Cuando estaba estudiando, la fuente de mi interés era hacer hermosas ventanas en Windows para mejorar mi aprendizaje y eficiencia en el trabajo. Por esta razón, he estudiado QT, MFC, estos marcos son muy buenos, y efectivamente lograron el efecto que quiero, pero el desarrollo es mas engorroso, despues aprendi qt python, y el desarrollo se volvio muy conveniente, pero nuevamente aparecio un nuevo problema, es decir, el empaque no es conveniente, por por eso, he experimentado tortuosas exploraciones en este camino. En este momento, aprender Rust es lo mismo. Si desea mejorar su capacidad de aprendizaje, debe encontrar los puntos de interés. Para Rust, realmente quiero usar las ventajas de Rust para realizar ventanas de Windows, y también he encontrado soluciones, como qt de Rust, pero es engorrosa, se presentarán en un artículo posterior; también está Tauri UI, un marco de interfaz de usuario multiplataforma que usa Rust como back-end, su idea es más como Electron, el front-end usa el diseño html+css, y luego El backend usa Rust, y luego empaqueta la aplicación. El método de uso se presentará más adelante en esta serie de artículos; también está Iced, que se presenta en este artículo, que se parece más al aleteo de Rust , un marco GUI multiplataforma basado en Elm.

Iced es un marco de GUI que me interesa más. Su método de desarrollo es bastante amigable para personas como yo que han aprendido Vue, y se siente muy cómodo con las características de Rust. Además, su apariencia también es bastante alta, por lo que lo aprendo.

Características de Iced

  • Simple y fácil de usar, con una serie de API integradas
  • Tipo seguro, con un modelo de programación interactivo
  • Multiplataforma (compatible con Windows, Mac, Linux y Web)
  • Disposición Responsive
  • basado en widgets
  • Compatibilidad con widgets personalizados
  • Hay otras características, se recomienda ir a Github para ver

1. Construya el proyecto

1. Crea un proyecto normalmente

Primero crea un proyecto

cargo new gui_iced_001

2. Importar idea

Importar proyecto usando idea

3. Introducir dependencias

Abra Cargo.toml y escriba las dependencias

iced = "0.4"

注意:Estoy usando una versión posterior a 2021. Si no lo está, se recomienda ir al sitio web oficial para conocer la estrategia de procesamiento correspondiente, que no se explicará aquí.

En este punto, el archivo debería verse así

Hasta ahora, el proyecto se ha construido y el siguiente paso es escribir nuestra demostración.

2. Escribe una demostración

Hay muchos ejemplos de Iced on Github, entre los cuales el más clásico y el único ejemplo escrito en el sitio web oficial es Counter counter, porque la demostración de Counter se realiza desde aquí. Aunque esto es muy simple, tiene muchas trampas. Fue difícil escribir esta demostración. Hablemos de dos trampas. Este marco no distingue entre filas y columnas. El código del ejemplo es demasiado antiguo. a paso explorado.

El siguiente contenido será bastante diferente del sitio web oficial, y el sitio web oficial no funcionará, preste atención a la proyección.

1. Estado de escritura

Primero, escriba un estado para el programa. Este concepto central inevitablemente se usará al aprender Vue, React o Flutter. No lo explicaré aquí por el momento, pero daré el código directamente.

struct Counter {
    
    
    value: i32,
    // The local state of the two buttons
    increment_button: button::State,
    decrement_button: button::State,
}

Aquí se define una estructura Counter , esta estructura se considera como el estado de nuestra ventana, sus miembros valuerepresentan el valor de la cuenta del contador increment_buttony decrement_buttonel estado de los dos botones + y -.

2. Definir el tipo de mensaje

El siguiente paso es definir los tipos de mensajes utilizados en el programa. La interacción en el programa se lleva a cabo a través de señales. Qt lo hace muy bien. Si ha estudiado qt o el front-end Vue y otros marcos, esto es fácil de entender. .

#[derive(Debug, Clone, Copy)]
enum Message {
    
    
    IncrementPressed,
    DecrementPressed,
}

Aquí se definen dos mensajes, uno es IncrementPressedpara representar el botón + en el que se hace clic y el otro es para DecrementPressedrepresentar el botón - en el que se hace clic.

3. Escribir lógica de vista

El ejemplo oficial aquí es implementar directamente la vista y la actualización de Counter, pero después de mi exploración, no se puede usar directamente.

El programa Iced necesita implementar Application o Sandbox. No me importa lo que estos dos signifiquen por ahora. Usamos Sandbox aquí porque es lo suficientemente simple.

Un Sandbox vacío debería verse así

impl Sandbox for Counter {
    
    
    type Message = ();

    fn new() -> Self {
    
    
        todo!()
    }

    fn title(&self) -> String {
    
    
        todo!()
    }

    fn update(&mut self, message: Self::Message) {
    
    
        todo!()
    }

    fn view(&mut self) -> Element<'_, Self::Message> {
    
    
        todo!()
    }
}

Aquí está la introducción de arriba a abajo.

Mensaje

Representa todos los mensajes de la ventana actual. Al usarlo, debe pasar la enumeración de mensajes definida. Por ejemplo, el uso aquí debería ser así,

#[derive(Debug, Clone, Copy)]
enum Message {
    
    
    IncrementPressed,
    DecrementPressed,
}
// ....
type Message = Message;

nuevo

Aquí es lo mismo que escribir código en general, debe devolver su propia instancia, por lo que no explicaré demasiado

fn new() -> Self {
    
    
        Self {
    
     value: 0, increment_button: Default::default(), decrement_button: Default::default() }
    }

título

Ver el nombre, aquí está para devolver el nombre de la ventana actual

fn title(&self) -> String {
    
    
        String::from("Counter - Iced")
    }

actualizar

Esta es la lógica de mensajes de la ventana de procesamiento. Esta ventana procesa dos mensajes. Uno es que IncrementPressedse hace clic en el botón +. Si se hace clic, el valor del estado será +1. El otro es que DecrementPressedse hace clic en el botón -. Si se hace clic, el valor del estado es -1. El procesamiento aquí es bastante simple y no tiene en cuenta los valores límite.

fn update(&mut self, message: Message) {
    
    
        match message {
    
    
            Message::IncrementPressed => {
    
    
                self.value += 1;
            }
            Message::DecrementPressed => {
    
    
                self.value -= 1;
            }
        }
    }

vista

Aquí para devolver el diseño de la ventana, de hecho, para construir esta ventana, aquí el código de la ventana de Counter es el siguiente

fn view(&mut self) -> Element<Message> {
    
    
        Column::new().push(
            Text::new("Counter")
        ).push(
            Row::new().push(
                Button::new(&mut self.increment_button, Text::new("+"))
                    .on_press(Message::IncrementPressed).width(Length::Fill),
            ).push(
                Text::new(self.value.to_string()).size(22),
            ).push(
                Button::new(&mut self.decrement_button, Text::new("-"))
                    .on_press(Message::DecrementPressed).width(Length::Fill),
            )
        )
        .align_items(Alignment::Center).into()
    }

Se puede ver que la llamada de cadena de tiempo utilizada aquí es capa por capa. Su código es muy similar a flutter. Si has estudiado flutter, debes estar muy familiarizado con él. Aquí hago un dibujo para explicar este código. Primero La ventana está dividida en dos filas por Columna, y su diseño es consistente con el marco rojo, con dos filas arriba y abajo

注意:En este marco, las filas y las columnas son estúpidamente indistinguibles. Columna significa columna, y en este marco significa fila.

En la primera línea, solo se agrega un componente de texto y se proporciona el valor inicial Counter. Originalmente, se pretendía usar chino aquí 计数器, pero esto no es compatible con chino.

Column::new().push(
            Text::new("Counter")
        )

En la segunda línea, se agrega un componente de Fila (componente) , y se agregan tres componentes, que son dos Botones, que son botones + y -, y un componente de Texto para mostrar el Valor actual

//...
.push(
            Row::new().push(
                Button::new(&mut self.increment_button, Text::new("+"))
                    .on_press(Message::IncrementPressed).width(Length::Fill),
            ).push(
                Text::new(self.value.to_string()).size(22),
            ).push(
                Button::new(&mut self.decrement_button, Text::new("-"))
                    .on_press(Message::DecrementPressed).width(Length::Fill),
            )
        )

Así que el diseño de la ventana debería verse así

4. Escribe la función principal

La ventana escrita no se puede ejecutar automáticamente, debe iniciarse, generalmente inicie la ventana en la función principal, será más fácil aquí, pegue el código directamente aquí

fn main() -> iced::Result {
    
    
    Counter::run(Settings::default())
}

Para iniciar la ventana, simplemente llame al método de ejecución de la ventana, que se pasa en Configuración para establecer el estado inicial de la ventana. Aquí, el estado predeterminado se usa directamente. Si desea profundizar más adelante, aquí habrá un especial problema para explicarlo.

3. Efecto de operación

En este punto, ejecutamos la demostración actualmente escrita

注意:El código completo se encuentra al final del artículo, si te da pereza escribir el código, puedes copiarlo directamente.


Resumir

Este número presenta el marco Iced de la GUI de Rust.Después de mi exploración, finalmente construí la demostración de Counter. "Después de mi experiencia, creo que este marco no es tan bueno como me imaginaba. De hecho, es el marco de GUI nativo de Rust y tiene las características que dijo. Es realmente hermoso, pero tiene el mayor problema. No es compatible con chino. , y la fila y la columna son estúpidamente indistinguibles. El documento oficial es demasiado antiguo, por lo que el proceso de construcción de una demostración se vuelve muy complicado y no es muy amigable para el desarrollo. Lo único que vale la pena mencionar es este código, que es realmente cómodo. Bastantes, esto no tiene comparación con otros marcos de interfaz de usuario. Esto es digno de aprobación. Espero que este marco o sus sucesores puedan resolver estos problemas en el futuro, para que la interfaz de usuario de Rust pueda volverse más fuerte.

código completo

use iced::{
    
    Alignment, button, Button, Column, Element, Length, Row, Sandbox, Settings, Text};

fn main() -> iced::Result {
    
    
    Counter::run(Settings::default())
}

struct Counter {
    
    
    value: i32,
    // The local state of the two buttons
    increment_button: button::State,
    decrement_button: button::State,
}

#[derive(Debug, Clone, Copy)]
enum Message {
    
    
    IncrementPressed,
    DecrementPressed,
}

impl Sandbox for Counter {
    
    
    type Message = Message;

    fn new() -> Self {
    
    
        Self {
    
     value: 0, increment_button: Default::default(), decrement_button: Default::default() }
    }

    fn title(&self) -> String {
    
    
        String::from("Counter - Iced")
    }

    fn update(&mut self, message: Message) {
    
    
        match message {
    
    
            Message::IncrementPressed => {
    
    
                self.value += 1;
            }
            Message::DecrementPressed => {
    
    
                self.value -= 1;
            }
        }
    }

    fn view(&mut self) -> Element<Message> {
    
    
        Column::new().push(
            Text::new("Counter")
        ).push(
            Row::new().push(
                Button::new(&mut self.increment_button, Text::new("+"))
                    .on_press(Message::IncrementPressed).width(Length::Fill),
            ).push(
                Text::new(self.value.to_string()).size(22),
            ).push(
                Button::new(&mut self.decrement_button, Text::new("-"))
                    .on_press(Message::DecrementPressed).width(Length::Fill),
            )
        )
        .align_items(Alignment::Center).into()
    }
}


Supongo que te gusta

Origin blog.csdn.net/weixin_47754149/article/details/127271805
Recomendado
Clasificación