OpenHarmony 源码解析之SystemUi—Statusbar(TS)

news2024/12/23 15:19:05

作者:董伟

简介

SystemUI应用是OpenHarmony中预置的系统应用,为用户提供系统相关信息展示及交互界面,包括系统状态、系统提示、系统提醒等,例如系统时间、电量信息。

本文主要分析batterycomponent、clockcomponent、wificomponent三大组件:

  1. 导入batteryInfo模块,监听系统电池事件,实时获取电池电量状态
  2. 导入时间模块,调用JS内置函数,实时获取系统时间、日期、星期信息
  3. 导入Wifi模块,监听设备Wlan通信与连接事件,实时获取Wifi开关、供电、连接名等信息

架构图

目录

                    /applications/standard/systemui
                        ├── build.gradle                    # 全局编译配置文件
                        ├── settings.gradle                 # 编译模块配置文件
                        ├── LICENSE                         # 许可文件
                        ├── common                          # 通用工具类目录
                        ├── entry                           # entry模块目录
                        ├── signature                       # 证书文件目录
                        ├── features                        # 子组件目录
                        │   ├── batterycomponent            # 电池组件
                        │   ├── clockcomponent              # 时间组件
                        │   ├── control                     # 控制中心组件
                        │   ├── navigationservice           # 导航栏服务组件
                        │   ├── noticeitem                  # 通知子组件
                        │   ├── notificationservice         # 通知服务组件
                        │   ├── signalcomponent             # sim卡信号组件
                        │   ├── wificomponent               # wifi组件
                        ├── product                         # SystemUI总体功能目录
                            ├── navigationBar               # 导航栏模块目录
                            ├── statusbar                   # 状态栏模块目录
                            ├── systemDialog                # 系统弹框模块目录

batterycomponent

简介

电池组件只需监听‘usual.event.BATTERY_CHANGED’即电池变化事件即可,监听到电池变化,便获取一次电池的状态信息,实时获取电池的状态信息(是否在充电,电量百分比),以实现以下功能:

1.自动在充电时展示更醒目的图标,比如填充绿色、带闪电等

2.动态展示电量百分比变化

官方接口文档

https://developer.harmonyos.com/cn/docs/documentation/doc-references/js-apis-battery-info-0000001100730486

源码地址

https://gitee.com/nicklaus0602/applications_systemui/tree/master/features/batterycomponent

导入模块

import BatteryInfo from '@ohos.batteryInfo';			
import BatterySubscriber from '@ohos.commonEvent';		

申明变量与初始化

var mBatterySoc;
var mBatteryCharging;

let mProgress = Constants.DEFAULT_PROGRESS;
let mBatteryEventSubscriber = null;
let mBatteryEventSubscribeInfo = {
  events: ['usual.event.BATTERY_CHANGED']
}

export class BatteryStatus {
  /**
    * 自定义页面初始化函数,由此函数开始一层一层调用下一个函数,将当前类导出后,只需调用此初始化函数即可完成对Battery模块的使用
    * 这里使用AppStorage.SetAndLink('batterySoc', 0)来跨页面关联数据,只需要在另一个页面中导入当前自定义组件, 	
 	* 并使用@StorageLink('batterySoc')batterySoc: number = 1,即可关联变量mBatterySoc与batterySoc,然后在本页面修改mBatterySoc的值,
 	* 另一个页面的变量batterySoc值也会跟着变动。
 	* 
 	* 页面初始化 即注册订阅事件,监听mBatteryEventSubscribeInfo中的事件
 	*
 	*/
    initBatteryStatus() {
      Log.showInfo(TAG, 'initBatteryStatus');
      mBatterySoc = AppStorage.SetAndLink('batterySoc', 0);
      mBatteryCharging = AppStorage.SetAndLink('batteryCharging', false);
      if (mBatteryEventSubscriber == null) {
        this.registerBatteryListener();
      }
      this.getBatteryStatus();
    }

