Rust UI开发(四):iced中如何添加菜单栏(串口调试助手)
注:此文适合于对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{//portPortCOM0,//baudrateRate9600,#[default]Rate19200,Rate38400,Rate57600,Rate115200,//databitDatabit8,Databit7,Databit6,Databit5,//paritybitPabitnone,Pabiteven,Pabitodd,Pabitspace,Pabitmark,//stopbitStopbit1,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",})}
}
相关文章:

Rust UI开发(四):iced中如何添加菜单栏(串口调试助手)
注:此文适合于对rust有一些了解的朋友 iced是一个跨平台的GUI库,用于为rust语言程序构建UI界面。 这是一个系列博文,本文是第四篇,前三篇链接: 1、Rust UI开发(一):使用iced构建UI时…...

P19 C++ 构造函数的成员初始化列表
目录 前言 01 如果不用成员列表如何初始化变量 02 成员列表初始化 03 为什么要使用成员列表初始化呢? 04 案例代码 前言 本期我们聊聊构造函数初始化列表。 你应该经常使用成员初始化列表,如果你不喜欢这种代码风格,建议你还是慢慢习惯吧…...
acwing算法基础之数学知识--Nim游戏和集合Nim游戏
目录 1 基础知识2 模板3 工程化 1 基础知识 (一) Nim游戏: n n n堆物品,每堆有 a i a_i ai个,两个玩家轮流取走任意一堆的任意个物品,但不能不取。取走最后一个物品的人获胜。 结论:如果这n…...

大数据Doris(二十八):Routine Load查看和修改作业
文章目录 Routine Load查看和修改作业 一、查看导入作业状态...

顺序表总结
📑打牌 : da pai ge的个人主页 🌤️个人专栏 : da pai ge的博客专栏 ☁️宝剑锋从磨砺出,梅花香自苦寒来 目录 🌤️arraylist的简…...

flutter 文本不随系统设置而改变大小[最全的整理]
文本不随系统设置而改变大小[四] 前言方案十九:使用LayoutBuilder和RichText方案二十:使用Transform.scale方案二十一:使用自定义文本缩放因子方案二十二:使用SingleChildScrollView方案二十三:使用FittedBox方案二十四…...

python -opencv 图像锐化
python -opencv 图像锐化 图像锐化其实,是一种增强图片对比度的技术,我们可以通过计算图像的导数,把导数绝对值数值大于零的数值加回原图像,通过这种方法,可以增强图像的对比度。 实现代码如下: import c…...

数字电源为什么一般用DSP控制,而不能用普通的单片机?
数字电源为什么一般用DSP控制,而不能用普通的单片机? 首先你要清楚,数字电源需要一个芯片具备什么功能? 1 能发PWM波 ,并且具备保护关断功能; 电源对PWM发波 要求很高,精度要ns级甚至ps级的&…...

个人投资白银收益怎么样?
个人投资白银是可以带来丰厚的收益,但收益的具体情况取决于多种因素。以下是一些明确的答案和举例,帮助投资者更好地理解个人投资白银的收益情况。 白银市场的价格波动是决定投资收益的主要因素之一,白银价格受全球经济形势、地缘局势风险、…...

代码随想录算法训练营 ---第四十五天
前言: 昨天的题做过之后,今天的题基本上都很简单,但是要注重一下细节。 第一题: 简介: 动态规划五部曲: 1.确定dp数组的含义 dp[i]:爬到有i个台阶的楼顶,有dp[i]种方法 2.确定dp…...

