Rust UI开发(四):iced中如何添加菜单栏(串口调试助手)

news2024/11/26 0:57:22

注:此文适合于对rust有一些了解的朋友
iced是一个跨平台的GUI库,用于为rust语言程序构建UI界面。
在这里插入图片描述
这是一个系列博文,本文是第四篇,前三篇链接:
1、Rust UI开发(一):使用iced构建UI时,如何在界面显示中文字符
2、Rust UI开发(二):iced中如何为窗口添加icon图标
3、Rust UI开发(三):iced如何打开图片(对话框)并在窗口显示图片?

注:本篇是系列的第四篇,从本篇开始,将基于编写一个串口调试助手项目,以多个篇幅,来分别说明。
要编写一个调试助手,总的来说,可以分为UI设计、底层串口数据通讯、交互三个方面。
所以,此后数篇博文都将以“串口调试助手”项目为例,辅以各个功能的介绍说明如菜单栏如何创建、串口UI界面如何设计、串口通讯如何实现以及数据交互如何实现等,我希望最终能达到一个完整的可使用的以rust和iced为主要库构建的实例项目,可以实现与串口设备的通讯,至少能稳定实现数据交互。

本篇主要关注一个问题,就是菜单栏的创建,iced库中并没有包含menu部件,需要用到iced_aw库。github地址:
https://github.com/iced-rs/iced_aw
这是一个包含有许多额外部件的iced库,如颜色选择器、日期选择器、菜单、拆分、Tab组件等。

从本篇开始,将附加程序中用到的依赖项
Cargo.toml:

[dependencies]
iced.workspace=true
iced.features=["image","svg"]

iced_aw={ workspace=true, features = ["card","menu","quad","icon_text"] }
image.workspace=true
num-complex.workspace=true

[workspace.dependencies]
iced = "0.10"
iced_aw={ version = "0.7.0", default-features = false }

image="*"
num-complex="*"

项目文件结构:
在这里插入图片描述

实际效果预览:
在这里插入图片描述

声明:本篇参考iced_aw的官方关于menu的示例,但作了一些修改,以适应自定义项目的所需,所以,如果想要了解iced_aw源代码的,建议去参看官方示例。

关于iced如何构建窗口,以及窗口设置、图标设置等内容,可以看本系列前三篇,本篇主要实现这样的功能,创建菜单栏,当选择某个菜单项时,文本框中显示当前选择的菜单项名称。

菜单栏创建

1、添加依赖
参看前面的toml文件。

2、程序里导入


use iced_aw::menu::{menu_tree::MenuTree, CloseCondition, ItemHeight, ItemWidth, PathHighlight};
use iced_aw::quad;
use iced_aw::{helpers::menu_tree, menu_bar, menu_tree};

其中有一些是本篇内容没有用到的,删掉也可以,不删也没关系,不影响程序的测试。

3、menu部件创建
iced_aw的官方示例中,关于menu的创建,看起来比较复杂,原因是功能做的比较丰富,但如果不需要那么多功能,则可以对其进行修改。
官方示例程序,是层层递进的结构,并且写的复杂,是因为要设置菜单的样式、菜单的反馈对应的动作等。
但是,我们可以从简单的先来看,如果你只是要在窗口上实现一个菜单栏,那么:

menu_bar!(menu_tree!(button("文件")))

这个就可以实现,当然这样实现的菜单没有任何功能,也没有样式的变化。它就是在窗口创建了一个菜单项。
在这里插入图片描述
上图可以看到,这样创建的无样式的菜单项和旁边设置了主题样式的菜单项,有明显区别。
事实上,在这里的菜单项,就是一个个的按钮组成。通过设置按钮的样式,就可以改变菜单的样式。
所以,在官方示例中,是创建了一个ButtonStyle结构体:

struct ButtonStyle;

然后,将button部件的StyleSheet特性实现于创建的结构体ButtonStyle上:

impl button::StyleSheet for ButtonStyle {
    type Style = iced::Theme;