    uninitBatteryStatus() {
      Log.showInfo(TAG, 'uninitBatteryModel');
      this.unregisterBatteryListener();
    }

}

订阅与回调

/**
   * Subscribe Battery events   创建订阅
   */
private registerBatteryListener() {
  Log.showInfo(TAG, 'registerBatteryListener start');
  BatterySubscriber.createSubscriber(
    mBatteryEventSubscribeInfo,
    this.createBatterySubscriberCallBack.bind(this)
  );
}

/**
 * Unsubscribe Battery events  取消订阅
 *
 */
private unregisterBatteryListener() {
  Log.showInfo(TAG, 'unregisterBatteryListener');
  BatterySubscriber.unsubscribe(mBatteryEventSubscriber, () => {
    Log.showInfo(TAG, `unregister Battery Status Listener ===============`);
  });
}

/**
   * Callback of the subscriber 订阅回调,输出日志
   *
   * @param {Object} err - error returns from the caller
   * @param {Object} data - data returns from the caller
   */

private createBatterySubscriberCallBack(err, data) {
  Log.showInfo(TAG, `Subscriberregister createBatterySubscriberCallBack err: ${JSON.stringify(err)} data: ${JSON.stringify(data)}`);
  mBatteryEventSubscriber = data;
  BatterySubscriber.subscribe(mBatteryEventSubscriber, this.batterySubscriberCallBack.bind(this));
}

/**
   * Callback of the events  事件回调
   若err.code == 0,表示函数执行正常,此时判断事件是否为'usual.event.BATTERY_CHANGED',如果该事件发生,即调用电池模块内的函数来获取电池状态信息
   *
   * @param {Object} err - error returns from the caller
   * @param {Object} data - data returns from the caller
   */

private batterySubscriberCallBack(err, data) {
  Log.showInfo(TAG, `batterySubscriberCallBack err: ${JSON.stringify(err)} data: ${JSON.stringify(data)}`);
  if (err.code == 0) {
    if (data.event == 'usual.event.BATTERY_CHANGED') {
      this.getBatteryStatus();
    }
  } else {
    Log.showInfo(TAG, 'Subscriberregister error when subscribing ========');
  }
}

获取电池状态、电量

/**
   *  获取电池状态和剩余电量
   */
private getBatteryStatus() {
  Log.showInfo(TAG,'getBatteryStatus')

  // 调用BatteryInfo.batterySOC获取电量值
  let batterySoc = BatteryInfo.batterySOC;

  // 调用BatteryInfo.chargingStatus获取充电状态枚举值
  let batteryCharging = BatteryInfo.chargingStatus;

  if (null == batterySoc) {
    // Set the battery Soc as full when there is no battery hardware 设备无电池硬件时,电量默认为满电
    batterySoc = mProgress;
  }
  if (batterySoc <= 0) {
    // 确保电量值不为负数
    batterySoc = Math.abs(batterySoc) * Constants.PERCENT_NUMBER;
  }

  this.checkBatteryStatus(batteryCharging, (result) => {               
    let batteryStatus = result;
    // 检查电池的充电状态 将电量的值赋给mBatterySoc,
    mBatterySoc.set(batterySoc);
    // 电池状态赋给mBatteryCharging
    // 0是false,1、2、3是true
    mBatteryCharging.set(batteryStatus);
  });
}

/**
   * 传入参数charging,根据charging的值来赋boolean值给batteryStatus,charging为0时表示电池未充电
   表示电池充电状态的枚举:
   NONE 	0  	表示电池充电状态未知
   ENABLE 	1 	表示电池充电状态为使能状态
   DISABLE	2	表示电池充电状态为停止状态
   FULL	    3	表示电池充电状态为已充满状态
   *
   * @param {number} charging - the battery charging status
   * @param {object} callback - Function callback
   */
