如何实现手机遥控端关机按钮同时关闭TV端和手机端界面

目前家庭电视机主要通过其自带的遥控器进行操控,实现的功能较为单一。例如,当我们要在TV端搜索节目时,电视机在遥控器的操控下往往只能完成一些字母或数字的输入,而无法输入其他复杂的内容。分布式遥控器将手机的输入能力和电视遥控器的遥控能力结合为一体,从而快速便捷操控电视。

分布式遥控器的实现基于OpenHarmony的分布式能力和RPC通信能力,UI使用eTS进行开发。如下图所示,分别用两块开发板模拟TV端和手机端。

  1. 分布式组网后可以通过TV端界面的Controller按钮手动拉起手机端的遥控界面,在手机端输入时会将输入的内容同步显示在TV端搜索框,点击搜索按钮会根据输入的内容搜索相关节目。
  2. 还可以通过点击方向键(上下左右)将焦点移动到我们想要的节目上,再点击播放按钮进行播放,按返回按钮返回TV端主界面。
  3. 同时还可以通过手机遥控端关机按钮同时关闭TV端和手机端界面。

UI效果图如下:

图1 TV端主页默认页面

图2 手机端遥控页面

  • 图3 TV端视频播放页面

说明: 本示例涉及使用系统接口,需要手动替换Full SDK才能编译通过

2.搭建OpenHarmony环境

完成本篇Codelab我们首先要完成开发环境的搭建,本示例以RK3568开发板为例,参照以下步骤进行:

  1. 获取OpenHarmony系统版本:标准系统解决方案(二进制)。

      以3.1版本为例:

2.搭建烧录环境。

    1. 完成DevEco Device Tool的安装
    2. 完成RK3568开发板的烧录

3.搭建开发环境。

    1. 开始前请参考工具准备,完成DevEco Studio的安装和开发环境配置。
    2. 开发环境配置完成后,请参考使用工程向导创建工程(模板选择“Empty Ability”),选择JS或者eTS语言开发。
    3. 工程创建完成后,选择使用真机进行调测。

3.分布式组网

本章节以系统自带的音乐播放器为例(具体以实际的应用为准),介绍如何完成两台设备的分布式组网。

  1. 硬件准备:准备两台烧录相同的版本系统的RK3568开发板A、B。
  2. 开发板A、B连接同一个WiFi网络。

      打开设置-->WLAN-->点击右侧WiFi开关-->点击目标WiFi并输入密码。

3.将设备A,B设置为互相信任的设备。

  • 找到系统应用“音乐”。

  • 设备A打开音乐,点击左下角流转按钮,弹出列表框,在列表中会展示远端设备的id。选择远端设备B的id,另一台开发板(设备B)会弹出验证的选项框。

  • 设备B点击允许,设备B将会弹出随机PIN码,将设备B的PIN码输入到设备A的PIN码填入框中。

  1. 配网完毕。

4.代码结构解读

本篇Codelab只对核心代码进行讲解,首先来介绍下整个工程的代码结构:

  • MainAbility:
    • model:数据模型。
      • RemoteDeviceModel.ets:获取组网内的设备列表模型。
      • PicData.ets:图片信息数据。
      • PicDataModel.ets:图片信息模型。
      • ConnectModel.ets:连接远端Service和发送消息模型。
    • pages:存放TV端各个页面。
      • TVindex.ets:TV端主页面。
      • VideoPlay.ets:TV端视频播放页面。
  • PhoneAbility:存放应用手机控制端主页面。
    • pages/PhoneIndex.ets:手机控制端主页面。
  • ServiceAbility:存放ServiceAbility相关文件。
    • service.ts:service服务,用于跨设备连接后通讯。
  • resources :存放工程使用到的资源文件。
    • resources/rawfile:存放工程中使用的图片资源文件。
  • config.json:配置文件。

5.实现TV端界面

在本章节中,您将学会开发TV端默认界面和TV端视频播放界面,示意图参考第一章图1和图3所示。

建立数据模型,将图片ID、图片源、图片名称和视频源绑定成一个数据模型。详情代码可以查看MainAbility/model/PicData.ets和MainAbility/model/PicDataModel.ets两个文件。

  1. 实现TV端默认页面布局和样式。
  • 在MainAbility/pages/TVIndex.ets 主界面文件中添加入口组件。页面布局代码如下:
// 入口组件
@Entry
@Component
struct Index {private letters: string[] = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9']private source: string@State text: string = ''@State choose: number = -1build() {Flex({ direction: FlexDirection.Column }) {TextInput({text: this.text, placeholder: 'Search' }).onChange((value: string) => {this.text = value})Row({space: 30}) {Text('Clear').fontSize(16).backgroundColor('#ABB0BA').textAlign(TextAlign.Center).onClick(() => {this.text = ''}).clip(true).borderRadius(10)Text('Backspace').fontSize(16).backgroundColor('#ABB0BA').textAlign(TextAlign.Center).onClick(() => {this.text = this.text.substring(0, this.text.length - 1)}).clip(true).borderRadius(10)Text('Controller').fontSize(16).backgroundColor('#ABB0BA').textAlign(TextAlign.Center).onClick(() => {......}).clip(true).borderRadius(10)}Grid() {ForEach(this.letters, (item) => {GridItem() {Text(item).fontSize(20).backgroundColor('#FFFFFF').textAlign(TextAlign.Center).onClick(() => {this.text += item}).clip(true).borderRadius(5)}}, item => item)}.rowsTemplate('1fr 1fr 1fr 1fr').columnsTemplate('1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr').columnsGap(8).rowsGap(8).width('75%').height('25%').margin(5).backgroundColor('#D2D3D8').clip(true).borderRadius(10)Grid() {ForEach(this.picItems, (item: PicData) => {GridItem() {PicGridItem({ picItem: item })}}, (item: PicData) => item.id.toString())}.rowsTemplate('1fr 1fr 1fr').columnsTemplate('1fr 1fr').columnsGap(5).rowsGap(8).width('90%').height('58%').backgroundColor('#FFFFFF').margin(5)}.width('98%').backgroundColor('#FFFFFF')}
}
  • 其中PicGridItem将PicItem的图片源和图片名称绑定,实现代码如下:
// 九宮格拼图组件
@Component
struct PicGridItem {private picItem: PicDatabuild() {Column() {Image(this.picItem.image).objectFit(ImageFit.Contain).height('85%').width('100%').onClick(() => {......})})Text(this.picItem.name).fontSize(20).fontColor('#000000')}.height('100%').width('90%')}
}

2.实现TV端视频播放界面。

  • 在MainAbility/pages/VideoPlay.ets 文件中添加组件。页面布局代码如下:
import router from '@system.router'
@Entry
@Component
struct Play {
// 取到Index页面跳转来时携带的source对应的数据。private source: string = router.getParams().sourcebuild() {Column() {Video({src: this.source,}).width('100%').height('100%').autoPlay(true).controls(true)}}
}
  • 在MainAbility/pages/TVIndex.ets中,给PicGridItem的图片添加点击事件,点击图片即可播放PicItem的视频源。实现代码如下:
Image(this.picItem.image).......onClick(() => {router.push({uri: 'pages/VideoPlay',params: { source: this.picItem.video }})})

6.实现手机遥控端界面

在本章节中,您将学会开发手机遥控端默认界面,示意图参考第一章图2所示。

  • PhoneAbility/pages/PhoneIndex.ets 主界面文件中添加入口组件。页面布局代码如下:
@Entry
@Component
struct Index {build() {Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center }) {Row() {Image($rawfile('TV.png')).width(25).height(25)Text('华为智慧屏').fontSize(20).margin(10)}// 文字搜索框TextInput({ placeholder: 'Search' }).margin(20).onChange((value: string) => {if (connectModel.mRemote){......}})Grid() {GridItem() {// 向上箭头Button({ type: ButtonType.Circle, stateEffect: true }) {Image($rawfile('up.png')).width(80).height(80)}.onClick(() => {......}).width(80).height(80).backgroundColor('#FFFFFF')}.columnStart(1).columnEnd(5)GridItem() {// 向左箭头Button({ type: ButtonType.Circle, stateEffect: true }) {Image($rawfile('left.png')).width(80).height(80)}.onClick(() => {......}).width(80).height(80).backgroundColor('#FFFFFF')}GridItem() {// 播放键Button({ type: ButtonType.Circle, stateEffect: true }) {Image($rawfile('play.png')).width(60).height(60)}.onClick(() => {......}).width(80).height(80).backgroundColor('#FFFFFF')}GridItem() {// 向右箭头Button({ type: ButtonType.Circle, stateEffect: true }) {Image($rawfile('right.png')).width(70).height(70)}.onClick(() => {......}).width(80).height(80).backgroundColor('#FFFFFF')}GridItem() {// 向下箭头Button({ type: ButtonType.Circle, stateEffect: true }) {Image($rawfile('down.png')).width(70).height(70)}.onClick(() => {......}).width(80).height(80).backgroundColor('#FFFFFF')}.columnStart(1).columnEnd(5)}.rowsTemplate('1fr 1fr 1fr').columnsTemplate('1fr 1fr 1fr').backgroundColor('#FFFFFF').margin(10).clip(new Circle({ width: 325, height: 325 })).width(350).height(350)Row({ space:100 }) {// 返回键Button({ type: ButtonType.Circle, stateEffect: true }) {Image($rawfile('return.png')).width(40).height(40)}.onClick(() => {......}).width(100).height(100).backgroundColor('#FFFFFF')// 关机键Button({ type: ButtonType.Circle, stateEffect: true }) {Image($rawfile('off.png')).width(40).height(40)}.onClick(() => {......}).width(100).height(100).backgroundColor('#FFFFFF')// 搜索键Button({ type: ButtonType.Circle, stateEffect: true }) {Image($rawfile('search.png')).width(40).height(40)}.onClick(() => {......}).width(100).height(100).backgroundColor('#FFFFFF')}.padding({ left:100 })}.backgroundColor('#E3E3E3')}
}

7.实现分布式拉起和RPC通信

在本章节中,您将学会如何拉起在同一组网内的设备上的FA,并且连接远端Service服务。

  1. 首先通过TV端拉起手机端界面,并将本端的deviceId发送到手机端。
  • 点击TV端主页上的"Controller"按钮,增加.onClick()事件。调用RegisterDeviceListCallback()发现设备列表,并弹出设备列表选择框CustomDialogExample,选择设备后拉起远端FA。CustomDialogExample()代码如下:
// 设备列表弹出框
@CustomDialog
struct CustomDialogExample {@State editFlag: boolean = falsecontroller: CustomDialogControllercancel: () => voidconfirm: () => voidbuild() {Column() {List({ space: 10, initialIndex: 0 }) {ForEach(DeviceIdList, (item) => {ListItem() {Row() {Text(item).width('87%').height(50).fontSize(10).textAlign(TextAlign.Center).borderRadius(10).backgroundColor(0xFFFFFF).onClick(() => {onStartRemoteAbility(item);this.controller.close();})}}.editable(this.editFlag)}, item => item)}}.width('100%').height(200).backgroundColor(0xDCDCDC).padding({ top: 5 })}
}
  • 点击设备弹出框内的Text组件会调用onStartRemoteAbility()方法拉起远端FA(手机端),将TV端的deviceId传给手机端,并连接手机端的Service。因此在featureAbility.startAbility()成功的回调中也要调用onConnectRemoteService()方法。这里将连接远端Service和发送消息抽象为ConnectModel,详细代码可查看MainAbility/model/ConnectModel.ets文件中onConnectRemoteService()方法。onStartRemoteAbility()方法的代码如下:
function onStartRemoteAbility(deviceId) {AuthDevice(deviceId);let numDevices = remoteDeviceModel.deviceList.length;if (numDevices === 0) {prompt.showToast({message: "onStartRemoteAbility no device found"});return;}var params = {remoteDeviceId: localDeviceId}var wantValue = {bundleName: 'com.example.helloworld0218',abilityName: 'com.example.helloworld0218.PhoneAbility',deviceId: deviceId,parameters: params};featureAbility.startAbility({want: wantValue}).then((data) => {// 拉起远端后,连接远端serviceconnectModel.onConnectRemoteService(deviceId)});
}
  • 需要注意的是,配置文件config.json中ServiceAbility的属性visible要设置为true,代码如下:
"abilities": [...{"visible": true,"srcPath": "ServiceAbility","name": ".ServiceAbility","icon": "$media:icon","srcLanguage": "ets","description": "$string:description_serviceability","type": "service"}
],

2.成功拉起手机端界面后,通过接收TV端传过来的deviceId连接TV端的Service。在手机端的生命周期内增加aboutToAppear()事件,在界面被拉起的时候读取对方的deviceId并调用onConnectRemoteService()方法,连接对方的Service,实现代码如下:

async aboutToAppear() {await featureAbility.getWant((error, want) => {// 远端被拉起后,连接对端的serviceif (want.parameters.remoteDeviceId) {let remoteDeviceId = want.parameters.remoteDeviceIdconnectModel.onConnectRemoteService(remoteDeviceId)}});}

3.建立一个ServiceAbility处理收到的消息并发布公共事件,详细代码请看ServiceAbility/service.ts文件。TV端订阅本端Service的公共事件,并接受和处理消息。

  • 创建SubscribeEvent(),实现代码如下:
subscribeEvent() {let self = this;// 用于保存创建成功的订阅者对象,后续使用其完成订阅及退订的动作var subscriber;// 订阅者信息var subscribeInfo = {events: ["publish_change"],priority: 100};// 设置有序公共事件的结果代码回调function SetCodeCallBack() {}// 设置有序公共事件的结果数据回调function SetDataCallBack() {}// 完成本次有序公共事件处理回调function FinishCommonEventCallBack() {}// 订阅公共事件回调function SubscribeCallBack(err, data) {let msgData = data.data;let code = data.code;// 设置有序公共事件的结果代码subscriber.setCode(code, SetCodeCallBack);// 设置有序公共事件的结果数据subscriber.setData(msgData, SetDataCallBack);// 完成本次有序公共事件处理subscriber.finishCommonEvent(FinishCommonEventCallBack)// 处理接收到的数据data......// 创建订阅者回调function CreateSubscriberCallBack(err, data) {subscriber = data;// 订阅公共事件commonEvent.subscribe(subscriber, SubscribeCallBack);}// 创建订阅者commonEvent.createSubscriber(subscribeInfo, CreateSubscriberCallBack);}
}
  • 在TV端的生命周期内增加aboutToAppear()事件,订阅公共事件,实现代码如下:
async aboutToAppear() {this.subscribeEvent();}

4.成功连接远端Service服务后,在手机遥控器端进行按钮或者输入操作都会完成一次跨设备通讯,消息的传递是由手机遥控器端的FA传递到TV端的Service服务。这里将连接远端Service和发送消息抽象为ConnectModel,详细代码可查看MainAbility/model/ConnectModel.ets文件中sendMessageToRemoteService()方法。

8.设置遥控器远端事件

手机端应用对TV端能做出的控制有:向上移动、向下移动、向左移动、向右移动、确定、返回、关闭。在手机端按键上增加点击事件,通过sendMessageToRemoteService()的方法发送到TV端Service。TV端根据发送code以及数据,进行数据处理,这里只展示TV端数据处理部分的核心代码:

// code = 1时,将手机遥控端search框内数据同步到TV端
if (code == 1) {self.text = data.parameters.dataList;
}
// code = 2时,增加选中图片效果
if (code == 2) {// 如果在图片序号范围内就选中图片,否则不更改var tmp: number = +data.parameters.dataList;if ((self.choose + tmp <= 5) && (self.choose + tmp >= 0)) {self.choose += tmp;}
}
// code = 3时,播放选中图片对应的视频
if (code == 3) {self.picItems.forEach(function (item) {if (item.id == self.choose) {router.push({uri: 'pages/VideoPlay',params: { source: item.video }})}})
}
// code = 4时,回到TV端默认页面
if (code == 4) {router.push({uri: 'pages/TVIndex',})
}
// code = 5时,关闭程序
if (code == 5) {featureAbility.terminateSelf()
}
// code = 6时,搜索图片名称并增加选中特效
if (code == 6) {self.picItems.forEach(function (item) {if (item.name == self.text) {self.choose = Number(item.id)}})
}

为了帮助大家更深入有效的学习到鸿蒙开发知识点,小编特意给大家准备了几套最新版的HarmonyOS NEXT学习资源

获取完整版高清学习路线,请点击→《HarmonyOS教学视频

HarmonyOS教学视频

鸿蒙语法ArkTS、TypeScript、ArkUI等…视频教程

鸿蒙生态应用开发白皮书V2.0PDF:

获取白皮书:请点击→《鸿蒙生态应用开发白皮书V2.0PDF

在这里插入图片描述

鸿蒙 (Harmony OS)开发学习手册

一、入门必看

  1. 应用开发导读(ArkTS)
  2. .……

在这里插入图片描述


二、HarmonyOS 概念

  1. 系统定义
  2. 技术架构
  3. 技术特性
  4. 系统安全

在这里插入图片描述

三、如何快速入门?《做鸿蒙应用开发到底学习些啥?》

  1. 基本概念
  2. 构建第一个ArkTS应用
  3. .……

在这里插入图片描述


四、开发基础知识

  1. 应用基础知识
  2. 配置文件
  3. 应用数据管理
  4. 应用安全管理
  5. 应用隐私保护
  6. 三方应用调用管控机制
  7. 资源分类与访问
  8. 学习ArkTS语言
  9. .……

在这里插入图片描述


五、基于ArkTS 开发

  1. Ability开发
  2. UI开发
  3. 公共事件与通知
  4. 窗口管理
  5. 媒体
  6. 安全
  7. 7.网络与链接
  8. 电话服务
  9. 数据管理
  10. 后台任务(Background Task)管理
  11. 设备管理
  12. 设备使用信息统计
  13. DFX
  14. 国际化开发
  15. 折叠屏系列
  16. .……

在这里插入图片描述


更多了解更多鸿蒙开发的相关知识可以参考:《鸿蒙 (Harmony OS)开发学习手册

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

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

相关文章

基于springboot+vue的智慧生活商城系统

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…

Pytest自动化测试执行环境切换的两种解决方案(超详细)

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 点击文末小卡片 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 痛点分析 在实际企业的项目中&#xff0c;自动化测试的代码往往需要在不同的环境中进行切换&am…

【STL基础】vector、stack、queue、list、pair、map、unordered_map、set、unordered_set(详细讲解)

vector、list、pair、unordered_map、unordered_set、stack、queue 参考文章&#xff1a; &#xff08;1&#xff09;【apollo】泛型编程 与 STL &#xff08;2&#xff09;c stack用法 入门必看 超详细 &#xff08;3&#xff09;C中queue的用法&#xff08;超详细&#xff0c…

C语言关于void类型的指针作为函数形参在使用时需要注意的坑

目录 前言 一、void*指针使用时不同编译器下的处理结果 二、void*指针传递的指针变量进行位运算时&#xff0c;一定要注意强制转换的类型&#xff0c;和值的取值范围 总结 前言 众所周知&#xff0c;void* 指针作为函数形参时&#xff0c;表示可以接受任意类型的参数&#xf…

C语言基础知识点(十七)结构体中只用指针来存储字符串

// 如果需要用结构存储字符串&#xff0c;用字符数组作为成员会比较简单 // 如果需要使用指向char的指针来进行存储&#xff0c;那么需要请求malloc来 // 为字符串分配合适的存储空间#include <stdio.h> #include <string.h> //提供strcpy()\strlen()的原型 #i…

基于FFmpeg混流及录制rtmp直播流

1、什么是混流&#xff1f; 混流就是把多路音视频流合成单流。准确的说&#xff0c;混流应该叫做混音&#xff08;音频流&#xff09;混画面&#xff08;视频流&#xff09; 混流的过程包括解码、混流、编码和推流四个部分。混流这个环节包括做抖动缓冲&#xff0c;目的是把多…

GDPU Java 天码行空4

文章目录 一、实验目的二、实验内容及要求三、实验内容及要求1. 设计AnimalTool工具类&#xff0c;实现eat()函数多态性&#x1f496; AnimalDemo.java&#x1f338; 运行结果 2. 是猫是狗&#x1f496; DuoTaiDemo5.java&#x1f338; 运行结果 3. 太会了&#x1f496; DuoTai…

国内IP地址切换排行榜软件大全

随着互联网的飞速发展&#xff0c;IP地址切换技术在日常工作和生活中扮演着越来越重要的角色。无论是为了网络安全、访问特定地区网站&#xff0c;还是进行市场调研、网络爬虫等&#xff0c;IP地址切换都成为了不可或缺的工具。虎观代理将为您介绍国内较受欢迎的IP地址切换软件…

B004-springcloud alibaba 服务容错 Sentinel

目录 高并发带来的问题服务雪崩效应常见容错方案常见的容错思路隔离超时限流熔断降级 常见的容错组件 Sentinel入门什么是Sentinel微服务项目集成Sentinel核心库安装Sentinel控制台实现一个接口的限流 Sentinel的概念和功能基本概念重要功能 Sentinel规则流控规则三种流控模式三…

深度学习——线性代数相关知识

线性代数基础知识 一、线性代数基础知识1、标量2、向量3、矩阵4、张量5、点积6、向量—矩阵积7、矩阵—矩阵乘法 二、小结 一、线性代数基础知识 本节将介绍简要地回顾一下部分基本线性代数内容&#xff0c;线性代数中的基本数学对象、算术和运算&#xff0c;并用数学符号和相…

基于SpringBoot的高校办公室行政事务管理系统

采用技术 基于SpringBoot的高校办公室行政事务管理系统的设计与实现~ 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBootMyBatis 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 页面展示效果 功能清单 教师信息管理 办公室管理 办公物资管…

软文营销应该怎么做?软文营销的关键

软文本营销不是一个简单的写作和发送文章的过程&#xff0c;而是一个从早期准备到软文本写作再到效果评估的综合运营管理过程。 步骤一&#xff1a;目标明确 目标是指目标用户&#xff0c;找出目标用户是什么样的群体&#xff0c;从而根据用户群体的画像进行软文准备。 步骤二…

3000+人使用,这套人力资源数据分析工具还能这么用

中国科学院自动化研究所&#xff08;以下简称“自动化所”&#xff09;成立于1956年&#xff0c;是中国科学院率先布局成立的“人工智能创新研究院”的总体牵头单位&#xff0c;是中国最早开展智能科学与技术基础理论、关键技术和创新性应用研究的科研机构&#xff0c;也是中国…

ADAS-AEB系统详解

ADAS-AEB系统详解 AEB即自动紧急制动&#xff08;Automatic Emergency Braking&#xff09;&#xff0c;其通过雷达、摄像头共同监测前方车辆以及行人情况&#xff0c;若探测到潜在碰撞风险&#xff0c;系统将采取相应预警及制动措施&#xff0c;从而避免发生碰撞或减轻碰撞损…

加速量产化节奏!移远通信5G RedCap模组RG255C-CN顺利通过SRRC认证

近日&#xff0c;移远通信5G RedCap模组产品再传喜讯——RG255C-CN顺利通过SRRC&#xff08;无线电型号核准&#xff09;认证测试&#xff0c;成为领先行业的轻量化5G产品。 此前&#xff0c;该模组也已通过NAL&#xff08;电信设备进网许可&#xff09;、CCC&#xff08;中国强…

DXP学习1-使用DXP软件创建工程并熟悉相关操作

目录 实验内容&#xff08;任务&#xff09; PCB项目文件及原理图文件的创建及保存&#xff1a; 熟悉窗口界面、主菜单、各工具栏及图纸参数的设置&#xff1a; 首先先通过"纸张选择"做如下修改 修改纸张大小&#x1f447; 修改标题栏的格式&#x1f447; 修改…

生命源集团2024全球品牌发布会成功举办

生命源集团2024全球品牌发布会圆满落幕 3月20日&#xff0c;生命源集团在杭州隆重举办了主题为“生命源启&#xff0c;荣耀之巅”的2024全球品牌发布会。 活动伊始&#xff0c;嘉宾们陆续签到入场&#xff0c;现场气氛热烈而庄重。随后&#xff0c;生命源集团十二大事业部总裁…

6.2 ServiceNow 自动化测试框架 (ATF)

6.2 自动化测试框架 ATF 目录一、自动化测试框架 (ATF) 简介1. Automated Test Framework&#xff08;ATF&#xff09;2. 使用自动化测试框架 (ATF)的好处&#xff1a; 二、 ATF的测试类型1. 功能业务逻辑测试2. 回归测试3. 浏览器兼容性测试4. 服务器端 Jasmine测试 三、 ATF测…

详解:创业老阳推荐的Temu蓝海项目还能赚钱吗?

在当前全球化的背景下&#xff0c;跨境电商行业日益繁荣&#xff0c;成为了许多创业者关注的焦点。其中&#xff0c;Temu项目凭借其独特的商业模式和强大的市场潜力&#xff0c;备受瞩目。尤其是当知名创业导师老阳推荐Temu项目时&#xff0c;更是激起了广大创业者的热情和好奇…

机器人路径规划:基于冠豪猪优化算法(Crested Porcupine Optimizer,CPO)的机器人路径规划(提供MATLAB代码)

一、机器人路径规划介绍 移动机器人&#xff08;Mobile robot&#xff0c;MR&#xff09;的路径规划是 移动机器人研究的重要分支之&#xff0c;是对其进行控制的基础。根据环境信息的已知程度不同&#xff0c;路径规划分为基于环境信息已知的全局路径规划和基于环境信息未知或…