    //生成按钮的激活外观
    fn active(&self, style: &Self::Style) -> button::Appearance {
        button::Appearance {
            text_color: style.extended_palette().background.base.text,
            border_radius: [2.0; 4].into(),
            background: Some(Color::TRANSPARENT.into()),
            ..Default::default()
        }
    }

    //生成按钮的悬停外观
    fn hovered(&self, style: &Self::Style) -> button::Appearance {
        let plt = style.extended_palette();

        button::Appearance {
            background: Some(plt.primary.weak.color.into()),
            text_color: plt.primary.weak.text,
            border_radius:[6.0; 4].into(),                      //border_radius:倒角半径
            ..self.active(style)
        }
    }
}

上面的实现中,启用了button部件的active和hovered两个功能,这两个功能是当我们将鼠标放在按钮上悬停以及激活按钮时,按钮的样式会按照设定的程序来变化。可以看到,其中改变的是文本颜色、背景色以及部件的四边的倒角。
基于这个按钮样式数据ButtonStyle,我们可以创建一个基础按钮base_button:

//基础按钮
fn base_button<'a>(
    content: impl Into<Element<'a, Message, iced::Renderer>>,
    msg: Message,
) -> button::Button<'a, Message, iced::Renderer> {
    button(content)
        .padding([4, 8])
        .style(iced::theme::Button::Custom(Box::new(ButtonStyle {})))
        .on_press(msg)
}

在base_button的基础上,创建带标签按钮labeled_button:

//带标签按钮
fn labeled_button<'a>(label: &str, msg: Message) -> button::Button<'a, Message, iced::Renderer> {
    base_button(
        text(label)
            .width(Length::Fill)
            .height(Length::Fill)
            .vertical_alignment(alignment::Vertical::Center),
        msg,
    )
}

然后创建测试按钮debug_button:

//测试按钮
fn debug_button<'a>(label: &str) -> button::Button<'a, Message, iced::Renderer> {
    labeled_button(label, Message::InputChanged(label.into()))
}

最后,在菜单项中调用这个有样式设定的按钮即可:

fn debug_item<'a>(label: &str) -> MenuTree<'a, Message, iced::Renderer> {
    menu_tree!(debug_button(label).width(Length::Fill).height(Length::Fill))
}

以上,都是官方示例给出的步骤,它是用函数块的形势,将每一步分解,这样方便多次调用,以及对某个涉及到的项进行动态更改。
但是,如果你不想这样多次,就想一个函数实现菜单项功能,那么可以自己重新写一个函数:

///简单的菜单调用
fn menu_simple<'a>(label:&str,_app:&Counter)->MenuTree<'a,Message,iced::Renderer>{
    
    menu_tree( button("haha")
    .padding([4, 8])
    .style(iced::theme::Button::Custom(Box::new(ButtonStyle {})))
    .on_press(Message::InputChanged(label.into()))
        , vec![
            //debug_item("label"),
            menu_tree!(text("haha"))
        ]
        )
}

可以看到,在我们自定义的函数里,使用menu_tree,可以直接创建菜单和子菜单,但数量少时还可以,数量多了,写在一个函数里,就不太方便了。
在这里插入图片描述
这里,我们在自定义函数里只是简单的编写了一些程序,目的是演示,如果去编写实际项目,建议按照官方示例的模板,因为那样写比较有清晰的结构。

现在,我们了解如何创建菜单,接下来响应菜单。其实这里就比较容易了,因为菜单是由一个个button这样的小部件组成的,只需要监控小部件的触发函数,就可以在交互中传回消息。以我们自定义的函数为例,菜单中button的on_press函数,绑定了消息参数:InputChanged,InputChanged附带一个String类型的返回值。