private checkBatteryStatus(charging, callback) {
  Log.showInfo(TAG, `checkBatteryStatus charging: ${charging}`);
  let batteryStatus;
  switch (charging) {
    case Constants.NONE:
      batteryStatus = false;
      break;
    case Constants.DISABLE:
    case Constants.ENABLE:
    case Constants.FULL:
      batteryStatus = true;
      break;
    default:
      batteryStatus = false;
      break;
  }
  callback(batteryStatus);
}

Wificomponent

注:官方暂无WifiInfo模块的接口文档,只有“import wifi from ‘@ohos.wifi’”模块的相关文档,二者部分属性的枚举值相同,可以稍做参考。

wifi 模块地址:https://developer.harmonyos.com/cn/docs/documentation/doc-references/js-apis-wlan-0000001121342036

简介

wifi模块需要监听的事件较多,需要监听以下事件:

1.连接事件’usual.event.wifi.CONN_STATE’,

2.供电事件’usual.event.wifi.POWER_STATE’(常用于路由器等设备)

3.连接名事件’WIFI_CONNECT_NAME’,

通过监听wifi的连接状态变化来判断wifi的开关状态,通过监听wifi的供电状态变化来判断wifi是否可用,通过监听wifi连接的名称变化来判断当前连接的是哪一个wifi网络。

通过对这三个事件的监听,我们可以实时获取wifi的开关状态,供电状态,连接名称,借此可以实现以下功能:

1.自动根据wifi开关状态设置不同图标

2.自动展示连接的wifi名称

源码地址

https://gitee.com/openharmony/applications_systemui/tree/master/features/wificomponent

导入模块

import WifiInfo from '@ohos.wifi_native_js';
import Subscriber from '@ohos.commonEvent';

申明变量与初始化

var mCommonEventSubscribeInfo = {
  events: [Constants.EVENT_CONN_STATE,
  Constants.EVENT_POWER_STATE, Constants.Event_CONN_NAME]
};

var mCommonEventSubscriber = null;
var mWifiInfo;
var mWifiStatus;
var mWifiOpenStatus;

 export class WifiModel {
 	/**
 	* 自定义页面初始化函数,由此函数开始一层一层调用下一个函数,将当前类导出后,只需调用此初始化函数即可完成对Wifi模块的使用
 	* 页面初始化,这里使用AppStorage.SetAndLink('wifiInfo', 0)来跨页面关联数据,只需要在另一个页面中导入当前自定义组件, 	
 	* 并使用@StorageLink('wifiInfo')wifiInfo: number = 1,即可关联变量mWifiInfo与wifiInfo,然后再本页面修改mWifiInfo的值,
 	* 另一个页面的变量wifiInfo值也会跟着变动。
 	* 
 	* 页面初始化 即注册订阅事件,监听wifi事件变化,并获取wifi当前状态信息
 	*
 	*/
    initWifiModel() {
        Log.showInfo(TAG, `initWifiModel`)
        mWifiInfo = AppStorage.SetAndLink("wifiInfo", 0);
        mWifiStatus = AppStorage.SetAndLink("wifiStatus", false);
        mWifiOpenStatus = AppStorage.SetAndLink("wifiOpenStatus", false);
        if(mCommonEventSubscriber == null){
          this.registerWiFiStatusListener();
        }
        this.getWifiMessage();
      }

    /**
     * 取消初始化时取消订阅
     *
     */
     uninitWifiModel() {
       Log.showInfo(TAG, `uninitWifiModel`)
       this.unregisterWiFiStatusListener()
     }
}

订阅与回调

通过创建对wifi事件的订阅,来监听mCommonEventSubscribeInfo中的三个事件,‘usual.event.wifi.CONN_STATE’,‘usual.event.wifi.POWER_STATE’,‘WIFI_CONNECT_NAME’,若事件发生,则触发回调,

/**
 * Subscribe wifi events  订阅wifi事件,无返回值,创建订阅,监听mCommonEventSubscribeInfo中的事件
 *
 */