【密码学】【多方安全计算】不经意传输(Oblivious Transfer,OT)
文章目录 不经意传输(oblivious transfer)定义不经意传输的实例(1 out 2,二选一不经意传输)基于RSA的1 out 2 不经意传输疑问 不经意传输(oblivious transfer)定义 不经意传输(obli…...
STL常用算法-C++
概述: 算法主要是由头文件 <algorithm> <functional> <numeric> 组成。<algorithm> 是所有 STL 头文件中最大的一个,范围涉及是比较、交换、查找、遍历操作、复制、修改等等。<functional> 定义了一些模板类,…...

一、Lua基础
文章目录 一、Lua是什么二、Lua特性(一)轻量级(二)可扩展(三)其它特性 三、Lua安装四、Lua应用 看到评论说,C让我见识了语言的严谨与缜密,lua让我见识到了语言的精巧与创新ÿ…...
vue3 webSocket 封装及使用
vue3 webSocket 封装及使用 封装 import { ref, onUnmounted } from vue; interface SocketOptions {heartbeatInterval?: number;reconnectInterval?: number;maxReconnectAttempts?: number; }class Socket {url: string;ws: WebSocket | null null;opts: SocketOption…...
记录vscode常用插件集合(extensions)
名称用处Chinese (Simplified) (简体中文) Language Pack for Visual Studio Code适用于 VS Code 的中文(简体)语言包Dev ContainersVisual Studio代码开发容器ES7 React/Redux/GraphQL/React-Native snippetsES7 React/Redux/GraphQL/Rect Native代码段…...
正则表达式详解
一、正则表达式概述 正则表达式是一组由字母和符号组成的特殊文本,它可以用来从文本中找出满足你想要的格式的句子。通俗的讲就是按照某种规则去匹配符合条件的字符串 一个正则表达式是一种从左到右匹配主体字符串的模式。 “Regular expression”这个词比较拗口&a…...
【限时免费】20天拿下华为OD笔试之【双指针】2023Q1A-两数之和绝对值最小【欧弟算法】全网注释最详细分类最全的华为OD真题题解
文章目录 题目描述与示例题目描述输入输出示例一输入输出说明 解题思路代码解法一pythonjavacpp 解法二pythonjavacpp 时空复杂度 华为OD算法/大厂面试高频题算法练习冲刺训练 题目描述与示例 题目描述 给定一个整数数组nums,请你在该数组中找出两个数,…...
expect脚本在自动化部署中的具体应用案例
#expect脚本在自动化部署中的具体应用 expect脚本是一个非常好的交互式应用脚本,在自动化部署中,可以使用这个脚本来实现全自动的自动化部署。下面是一些具体的应用案例。 场景一:自动安装mysql 可以使用expect脚本来实现mysql自动安装&…...

【Java+SQL Server】前后端连接小白教程
目录 📋 流程总览 ⛳️【SQL Server】数据库操作 1. 新建数据库text 2. 新建表 3. 编辑表 ⛳️【IntelliJ IDEA】操作 1. 导入jar包 2. 运行显示错误 📋 流程总览 ⛳️【SQL Server】数据库操作 打开SQL Server数据库-->sa登录-->新建数据库…...

Xilinx Zynq-7000系列FPGA多路视频处理:图像缩放+视频拼接显示,提供工程源码和技术支持
目录 1、前言免责声明 2、相关方案推荐FPGA图像处理方案FPGA图像缩放方案FPGA视频拼接叠加融合方案推荐 3、设计思路详解HLS 图像缩放介绍Video Mixer介绍 4、vivado工程介绍PL 端 FPGA 逻辑设计PS 端 SDK 软件设计 5、工程移植说明vivado版本不一致处理FPGA型号不一致处理其他…...

日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻
在如今就业市场竞争日益激烈的背景下,越来越多的求职者将目光投向了日本及中日双语岗位。但是,一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧?面对生疏的日语交流环境,即便提前恶补了…...
设计模式和设计原则回顾
设计模式和设计原则回顾 23种设计模式是设计原则的完美体现,设计原则设计原则是设计模式的理论基石, 设计模式 在经典的设计模式分类中(如《设计模式:可复用面向对象软件的基础》一书中),总共有23种设计模式,分为三大类: 一、创建型模式(5种) 1. 单例模式(Sing…...

DAY 47
三、通道注意力 3.1 通道注意力的定义 # 新增:通道注意力模块(SE模块) class ChannelAttention(nn.Module):"""通道注意力模块(Squeeze-and-Excitation)"""def __init__(self, in_channels, reduction_rat…...

为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?
在建筑行业,项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升,传统的管理模式已经难以满足现代工程的需求。过去,许多企业依赖手工记录、口头沟通和分散的信息管理,导致效率低下、成本失控、风险频发。例如&#…...

EtherNet/IP转DeviceNet协议网关详解
一,设备主要功能 疆鸿智能JH-DVN-EIP本产品是自主研发的一款EtherNet/IP从站功能的通讯网关。该产品主要功能是连接DeviceNet总线和EtherNet/IP网络,本网关连接到EtherNet/IP总线中做为从站使用,连接到DeviceNet总线中做为从站使用。 在自动…...

【OSG学习笔记】Day 16: 骨骼动画与蒙皮(osgAnimation)
骨骼动画基础 骨骼动画是 3D 计算机图形中常用的技术,它通过以下两个主要组件实现角色动画。 骨骼系统 (Skeleton):由层级结构的骨头组成,类似于人体骨骼蒙皮 (Mesh Skinning):将模型网格顶点绑定到骨骼上,使骨骼移动…...

ios苹果系统,js 滑动屏幕、锚定无效
现象:window.addEventListener监听touch无效,划不动屏幕,但是代码逻辑都有执行到。 scrollIntoView也无效。 原因:这是因为 iOS 的触摸事件处理机制和 touch-action: none 的设置有关。ios有太多得交互动作,从而会影响…...
Device Mapper 机制
Device Mapper 机制详解 Device Mapper(简称 DM)是 Linux 内核中的一套通用块设备映射框架,为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程,并配以详细的…...
IP如何挑?2025年海外专线IP如何购买?
你花了时间和预算买了IP,结果IP质量不佳,项目效率低下不说,还可能带来莫名的网络问题,是不是太闹心了?尤其是在面对海外专线IP时,到底怎么才能买到适合自己的呢?所以,挑IP绝对是个技…...

使用SSE解决获取状态不一致问题
使用SSE解决获取状态不一致问题 1. 问题描述2. SSE介绍2.1 SSE 的工作原理2.2 SSE 的事件格式规范2.3 SSE与其他技术对比2.4 SSE 的优缺点 3. 实战代码 1. 问题描述 目前做的一个功能是上传多个文件,这个上传文件是整体功能的一部分,文件在上传的过程中…...