button("haha")
    .padding([4, 8])
    .style(iced::theme::Button::Custom(Box::new(ButtonStyle {})))
    .on_press(Message::InputChanged(label.into())

在Updata函数里更新:

 Message::InputChanged(value) =>{
                self.value=value;
            }

这里的逻辑是,当菜单项的按钮点击时,InputChanged消息响应,返回当前的菜单项文本值,在update中,我们把文本值传给定义的数据value。而value被我们绑定到一个文本框:

text(format!("当前所选菜单是:{:?}",self.value)).size(20)

这样,当窗口启动后,我们只要点击当前菜单项,其名称就通过消息传递给文本框显示。
这其中关于Sandbox的窗口的update、view等函数就不细说了,前面的博文里已经有过说明。

需要注意的是,本篇是说明了如何创建菜单及如何简单的应答,关于详细的对应于“串口调试助手”实例的菜单的创建程序将在后面的篇章中说明,本文就到此了。

动态演示:
在这里插入图片描述

完整代码:
完整代码里有一些另外的数据和函数,是本篇未提及的,但不影响本篇内容的测试。另外,所有代码都是测试中的程序,所以可能会不够干净清晰。

use iced::widget::{button, column,row, text,combo_box,pick_list,svg};
use iced::{Alignment,theme, Element, Color,Sandbox,Length, Settings, alignment};
use iced::widget::Column;
use iced::Font;
use iced::font::Family;
use iced::window;
use iced::window::icon;

use iced_aw::menu::{menu_tree::MenuTree, CloseCondition, ItemHeight, ItemWidth, PathHighlight};
use iced_aw::quad;
use iced_aw::{helpers::menu_tree, menu_bar, menu_tree};

extern  crate image;
extern crate num_complex;

pub fn main() -> iced::Result {
    //Counter::run(Settings::default())             //此处为使用默认窗口设置 
    let ff="微软雅黑";                  //设置自定义字体

    //第二种获取rgba图片的方法,利用Image库
    let img2=image::open("../iced_test/img/img3.jpg");
    let img2_path=match  img2 {
        Ok(path)=>path,
        Err(error)=>panic!("error is {}",error),
    };
    let img2_file=img2_path.to_rgba8();
    let ico2=icon::from_rgba(img2_file.to_vec(), 64, 64);
    let ico2_file=match ico2{
        Ok(file)=>file,
        Err(error)=>panic!("error is {}",error),
    };
    Counter::run(Settings { 
        window:window::Settings{                    //设置自定义窗口尺寸
            size:(800,600),
            //icon:Some(ico_file),
            icon:Some(ico2_file),
            ..window::Settings::default()
        },
        default_font:Font{                          //设置自定义字体,用于显示中文字符
            family:Family::Name(ff),
            ..Font::DEFAULT},
        ..Settings::default()
    })
}
//创建结构体struct
struct Counter{
    value: String,
    value2:String,
    sli_value:f32,
    baudrates:combo_box::State<Baudrate>,
    selected_port:Option<Baudrate>,
    selected_baudrate:Option<Baudrate>,
    selected_databit:Option<Baudrate>,
    selected_pabit:Option<Baudrate>,
    selected_stopbit:Option<Baudrate>,
    text:String,
}

#[derive(Debug, Clone)]           //为下方的enum添加特性trait
enum Message {
    Showtext,
    InputChanged(String),
    SliderChanged(f32),
    Selected_port(Baudrate),
    Selected_baud(Baudrate),
    Selected_databit(Baudrate),
    Selected_pabit(Baudrate),
    Selected_stopbit(Baudrate),
    OptionHovered(Baudrate),
    Closed,
}

//sandbox是一个trait
impl Sandbox for Counter {             //impl将sandbox添加给Counter,使Counter具有了sandbox的一些特性
    type Message = Message;
    fn new() -> Self {                  //初始化sandbox,返回初始值
        Self { 
            value: String::new(),
            value2:String::new(),
            sli_value:0.0,
            baudrates: combo_box::State::new(Baudrate::BAUD.to_vec()),
            selected_port:None,
            selected_baudrate: None,
            selected_databit:None,
            selected_pabit:None,
            selected_stopbit:None,
            text: String::new(),
        }
    }

    fn title(&self) -> String {         //返回sandbox的标题
        String::from("iced_串口助手")
        //self.value.clone()
    }

    fn update(&mut self, message: Message) {        //此处书写更新逻辑程序,所有UI交互会在这里处理
       
        match message {
            Message::Showtext=> { 

                let ss=&self.value;         //新建一个value的引用
                self.value2=ss.to_string();          //将变量的引用字符化后传给value2
                    
            }
            Message::InputChanged(value) =>{
                self.value=value;
            }
            Message::SliderChanged(sli_value)=>{
                self.sli_value=sli_value;
            }
            Message::Selected_port(port)=>{
                self.selected_port=Some(port);
            }
            Message::Selected_baud(baudrate)=>{
                self.selected_baudrate=Some(baudrate);
                self.text=baudrate.hello().to_string();
            }
            Message::Selected_databit(databit)=>{
                self.selected_databit=Some(databit);
            }
            Message::Selected_pabit(pabit)=>{
                self.selected_pabit=Some(pabit);
            }
            Message::Selected_stopbit(stopbit)=>{
                self.selected_stopbit=Some(stopbit);
            }
            Message::OptionHovered(baudrate)=>{
                self.text=baudrate.hello().to_string();
            }
            Message::Closed=>{
                self.text = self.selected_baudrate.map(|baudrate| baudrate.hello().to_string())
                                                    .unwrap_or_default();
            }
                
        }
    }

    fn view(&self) -> Element<Message> {            
        //let ff="Microsoft YaHei"; 
        column![
            row![
                menu_bar!(
                    menu_1(self),menu_2(self),menu_group("工具",self),menu_group("帮助", self))//menu_3(self), menu_4(self))
                        .item_width(ItemWidth::Uniform(180))
                        .item_height(ItemHeight::Uniform(27)

                        ),
                //menu_bar!(menu_group(self)),
                menu_bar!(menu_tree!(button("文件"))),
                menu_bar!(menu_simple("简单",self))
            ]
            .spacing(20),
            //ser_group(self)
            text(format!("当前所选菜单是:{:?}",self.value)).size(20)
        
        ]
        .spacing(40)
        .padding(6)
        .into()
      
    }

}
///serial group 布局,
///将同一个布局集中在一个函数中,
///这是一种模块化编程
fn ser_group<'a>(_app:&Counter)-> Column<'a,Message>{
    column![
        row![
            text("端口:").size(16), 
            pick_list(&Baudrate::PORT[..],_app.selected_port,Message::Selected_port)
                .placeholder("port")
                .width(100),
            button("获取端口").on_press(Message::Showtext)
        ].spacing(10),
        row![
        text("波特率:").size(16), 
        pick_list(&Baudrate::BAUD[..],_app.selected_baudrate,Message::Selected_baud)
        .placeholder("baudrate")
        .width(100)
        ].spacing(10),
        row![
        text("数据位:").size(16), 
        pick_list(&Baudrate::DATABIT[..],_app.selected_databit,Message::Selected_databit)
        .placeholder("databit")
        .width(100)
        ].spacing(10),
        row![
            text("校验位:").size(16), 
            pick_list(&Baudrate::PABIT[..],_app.selected_pabit,Message::Selected_pabit)
            .placeholder("paritybit") 
            .width(100)
        ].spacing(10),
        row![
            text("停止位:").size(16), 
            pick_list(&Baudrate::STOPBIT[..],_app.selected_stopbit,Message::Selected_stopbit)
            .placeholder("stopbit") 
            .width(100)
        ].spacing(10),
        row![
            button(text("连接").horizontal_alignment(alignment::Horizontal::Center)
            .vertical_alignment(alignment::Vertical::Center))
            .width(80).height(40)
            .on_press(Message::Showtext),
            button(text("断开").horizontal_alignment(alignment::Horizontal::Center)
            .vertical_alignment(alignment::Vertical::Center))
            .width(80).height(40)
            .on_press(Message::Showtext)
            
        ].spacing(10),
                                        
    ]
    .spacing(16)
    .padding(16)
    .align_items(Alignment::Center)
    .into()

}

///自定义按钮样式,用于菜单栏使用
struct ButtonStyle;
//让ButtonStyle实现button的StyleSheet功能
impl button::StyleSheet for ButtonStyle {
    type Style = iced::Theme;

    //生成按钮的激活外观
    fn active(&self, style: &Self::Style) -> button::Appearance {
        button::Appearance {
            text_color: style.extended_palette().background.base.text,
            border_radius: [2.0; 4].into(),
            background: Some(Color::TRANSPARENT.into()),
            ..Default::default()
        }
    }

    //生成按钮的悬停外观
    fn hovered(&self, style: &Self::Style) -> button::Appearance {
        let plt = style.extended_palette();

        button::Appearance {
            background: Some(plt.primary.weak.color.into()),
            text_color: plt.primary.weak.text,
            border_radius:[6.0; 4].into(),                      //border_radius:四角倒圆半径
            ..self.active(style)
        }
    }
}

//基础按钮
fn base_button<'a>(
    content: impl Into<Element<'a, Message, iced::Renderer>>,
    msg: Message,
) -> button::Button<'a, Message, iced::Renderer> {
    button(content)
        .padding([4, 8])
        .style(iced::theme::Button::Custom(Box::new(ButtonStyle {})))
        .on_press(msg)
}
//带标签按钮
fn labeled_button<'a>(label: &str, msg: Message) -> button::Button<'a, Message, iced::Renderer> {
    base_button(
        text(label)
            .width(Length::Fill)
            .height(Length::Fill)
            .vertical_alignment(alignment::Vertical::Center),
        msg,
    )
}