registerWiFiStatusListener() : void {
  Log.showInfo(TAG, `register Wifi status listener ===========`);
  Subscriber.createSubscriber(
    mCommonEventSubscribeInfo,
    this.createWifiStatusSubscriberCallBack.bind(this)
  );
}

/**
 * Callback of the subscriber    订阅回调
 *
 * @param {Object} err - error returns from the caller
 * @param {Object} data - data returns from the caller
 */
createWifiStatusSubscriberCallBack(err, data) {
  Log.showInfo(TAG, `createWifiStatusSubscriberCallBack start err: ${JSON.stringify(err)} data: ${JSON.stringify(data)}`);
  mCommonEventSubscriber = data;
  Subscriber.subscribe(mCommonEventSubscriber, this.wifiStatusSubscriberCallBack.bind(this));
}

/**
 * Callback of the events     事件回调
 *
 * @param {Object} err - error returns from the caller
 * @param {Object} data - data returns from the caller
 */
private wifiStatusSubscriberCallBack(err, data) {
  Log.showInfo(TAG, `wifiStatusSubscriberCallBack start err:${ JSON.stringify(err)} data: ${ JSON.stringify(data) }`);
  // 默认枚举值 DEFAULT_ERR_CODE: number = 0,代表函数正常运行
  if (err.code == Constants.DEFAULT_ERR_CODE) {
    Log.showInfo(TAG, `wifi data == ${JSON.stringify(data)}`);
    // 枚举值 EVENT_CONN_STATE: string = 'usual.event.wifi.CONN_STATE',表示wifi连接状态变化
    if (data.event == Constants.EVENT_CONN_STATE) {
    /**
     * 枚举值 
     * WIFI_STATE_AP_CONNECTING: number = 1;     正在建立WLAN连接
     * WIFI_STATE_NETWORK_ENABLED: number = 3;	 网络可用
     * WIFI_STATE_NO_NETWORK: number = 4;		 无网络连接
     * 如果正在建立WLAN连接||网络可用||无网络连接,则调用changeWifiStatus()方法,设置mWifiStatus为true,表示当前wifi已激活,否则即设置为false,表	  * 示当前wifi未打开
     */
      if(data.code == Constants.WIFI_STATE_AP_CONNECTING ||
      data.code == Constants.WIFI_STATE_NETWORK_ENABLED ||
      data.code == Constants.WIFI_STATE_NO_NETWORK){
        this.updateWifiInfo();
        this.changeWifiStatus(true);
      }else {
        this.updateWifiInfo();
        this.changeWifiStatus(false);
        mWifiName.set('WLAN');
      }
    }
    // WIFI_POWER_OFF: number = 0;  WIFI_POWER_ON: number = 4;
    // data.code == 0,wifi不可用,mWifiOpenStatus.set(false),
    // data.code == 4,wifi可用,mWifiOpenStatus.set(true)

    // 枚举值 EVENT_POWER_STATE: string = 'usual.event.wifi.POWER_STATE',表示wifi供电状态变化(常用于路由器等设备)
    if (data.event == Constants.EVENT_POWER_STATE) {
      if( data.code == Constants.WIFI_POWER_OFF){
        this.updateWifiInfo();
        this.changeWifiStatus(false);
        mWifiOpenStatus.set(false);
        mWifiName.set('WLAN');
      }else if(data.code == Constants.WIFI_POWER_ON){
        mWifiOpenStatus.set(true);
      }
    }
    // 枚举值 Event_CONN_NAME: string = 'WIFI_CONNECT_NAME',表示连接名称变化,意味着连接到了wifi网络(或者切换到了其他的wifi网络),可以获取当前wifi的信号强度了,更新wifi名称,并设置wifiStatus为true,表示已连接
    if(data.event == 'WIFI_CONNECT_NAME'){
      this.updateWifiName(JSON.parse(data.data).name)
      this.changeWifiStatus(true)

      // rssi是热点的信号强度(dBm),类型为number,取值范围为[0, 4],rssi为4时wifi信号满格
      // band是WLAN接入点的频段,类型为number
      // 将rssi,band传入函数updateWifiInfo()
      let rssi = JSON.parse(data.data).rssi
      let band = JSON.parse(data.data).band
      Log.showInfo(TAG, `WIFI_CONNECT_NAME ================ ${rssi}`)
      this.updateWifiInfo(rssi,band);
    }
  } else {
    Log.showError(TAG, `error when subscribing ========`);
  }
}