//测试按钮
fn debug_button<'a>(label: &str) -> button::Button<'a, Message, iced::Renderer> {
    labeled_button(label, Message::InputChanged(label.into()))
}

//调试item
fn debug_item<'a>(label: &str) -> MenuTree<'a, Message, iced::Renderer> {
    menu_tree!(debug_button(label).width(Length::Fill).height(Length::Fill))
}

//定义子菜单样式,附加有箭头图标
fn sub_menu<'a>(
    label: &str,
    msg: Message,
    children: Vec<MenuTree<'a, Message, iced::Renderer>>,
) -> MenuTree<'a, Message, iced::Renderer> {
    let handle = svg::Handle::from_path("../iced_test/img/caret-right-fill.svg");
    let arrow = svg(handle)
        .width(Length::Shrink)
        .style(theme::Svg::custom_fn(|theme| svg::Appearance {
            color: Some(theme.extended_palette().background.base.text),
        }));

    menu_tree(
        base_button(
            row![
                text(label)
                    .width(Length::Fill)
                    .height(Length::Fill)
                    .vertical_alignment(alignment::Vertical::Center),
                arrow
            ]
            .align_items(iced::Alignment::Center),
            msg,
        )
        .width(Length::Fill)
        .height(Length::Fill),
        children,
    )
}