/**
 * Unsubscribe wifi events    取消wifi事件订阅(退订)
 *
 */
private unregisterWiFiStatusListener() {
  Subscriber.unsubscribe(mCommonEventSubscriber, () => {
    Log.showInfo(TAG, `unregister Wifi Status Listener ===============`);
  });
}

获取Wifi状态

/**
 * Check the connection status of Wifi  检查wifi的连接状态
 *
 * @param {boolean} status - if display wifi icon
 */
private changeWifiStatus(status) {
  Log.showInfo(TAG, `enter changeWifiStatus ================ ${status}`);
  mWifiStatus.set(status)
}

// 更新wifi信息,传入参数rssi,band
private updateWifiInfo(rssi=Constants.UPDATE_WIFI_INFO_DEFAULT_PARAM,band=Constants.SIGN_LEVEL) {
  Log.showInfo(TAG, `enter changeWifiInfos ================ ${rssi}+${band}`);
  mWifiInfo.set(this.getWifiInfo(rssi,band))
  Log.showInfo(TAG, `mWifiInfo wifiInfo ${mWifiInfo.get()}`);
}
// 更新wifi名称
private updateWifiName(name) {
  Log.showInfo(TAG, `enter changeWifiNames ================ ${name}`);
  mWifiName.set(name);
}

/**
 * Update the image of wifi status   更新wifi状态的图标(根据level,即信号的强度,取值范围为[0, 4]),信号4代表信号满格
 *
 * @param {number} rssi - the rssi number of the connected wifi
 * @return {string} image used to show wifi status
 */
private getWifiInfo(rssi,band) {
  //The current version keeps return 0 as result, set the level as 4(full level) by hand.
  Log.showInfo(TAG, `getWifiImage enter =========`);
  //Fake number of band and rssi for wifi signal level temporarily
  let level = WifiInfo.getSignalLevel(rssi, band);
  Log.showInfo(TAG, `wifi level = ${level}`);
  return level;
}
// 启用wifi(暂不可用)
enableWifi() {
  Log.showInfo(TAG, 'enableWifi ing');
  WifiInfo.enableWifi();
}
// 关闭wifi(暂不可用)
disableWifi() {
  Log.showInfo(TAG, 'disableWifi ing');
  WifiInfo.disableWifi();
}

Clockcomponent

简介

对于系统时间的获取较为简单,只需在页面初始化时调用JS的内置函数来获取系统时间即可,需要注意的是因为要保持所展示的时间实时更新,需要使用以下函数来设置时间间隔,确保每隔一定的时间就调用一次函数,保证时间的实时更新。

setInterval(() => {
    函数名;
  }, 时间间隔);

本文中通过每隔3秒获取一次时间来展示系统时间,满足设备展示“xx:xx”即“小时-分钟“的需要,如果需要精度更高,就需要调整LOOP_TIME,使得调用函数的间隔更短。

源码地址

https://gitee.com/openharmony/applications_systemui/tree/master/features/clockcomponent

获取时间数据

const LOOP_TIME = 3000; 
var mTimeLink;
var mDayLink;
var mWeekDayLink;
var mMonthLink;
/**
  * 获取当前日期和时间 调用getDate()函数,实例化Date对象,获取系统当前时间,调用JS内置函数,每隔三秒将date对象传入
  *	this.updateTime(date);
  *	this.updateDay(date);
  *	this.updateWeekDay(date);
  *	this.updateMonth(date);
  *	函数,获取时间、日、周、月数据
  *
  */
private getCurrentDate() {
  Log.showInfo(TAG, 'getCurrentDate');
  this.getDate();
  timeInterval = setInterval(() => {
    this.getDate();
  }, LOOP_TIME);
}

// 实例化Date对象,获取系统当前时间,并作为参数传入JS内置函数获取想要的时分秒、日、周、月等值
private getDate(){
  Log.showInfo(TAG, 'getDate');
  let date = new Date();
  this.updateTime(date);
  this.updateDay(date);
  this.updateWeekDay(date);
  this.updateMonth(date);
}

/**
 * Update Time.
 * date.toTimeString()返回一个表示该Date对象时分秒部分的时间字符串
   substring(0, 5) 截取下标第0个到第5个字符,即 xx:xx:xx
 * @param {Object} date - Object of Date.
 */
private updateTime(date) {
  let time = date.toTimeString().substring(0, 5);
  mTimeLink.set(time);
}

/**
 * Update Day.
 * date.getDate() 获取每个月的第几号-number
 * @param {Object} date - Object of Date.
 */
private updateDay(date) {
  let day = date.getDate();
  mDayLink.set(day);
}

/**
 * Update WeekDay.
 * date.getDay() 返回每周中的第几天-number,想获得'星期一'这样的value,还需要定义数组来获取,例如:
 var weekdaylist=new Array(7)
	weekdaylist[0]="周日"
	weekdaylist[1]="周一"
	weekdaylist[2]="周二"
	weekdaylist[3]="周三"
	weekdaylist[4]="周四"
	weekdaylist[5]="周五"
	weekdaylist[6]="周六"
	weekdaylist[this.mWeekDay]
 * @param {Object} date - Object of Date.
 */
private updateWeekDay(date) {
  let weekDay = date.getDay();
  mWeekDayLink.set(weekDay);
}

/**
 * Update Month.
 * date.getMonth() 返回月份-number,月份取值范围【0,11】,这里需要加1
 * @param {Object} date - Object of Date.
 */
private updateMonth(date) {
  let month = (date.getMonth() + 1);
  mMonthLink.set(month);
}

结语

本文对源码的方法进行了细致的解读,目标是节省广大开发者分析源码的时间,希望大家阅读本文后,可以将源码中从订阅监听事件到调用方法获得枚举值的整个模块直接拿来使用,以此助力鸿蒙OS生态搭建!

为了能让大家更好的学习鸿蒙(HarmonyOS NEXT)开发技术,这边特意整理了《鸿蒙开发学习手册》(共计890页),希望对大家有所帮助:https://qr21.cn/FV7h05

《鸿蒙开发学习手册》:

如何快速入门:https://qr21.cn/FV7h05

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

开发基础知识:https://qr21.cn/FV7h05

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

基于ArkTS 开发:https://qr21.cn/FV7h05

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

鸿蒙开发面试真题(含参考答案):https://qr18.cn/F781PH

鸿蒙开发面试大盘集篇(共计319页):https://qr18.cn/F781PH

1.项目开发必备面试题
2.性能优化方向
3.架构方向
4.鸿蒙开发系统底层方向
5.鸿蒙音视频开发方向
6.鸿蒙车载开发方向
7.鸿蒙南向开发方向

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

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

相关文章

C#自定义控件 生成 与 加入到项目

C#自定义控件生成 在C#中&#xff0c;自定义控件通常是通过继承现有的控件类&#xff08;如UserControl、Form等&#xff09;并添加或修改其属性和方法来实现的。以下是一个简单的示例&#xff0c;演示如何创建一个自定义控件&#xff1a; 首先&#xff0c;创建一个新的Window…

陪诊小程序成品|陪诊系统功能|陪诊小程序研发功能和流程