fn debug_sub_menu<'a>(
    label: &str,
    children: Vec<MenuTree<'a, Message, iced::Renderer>>,
) -> MenuTree<'a, Message, iced::Renderer> {
    sub_menu(label, Message::InputChanged(label.into()), children)
    //menu_tree!(debug_button(label).width(Length::Fill).height(Length::Fill))
}
fn menu_1<'a>(_app: &Counter) -> MenuTree<'a, Message, iced::Renderer> {

    let sub_1 = debug_sub_menu(
        "A sub menu",
        vec![
            debug_item("Item"),
            debug_item("Item"),
            //sub_2,
            debug_item("Item"),
            debug_item("Item"),
            debug_item("Item"),
        ],
    )
    .width(220);

    let root = menu_tree(
        debug_button("文件"),
        vec![
            debug_item("新建"),
            debug_item("打开文件"),
            sub_1,
            debug_item("打开文件夹"),
            debug_item("保存"),
            debug_item("关闭"),
        ],
    )
    .width(110);

    root
}
fn menu_2<'a>(_app: &Counter) -> MenuTree<'a, Message, iced::Renderer> {
    let sub_1 = debug_sub_menu(
        "A sub menu",
        vec![
            debug_item("Item"),
            debug_item("Item"),
            //sub_2,
            debug_item("Item"),
            debug_item("Item"),
            debug_item("Item"),
        ],
    )
    .width(220);

    let root = menu_tree(
        debug_button("通讯"),
        vec![
            debug_item("设置参数"),
            debug_item("连接"),
            sub_1,
            debug_item("断开"),
            debug_item("Item"),
            debug_item("Item"),
        ],
    )
    .width(110);

    root
}
//fn menu_3<'a>(_app: &Counter) -> MenuTree<'a, Message, iced::Renderer> {}
//fn menu_4<'a>(_app: &Counter) -> MenuTree<'a, Message, iced::Renderer> {}