近年来&#xff0c;随着人们健康意识的提升和医疗行业的不断发展&#xff0c;陪诊小程序在医疗领域中扮演着越来越重要的角色。那么&#xff0c;什么是陪诊小程序&#xff1f;它具有怎样的功能和流程呢&#xff1f;本文将为您详细解读。 陪诊小程序是一种通过手机应用程序进行…

Ipython与Jupyter之间的关系

IPython 和 Jupyter 之间的关系可以从它们的历史和目标中得到很好的解释。IPython&#xff08;Interactive Python&#xff09;最初是由 Fernando Prez 于 2001 年创建的&#xff0c;旨在提升 Python 的交互式计算体验。它提供了一个强大的交互式 Python shell 和一个面向高效计…

Arduino IDE工程代码多文件编程和中文设置

一、esp8266模块信息 二、中英文切换 点击文件( File )–选择首选项( Preference )—选择语言( Language )—选择中文–点击确定( OK ) 三、多文件编程 在Arduino编程中&#xff0c;将代码分割成多个文件是一种很好的做法&#xff0c;特别是项目变得越来越大和复杂时。这样…

基于nodejs+vue基于hive旅游数据的分析与应用python-flask-django-php

系统阐述的是使用基于hive旅游数据的分析与应用系统&#xff0c;对于nodejs结构、MySql进行了较为深入的学习与应用。主要针对系统的设计&#xff0c;描述&#xff0c;实现和分析与测试方面来表明开发的过程。开发中使用了express框架和MySql数据库技术搭建系统的整体架构。利用…

【爬虫框架pyspider】02 - pyspider 用法详解

pyspider 用法详解 前面我们了解了 pyspider 的基本用法&#xff0c;我们通过非常少的代码和便捷的可视化操作就完成了一个爬虫的编写&#xff0c;本节我们来总结一下它的详细用法。 1. 命令行 上面的实例通过如下命令启动 pyspider&#xff1a; pyspider all 命令行还有很…

如何调用occtproxy放入自己的wpf文件

1.创建一个wpf程序 2.添加项目occtproxy.vcxproj 3.把该项目配置类型设为dll 4.添加引用 5.报错显示&#xff0c;这是因为还没有生成dll 6.把occtproxy设为启动项目运行&#xff0c;设定输出目录在该目录下&#xff0c;生成dll 7.再运行&#xff0c;即可

基于Colab训练的yolov4-tiny自定义数据集(可用于OpenCV For Unity)

参考资料文档和视频。 1.打开文档,点击【文件】【在云端硬盘中保存一份副本】,即将文档复制到自己云端硬盘。 2.打开该文件,按文中提示进行。 【代码执行程序】【更改运行时类型】修改运行时为GPU(免费的GPU不好用,收费的好用,某宝上几十元就可用一个月) 步骤1) !git…

日新增百万数据clickhouse大数据解决方案记录分享

公司广告业务需求&#xff0c;需要多个维度统计每个应用的设备数&#xff0c;点击率&#xff0c;展示率&#xff0c;等相关数据&#xff0c;而且数据需要进行去重&#xff0c;我第一时间想到的是利用clickhouse来做统计&#xff0c;因为我们平台访问量比较大&#xff0c;用mysq…

STM32-01基于HAL库(CubeMX+MDK+Proteus)仿真开发环境搭建(LED点亮测试实例)

STM32-01基于HAL库&#xff08;CubeMXMDKProteus&#xff09;仿真开发环境搭建&#xff08;LED点亮测试实例&#xff09; 一、 开发工具版本列表二、安装过程三、实例测试&#xff08;点亮单个LED&#xff09;0、功能需求分析1、Proteus绘制电路原理图2、STMCubeMX 配置引脚及模…