///一个菜单的group
/// 
/// 
fn menu_group<'a>(label:&str,_app:&Counter)->MenuTree<'a,Message,iced::Renderer>{
    menu_tree(
        debug_button(label),
        vec![
            debug_item("关于"),
        ]
    )
}
///简单的菜单调用
fn menu_simple<'a>(label:&str,_app:&Counter)->MenuTree<'a,Message,iced::Renderer>{
    
    menu_tree( button("haha")
    .padding([4, 8])
    .style(iced::theme::Button::Custom(Box::new(ButtonStyle {})))
    .on_press(Message::InputChanged(label.into()))
        , vec![
            //debug_item("label"),
            menu_tree!(text("haha"))
        ]
        )
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum Baudrate{
    //port
    PortCOM0,
    //baudrate
    Rate9600,
    #[default]
    Rate19200,
    Rate38400,
    Rate57600,
    Rate115200,
    //databit
    Databit8,
    Databit7,
    Databit6,
    Databit5,
    //paritybit
    Pabitnone,
    Pabiteven,
    Pabitodd,
    Pabitspace,
    Pabitmark,
    //stopbit
    Stopbit1,
    Stopbit1dot5,
    Stopbit2,
}
impl Baudrate {
    const PORT:[Baudrate;1]=[
        Baudrate::PortCOM0,
    ];
    const BAUD: [Baudrate; 5] = [
        Baudrate::Rate9600,
        Baudrate::Rate19200,
        Baudrate::Rate38400,
        Baudrate::Rate57600,
        Baudrate::Rate115200,
    ];
    const DATABIT:[Baudrate;4]=[
        Baudrate::Databit8,
        Baudrate::Databit7,
        Baudrate::Databit6,
        Baudrate::Databit5,

    ];
    const PABIT:[Baudrate;5]=[
        Baudrate::Pabitnone,
        Baudrate::Pabiteven,
        Baudrate::Pabitodd,
        Baudrate::Pabitspace,
        Baudrate::Pabitmark,
    ];
    const STOPBIT:[Baudrate;3]=[
        Baudrate::Stopbit1,
        Baudrate::Stopbit1dot5,
        Baudrate::Stopbit2,
    ];

    fn hello(&self) -> &str {
        match self {

            Baudrate::PortCOM0=>"COM0",

            Baudrate::Rate9600 => "9600",
            Baudrate::Rate19200 => "9600",
            Baudrate::Rate38400=> "9600",
            Baudrate::Rate57600 => "9600",
            Baudrate::Rate115200 => "9600",
        
            Baudrate::Databit8=>"8",
            Baudrate::Databit7=>"7",
            Baudrate::Databit6=>"6",
            Baudrate::Databit5=>"5",

            Baudrate::Pabitnone=>"None",
            Baudrate::Pabiteven=>"Even",
            Baudrate::Pabitodd=>"Odd",
            Baudrate::Pabitspace=>"Space",
            Baudrate::Pabitmark=>"Mark",

            Baudrate::Stopbit1=>"1",
            Baudrate::Stopbit1dot5=>"1.5",
            Baudrate::Stopbit2=>"2",

        }
    }
}
impl std::fmt::Display for Baudrate {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "{}",
            match self {

                Baudrate::PortCOM0=>"COM0",

                Baudrate::Rate9600 => "9600",
                Baudrate::Rate19200 => "19200",
                Baudrate::Rate38400 => "38400",
                Baudrate::Rate57600 => "57600",
                Baudrate::Rate115200=> "115200",
             
                Baudrate::Databit8=>"8",
                Baudrate::Databit7=>"7",
                Baudrate::Databit6=>"6",
                Baudrate::Databit5=>"5",

                Baudrate::Pabitnone=>"None",
                Baudrate::Pabiteven=>"Even",
                Baudrate::Pabitodd=>"Odd",
                Baudrate::Pabitspace=>"Space",
                Baudrate::Pabitmark=>"Mark",

                Baudrate::Stopbit1=>"1",
                Baudrate::Stopbit1dot5=>"1.5",
                Baudrate::Stopbit2=>"2",
            }
        )
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1265069.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Doris_Doris导入常见问题

Doris数据导入错误 &#xff1a;the length of input is too larger than schema 可能原因&#xff1a;varchar长度设置过短 Doris表字段乱序 导入palo表中的csv本身无schema信息&#xff0c;csv与palo表字段顺序必须一致&#xff0c;否则会错乱 Doris数据文件中字段比表字段…

linux文件管理命令_切换创建复制移动删除查看修改

1.3 文件管理命令 1.3.1 cd&#xff1a;切换目录&#xff08;change directory&#xff09; cd 绝对路径/相对路径 # 根目录 [rootlocalhost ~]# cd / # 家目录 [rootlocalhost /]# cd [rootlocalhost /]# cd ~ # 父级目录 [rootlocalhost /]# cd .. # 返回上一次目录 [roo…

【vue】v-model在表单元素上的应用

表单元素&#xff1a; https://blog.csdn.net/m0_67930426/article/details/134655644 使用模板 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Title</title> </head><body>&l…

订单管理系统怎么用?有哪些好用的订单管理系统?

订单管理系统怎么用&#xff1f;有哪些好用的订单管理系统&#xff1f;阅读本文你将了解&#xff1a;1、订单管理系统的核心功能&#xff1b;2、订单管理系统的拓展功能&#xff1b;3、订单管理系统推荐。 订单管理系统在当今商业环境中扮演着至关重要的角色。它是企业内部运营…

Flink-执行拓扑图与作业调度

算子与作业提交 一、Flink执行模式1.流执行模式2.批执行模式 二、Flink拓扑图1.基本概念2.拓扑图生成过程 三、拓扑生成和优化1.应用程序2.逻辑视图3.算子链4.Task Slots 四、作业调度1.调度2.拓扑图数据结构3.Job状态转化4.Task状态转化 总结参考链接 一、Flink执行模式 Flin…

文章解读与仿真程序复现思路——电力系统保护与控制EI\CSCD\北大核心《基于深度强化学习的城市配电网多级动态重构优化运行方法》

这个标题涉及到城市配电网&#xff08;Urban Power Distribution Network&#xff09;的优化运行方法&#xff0c;其中使用了深度强化学习&#xff08;Deep Reinforcement Learning&#xff09;技术&#xff0c;并且特别强调了多级动态重构。 解读每个关键部分&#xff1a; 基…

Docker 概述与安装

文章目录 1. Docker简介2. 传统虚拟机和容器3. Docker运行速度快的原因4. Docker软件4.1 Docker镜像4.2 Docker容器4.3 Docker仓库 5. Docker架构6. CentOS安装Docker6.1 卸载旧版本6.2 配置yum资源库6.3 安装Docker引擎6.4 启动docker引擎6.5 设置开机自启 7. 卸载Docker8. 运…

【C++初阶】五、类和对象(日期类的完善、流运算符重载函数、const成员、“”取地址运算符重载)

相关代码gitee自取&#xff1a; C语言学习日记: 加油努力 (gitee.com) 接上期&#xff1a; 【C初阶】四、类和对象 &#xff08;构造函数、析构函数、拷贝构造函数、赋值运算符重载函数&#xff09;-CSDN博客 一 . 日期类的完善 此次日期类的成员函数&#xff0c;采用声明…

Flink Flink中的合流

一、Flink中的基本合流操作 在实际应用中&#xff0c;我们经常会遇到来源不同的多条流&#xff0c;需要将它们的数据进行联合处理。所以 Flink 中合流的操作会更加普遍&#xff0c;对应的 API 也更加丰富。 二、联合&#xff08;Union&#xff09; 最简单的合流操作&#xf…

EZDML基本介绍

一、表结构设计器(EZDML) 这是一个数据库建表的小软件&#xff0c;可快速的进行数据库表结构设计&#xff0c;建立数据模型。类似大家常用的数据库建模工具如PowerDesigner、ERWIN、ER-Studio和Rational-Rose等的超级精简版。 官方下载地址&#xff1a;http://www.ezdml.com/d…

解析javascript数组方法 find 和 filter 有何区别

首先用一个案例可以很直观的看到 find 和 filter 的区别&#xff1b; 相同点&#xff1a; 两者分别可以接受三个参数&#xff1a;当前元素、当前索引、整个数组&#xff1b;两者都可以用来查找数组中符合条件的元素&#xff1b; 不同点&#xff1a; find&#xff1a; 用于查…

docker镜像管理命令

镜像管理命令 docker build : 命令用于使用 Dockerfile 创建镜像 docker build [OPTIONS] PATH | URL | - OPTIONS说明&#xff1a; --add-host :向hosts文件中添加自定义 host:ip 映射 --build-arg[] :设置镜像创建时的变量&#xff1b; --cache-from :指定镜像用作当前构建…

华为ospf和isis双点双向路由重分布的次优路径和环路终极解决方案

r5上直接导入直连路由 r3和r2进行双点双向路由重分布 查看R3去往R5产生了次优路径&#xff1a; 因为是R2先互相引入的isis和ospf&#xff0c;所以R3会产生次优路径&#xff0c;如果是R3先相互引入ospf和isis&#xff0c;那就是R2去R5会产生次优路径&#xff0c;而R3本身不会。…

华为设备使用python实现文件自动保存下载

实验目的&#xff1a; 公司有一台CE12800的设备&#xff0c;管理地址为172.16.1.2&#xff0c;现在需要编写自动化脚本&#xff0c;STELNET实现设备的自动保存配置文件&#xff0c;使用SFTP实现设备的文件下载。 实验拓扑&#xff1a; 实验步骤&#xff1a; 步骤1&#xff1…

Spark---资源、任务调度

一、Spark资源调度源码 1、Spark资源调度源码过程 Spark资源调度源码是在Driver启动之后注册Application完成后开始的。Spark资源调度主要就是Spark集群如何给当前提交的Spark application在Worker资源节点上划分资源。Spark资源调度源码在Master.scala类中的schedule()中进行…

揭开 BFC 的神秘面纱:前端开发必知必会

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

【多线程】-- 05 Lambda表达式

多线程 4 Lambda表达式 λ是希腊字母表中排序第十一位的字母&#xff0c;英语名称为Lambda是为了避免匿名内部类定义过多实质属于函数式编程的概念 为什么要使用Lambda表达式&#xff1f; 避免匿名内部类定义过多可以让代码看起来很简洁去掉了一堆没有意义的代码&#xff0…

【LeetCode】128. 最长连续序列——哈希的应用(3)

文章目录 1、思路2、解题方法3、复杂度时间复杂度:空间复杂度: 4、Code Problem: 128. 最长连续序列 1、思路 我会用一种做题者的思路来去看待这道题。 我们在乍一看到这道题的时候&#xff0c;看到它的时间复杂度要求为O(N)&#xff0c;然后又要求去找序列(就是让你判断这个…

高频Latex公式速查表,写论文技术博客不愁了

常见上下标X_{2}X^{2}\hat{X}\bar{X}\frac{1}{X}常见希腊字母\alpha \beta \gamma \delta \varepsilon \eta \theta \rho \sigma \phi \varphi \omega常见数学符号\leq \geq \neq\approx 其他\sum \prod \int \bigoplus \forall \exists \times \setminus \bigotimes \bigodot …

五分钟 k8s 实战-应用探针

Probe.png 今天进入 kubernetes 的运维部分&#xff08;并不是运维 kubernetes&#xff0c;而是运维应用&#xff09;&#xff0c;其实日常我们大部分使用 kubernetes 的功能就是以往运维的工作&#xff0c;现在云原生将运维和研发关系变得更紧密了。 今天主要讲解 Probe 探针相…