35.网络游戏逆向分析与漏洞攻防-游戏网络通信数据解析-登录成功数据包内容分析

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 如果看不懂、不知道现在做的什么&#xff0c;那就跟着做完看效果 内容参考于&#xff1a;易道云信息技术研究院VIP课 上一个内容&#xff1a;34.登录数据包的…

2.3 Mac OS安装Python环境

Mac OS安装Python环境 和 Linux 发行版类似&#xff0c;最新版的 Mac OS X 也会默认自带 Python 2.x。 我们可以在终端&#xff08;Terminal&#xff09;窗口中输入python命令来检测是否安装了 Python 开发环境&#xff0c;以及安装了哪个版本&#xff0c;如下所示&#xff1…

go的for循环应该这么用

目录 目录 一&#xff1a;介绍 1: for流程控制 2&#xff1a;for-range流程控制 二&#xff1a;实例展示 1&#xff1a;//按照一定次数循环 2&#xff1a;//无限循环 3: //循环遍历整数、各种容器和通道 4&#xff1a;遍历通道 5&#xff1a;//指针数组循环 6&…

javaWeb个人日记(博客)管理系统

一、简介 在快节奏的生活中&#xff0c;记录生活点滴、感悟和思考是一种重要的方式。基于此&#xff0c;我设计了一个基于JavaWeb的个人日记本系统&#xff0c;旨在帮助用户轻松记录并管理自己的日记。该系统包括登录、首页、日记列表、写日记、日记分类管理和个人中心等功能&…

ssm006基于java的少儿编程网上报名系统+vue

少儿编程网上报名系统 摘 要 在国家重视教育影响下&#xff0c;教育部门的密确配合下&#xff0c;对教育进行改革、多样性、质量等等的要求&#xff0c;使教育系统的管理和运营比过去十年前更加理性化。依照这一现实为基础&#xff0c;设计一个快捷而又方便的网上少儿编程网上…

Python程序怎么打包成exe文件

前言 pyinstaller可以将.py文件打包成.exe可执行文件&#xff0c;即使别人的电脑上没有搭建Python环境&#xff0c;也是可以直接运行程序的。 pyinstaller安装 首先打开cmd&#xff0c;在里面输入下面这一行命令&#xff0c;回车即可。 pip install pyinstaller 我运行命令…

力扣面试150 直线上最多的点数 数学 直线斜率 欧几里得求最大公约数

Problem: 149. 直线上最多的点数 思路 &#x1f468;‍&#x1f3eb; 参考题解 &#x1f496; 枚举直线 枚举统计 时间复杂度: O ( n 3 ) O(n^3) O(n3) 空间复杂度: O ( 1 ) O(1) O(1) class Solution {public int maxPoints(int[][] points){int n points.length;int…

学会Sass的高级用法,减少样式冗余

在当今的前端开发领域&#xff0c;样式表语言的进步已经显著提升了代码组织性和可维护性。Sass&#xff08;Syntactically Awesome Style Sheets&#xff09;作为CSS预处理器的翘楚&#xff0c;以其强大的变量、嵌套规则、混合宏&#xff08;mixin&#xff09;、循环和函数等高…

2015年认证杯SPSSPRO杯数学建模B题(第二阶段)替换式密码全过程文档及程序

2015年认证杯SPSSPRO杯数学建模 B题 替换式密码 原题再现&#xff1a; 历史上有许多密码的编制方法。较为简单的是替换式密码&#xff0c;也就是将文中出现的字符一对一地替换成其它的符号。对拼音文字而言&#xff0c;最简单的形式是单字母替换加密&#xff0c;也就是以每个…

鸿蒙开发图形图像:【图形子系统】

图形子系统 图形子系统主要包括UI组件、布局、动画、字体、输入事件、窗口管理、渲染绘制等模块&#xff0c;构建基于轻量OS应用框架满足硬件资源较小的物联网设备或者构建基于标准OS的应用框架满足富设备的OpenHarmony系统应用开发。 1.1 轻量系统 简介 图形子系统主要包括…