HarmonyOS 状态管理

在声明式 UI 框架中,数据的改变触发 UI 的重新渲染。在 ArkUI 中不是所有数据的变化都会触发 UI 重新渲染,只有 状态变量 才会引起 UI 重新渲染。

状态变量

状态变量: 指被状态装饰器装饰的变量,只有这种变量的改变才会引起 UI 的重新渲染。

常规变量: 指没有被状态装饰器装饰的变量,不会引起 UI 的重新渲染。

按影响范围分为:

  • 组件级别的状态: @State, @Prop, @Link, @Provide/@Consume, @Observed, @ObjectLink
  • 应用级别的状态:@StorageLink/@LocalStorageLink, @StorageProp/@LocalStorageProp

按传递方向分为:

  • 只读的单向传递
  • 可变更的双向传递

q.png

@State 组件内状态

@State 装饰的状态变量,是组件内的状态,是私有的,只能从组件内部访问,不与父组件中任何类型的状态变量同步。

允许装饰的变量类型:Object、class、string、number、boolean、enum,Date, 以及这些类型的数组。API11及以上支持Map、Set, undefined,null 和 联合类型

@State 装饰原始类型

@Entry
@Component
struct StatePage {@State text: string = 'HarmonyOS'@State count: number = 0build() {Column({ space: 10 }) {Text('string: ' + this.text).fontSize(17)Text('number: ' + this.count)Button('text = "Android"').onClick((event: ClickEvent) => {this.text = 'Android'})Button('count++').onClick((event: ClickEvent) => {this.count++})}.width('100%').height('100%')}
}

点击 Button 修改了 text,count 变量的值,会触发 UI 重新渲染,显示最新的值。

@State 装饰 class

export class User {name: stringcar?: Carconstructor(name: string, car?: Car) {this.name = name;this.car = car;}
}export class Car {brand: stringengine?: Engineconstructor(brand: string, engine?: Engine) {this.brand = brand;this.engine = engine;}
}export class Engine {type?: stringconstructor(type: string) {this.type = type;}
}
@Entry
@Component
struct StateClassPage {@State user: User = new User('Jack')build() {Column({space: 10}) {Text('Class: ' + `name=${this.user.name}, car=${this.user.car?.brand}`).fontSize(17)Column({ space: 10 }) {Button(`user = new User('Mike')`).onClick((event: ClickEvent) => {// 有效刷新this.user = new User('Mike')})Button(`user.name = 'Pony New'`).onClick((event: ClickEvent) => {// 有效刷新this.user.name = 'Pony New'})Button(`user.car = new Car('Benz')`).onClick((event: ClickEvent) => {// 有效刷新,@State 可以观察到一级属性 car 的赋值this.user.car = new Car('Benz')})Button(`this.user.car.brand = 'BMW'`).onClick((event: ClickEvent) => {// 无效刷新, user.car.brand, user.car.engine 为二级属性, @State 观察不到, 需要使用 @Observed 和 @ObjectLinkif (this.user.car) {this.user.car.brand = 'BMW'}})}}.width('100%')}
}

对于 @State 装饰的 Class 状态变量, ArkUI 只能观察到状态变量的一级属性的变化,从而引起 UI 重新渲染。如上例中 user.name 和 user.car 是 User 的一级属性,user.car.brand 是 User 的二级属性, 所以点击Button执行 this.user.car.brand = 'BMW' UI 没有刷新,这种情况,需要使用 @Observed/@ObjectLink

@State 装饰数组

@Entry
@Component
struct StateArrayPage {@State stringArray: string[] = ['Java', 'Kotlin']@State userArray: User[] = [new User('Jack'), new User('Make')]build() {Column({ space: 10 }) {ForEach(this.stringArray, (item: string) => {Text(item)})Row({ space: 6 }) {Button('add').onClick((event: ClickEvent) => {this.stringArray.push('Typescript')})Button('remove').onClick((event: ClickEvent) => {if (this.stringArray.length > 0) {this.stringArray.splice(0, 1)}})Button('update').onClick((event: ClickEvent) => {if (this.stringArray.length > 0) {this.stringArray[0] = 'Javascript by updated'}})Button('new Array()').onClick((event: ClickEvent) => {this.stringArray = ['New Array1', 'New Array2']})}Divider().height(20).color(Color.Gray)ForEach(this.userArray, (item: User) => {Text(`name=${item.name},car=${item.car}`)})Column({ space: 10 }) {Button('add').onClick((event: ClickEvent) => {this.userArray.push(new User('Jane'))})Button('remove').onClick((event: ClickEvent) => {if (this.stringArray.length > 0) {this.userArray.splice(0, 1)}})Button('update userArray[0]=new User("Lace")').onClick((event: ClickEvent) => {if (this.stringArray.length > 0) {// class 数组, 可以观察到数组中元素 重新赋值this.userArray[0] = new User('Lace')}})Button('userArray[0].name="Shane"').onClick((event: ClickEvent) => {// 无效刷新, 对于 class数组, 观察不到数组中 元素的属性 赋值this.userArray[0].name = 'Shane'})}}.width('100%')}
}

对于数组,ArkUI 可以观察到 数组新增,删除,重新创建数组, 数组项重新赋值,从而引起 UI 重新渲染,无法观察到 数组中某个元素的 属性的变化

@Prop 父 —> 子单向同步

@Prop 是单向同步的:对父组件状态变量值的修改,将同步给子组件@Prop装饰的变量,子组件@Prop变量的修改不会同步到父组件的状态变量上。

@Entry
@Component
struct PropPage {@State text: string = 'ArkUI'@State user: User = new User('Jane', new Car('Benz E'))build() {Column({ space: 10 }) {Text(this.text).onClick(() => {this.text = 'Flutter '})Text(`name:${this.user.name},car=${this.user.car?.brand}`).onClick(()=> {this.user = new User('parent User')})Divider().height(20)PropChild({ title: this.text, user: this.user })}.width('100%')}
}@Component
struct PropChild {/*** 修改父组件的状态变量可以同步刷新子组件, 而修改子组件的状态变量不会同步刷新父组件*/@Prop title: string = 'default'@Prop user: Userbuild() {Column({ space: 10 }) {Text(this.title).onClick(() => {this.title = 'JetpackCompose'})Text(`name:${this.user.name},car=${this.user.car?.brand}`)Button('user=new User("Shine")').onClick((event: ClickEvent) => {this.user = new User('Shine')})Button('user.car = new Car("Audi A6")').onClick((event: ClickEvent) => {this.user.car = new Car('Audi A6')})Button('user.car.brand="BWM 530"').onClick((event: ClickEvent) => {if (this.user.car) {this.user.car.brand = 'BWM 530'}})}}
}

@Prop 装饰的状态变量, ArkUI 同样观察不到 二级属性的变化,并且子组件状态变量的变化不会引起父组件 UI 的刷新, 但父组件状态变量的变化可以引起子组件的刷新。

@Link 父子双向同步

子组件中被@Link装饰的变量与其父组件中对应的数据源建立双向数据绑定.

@Link装饰器不能在@Entry装饰的自定义组件中使用。

@Link 装饰原始类型

@Entry
@Component
struct LinkBasicPage {@State text: string = 'ArkUI'build() {Column({ space: 10 }) {Text('父组件:' + this.text).onClick(() => {this.text = 'Flutter '})LinkBasicChild({ title: $text })}.width('100%')}
}@Component
struct LinkBasicChild {// @Link装饰的状态变量禁止初始化// @Link title: string = ''@Link title: stringbuild() {Column({ space: 10 }) {Text('子组件:' + this.title).onClick(() => {this.title = 'JetpackCompose'})}}
}

父子组件的状态变量的变化,可以相互引起 UI 刷新

@Link 装饰 class

@Entry
@Component
struct LinkClassPage {@State user: User = new User('Jane', new Car('Benz E'))build() {Column({ space: 10 }) {Text(`父组件 name=${this.user.name},car=${this.user.car?.brand}`)Button('user=new User("Mike")').onClick((event: ClickEvent) => {this.user = new User('Mike-P')})Divider()LinkClassChild({ user: $user })}.width('100%')}
}@Component
struct LinkClassChild {// 禁止本地初始化@Link user: Userbuild() {Column({ space: 10 }) {Text(`子组件 name=${this.user.name},car=${this.user.car?.brand}`)Button('user=new User("Shine")').onClick((event: ClickEvent) => {this.user = new User('Shine')})Button('user.car = new Car("Audi A6")').onClick((event: ClickEvent) => {this.user.car = new Car('Audi A6')})Button('user.car.brand="BWM 530"').onClick((event: ClickEvent) => {if (this.user.car) {this.user.car.brand = 'BWM 530'}})}}
}

@Link 装饰的状态变量, ArkUI 同样观察不到 二级属性的变化。一级属性可以引起父子组件UI 的刷新。

@Link 装饰数组

@Entry
@Component
struct LinkArrayPage {@State list: string[] = ['Android', 'iOS', 'Harmony']build() {Column({ space: 10 }) {ForEach(this.list, (item: string) => {Text(item)})Button('new Array').onClick((event: ClickEvent) => {this.list = new Array<string>('Benz', 'BMW', 'Audi')})Button('Add').onClick((event: ClickEvent) => {this.list.push('parent add')})Button('remove').onClick((event: ClickEvent) => {if (this.list.length > 0) {this.list.splice(0, 1)}})Button('update').onClick((event: ClickEvent) => {if (this.list.length > 0) {this.list[0] = 'parent update'}})Divider()LinkArrayChild({ childList: $list })}.width('100%')}
}@Component
struct LinkArrayChild {@Link childList: string[]build() {Column({ space: 10 }) {ForEach(this.childList, (item: string) => {Text(item)})Button('new Array').onClick((event: ClickEvent) => {this.childList = new Array<string>('Kotlin', 'Swift', 'ArkTS')})Button('Add').onClick((event: ClickEvent) => {this.childList.push('child Add')})Button('remove').onClick((event: ClickEvent) => {if (this.childList.length > 0) {this.childList.splice(0, 1)}})Button('update').onClick((event: ClickEvent) => {if (this.childList.length > 0) {this.childList[0] = 'child update'}})}}
}

@Provide/@Consume 父与后代组件双向同步

@Provide和@Consume,应用于与后代组件的双向数据同步,应用于状态数据在多个层级之间传递的场景。不同于上文提到的父子组件之间通过命名参数机制传递,@Provide和@Consume摆脱参数传递机制的束缚,实现跨层级传递。

@Provide/@Consume 装饰原始类型

@Entry
@Component
struct ProvideConsumeBasicPage {@Provide count: number = 1build() {Column({ space: 10 }) {Text(this.count.toString()).onClick(() => {this.count++})ProvideChild()}.width('100%')}
}@Component
struct ProvideChild {@Consume count: numberbuild() {Column({ space: 10 }) {Text(this.count.toString()).onClick(() => {this.count += 2})ProvideChildSecond()}.backgroundColor(Color.Brown).padding(30)}
}@Component
struct ProvideChildSecond {@Consume count: numberbuild() {Column() {Text(this.count.toString()).onClick(() => {this.count += 3})}.backgroundColor(Color.Pink).padding(30)}
}

@Provide/@Consume 装饰 class

@Entry
@Component
struct ProvideConsumeClassPage {@Provide user: User = new User('Apple')build() {Column({ space: 10 }) {Text('父组件:' + this.user.name)Button('user.name="parent"').onClick((event: ClickEvent) => {this.user.name = 'parent'})Divider()ProvideClassChild()}.width('100%')}
}@Component
struct ProvideClassChild {@Consume user: Userbuild() {Column({ space: 10 }) {Text('孩子组件:' + this.user.name)Divider()ProvideClassChildSecond()}}
}@Component
struct ProvideClassChildSecond {@Consume user: Userbuild() {Column({ space: 10 }) {Text('孙子组件:' + this.user.name)Divider()ProvideClassChildThird()}}
}@Component
struct ProvideClassChildThird {@Consume user: Userbuild() {Column({ space: 10 }) {Text('曾孙子:' + this.user.name)Button('user=new User("曾孙子")').onClick((event: ClickEvent) => {this.user = new User('曾孙子')})Button('user.name="曾孙name:sx"').onClick((event: ClickEvent) => {this.user.name="曾孙name:sx"})Button('user.car.brand = "曾孙.name.car: Benz S"').onClick((event: ClickEvent) => {if (this.user.car) {this.user.car.brand = '曾孙.name.car: Benz S'}})}}
}

@Oberved/@ObjectLink 嵌套类对象属性变化

上述 @State, @Prop,@Link 和 @Provide/@Consume 装饰器只能观察 class 一级属性赋值,无法观察二级属性变化,但在实际开发过程中,class 的属性类型仍是 class 类型是很常用见的,因此就需要使用 @Observed/@ObjectLink 来实现了。

@ObjectLink和@Observed类装饰器用于在涉及嵌套对象或数组的场景中进行双向数据同步:

  • 被@Observed装饰的类,可以被观察到属性的变化;
  • 子组件中@ObjectLink装饰器装饰的状态变量用于接收@Observed装饰的类的实例,和父组件中对应的状态变量建立双向数据绑定。这个实例可以是数组中的被@Observed装饰的项,或者是class object中的属性,这个属性同样也需要被@Observed装饰。
  • 单独使用@Observed是没有任何作用的,需要搭配@ObjectLink或者@Prop使用。
  • @ObjectLink 装饰的变量必须为被@Observed装饰的class实例
  • @ObjectLink 装饰的变量不允许重新赋值。

@ObjectLink 装饰 class

@Entry
@Component
struct ObjectLinkBasicPage {@State user: User = new User('Jack', new Car('BMW 3 serial'))build() {Column({ space: 10 }) {Button(`user.car.brand = 'BMW'`).onClick((event: ClickEvent) => {if (this.user.car) {this.user.car.brand = 'Benz E class'}})Divider()CarItem({ car: this.user.car })}.width('100%')}
}@Component
struct CarItem {// Car 需要被 @Observed 装饰@ObjectLink car: Carbuild() {Column() {Text('car: ' + this.car.brand)Button('car=new Car("audi")').onClick((event: ClickEvent) => {// 报错,@ObjectLink装饰的状态变量不允许被赋值, 可以对它的属性赋值// this.car = new Car('audi')this.car.brand = 'audi'})}.width('90%').padding(20).backgroundColor(Color.Pink)}
}

@ObjectLink 装饰数组中数组项

@Entry
@Component
struct ObjectLinkBasicPage {@State userArray: User[] = [new User('Jack', new Car('BMW 3 serial')),new User('Mike', new Car('Audi A4L'))]build() {Column({ space: 10 }) {Button(`userArray[0].car.brand = 'Benz S class'`).onClick((event: ClickEvent) => {if (this.userArray.length > 0) {let user: User = this.userArray[0]if (user.car) {user.car.brand = 'Benz S class'}}})ForEach(this.userArray, (item: User) => {UserItem({ user: item })})}.width('100%')}
}@Component
struct UserItem {// User 需要被 @Observed 装饰@ObjectLink user: Userbuild() {CarItem({ car: this.user.car })}
}@Component
struct CarItem {// Car 需要被 @Observed 装饰@ObjectLink car: Carbuild() {Column() {Text('car: ' + this.car.brand)}.width('90%').padding(20).backgroundColor(Color.Pink)}
}

ViewModel 存储数据

@Entry
@Component
struct ViewModelPage {@State viewModel: UserViewModel = new UserViewModel([new User('jack', new Car('保时捷')),new User('mack', new Car('奔驰'))])build() {Scroll() {Column() {Flex({ wrap: FlexWrap.Wrap }) {Button('new Array').margin(6).onClick((event: ClickEvent) => {this.viewModel.userList = [new User('new kotlin')]})Button('add').margin(6).onClick((event: ClickEvent) => {this.viewModel.userList.push(new User('kotlin'))})Button('remove').margin(6).onClick((event: ClickEvent) => {if (this.viewModel.userList.length > 0) {this.viewModel.userList.splice(0, 1)}})Button('viewModel.userList[0]=new User("peter")').margin(6).onClick((event: ClickEvent) => {if (this.viewModel.userList.length > 0) {this.viewModel.userList[0] = new User('peter', new Car('马自达'))}})Button('viewModel.userList[0].name="张三"').margin(6).onClick((event: ClickEvent) => {if (this.viewModel.userList.length > 0) {this.viewModel.userList[0].name = '张三'}})Button('viewModel.userList[0].car.brand="XIAOMI SU7 MAX"').margin(6).onClick((event: ClickEvent) => {if (this.viewModel.userList.length > 0) {let car = this.viewModel.userList[0].carif (car) {car.brand = 'XIAOMI SU7 MAX'}}})}ChildUser({ userList: this.viewModel.userList })}}}
}@Component
struct ChildUser {// ObservableArray 需要被 @Observed 装饰@ObjectLink userList: ObservableArray<User>build() {Column() {ForEach(this.userList, (user: User) => {UserItem({ user: user })Divider()})}.padding(20)}
}@Component
struct UserItem {// User 需要被 @Observed 装饰@ObjectLink user: Userbuild() {Column() {Text('user.name: ' + this.user.name)CarItem({ car: this.user.car })}}
}@Component
struct CarItem {// Car 需要被 @Observed 装饰@ObjectLink car: Car | undefinedbuild() {Text('user.car: ' + this.car?.brand)}
}@Observed
export class ObservableArray<T> extends Array<T> {constructor(args: T[]) {if (args instanceof Array) {super(...args);} else {super(args)}}
}

@ObservedV2装饰器和@Trace装饰器:类属性变化观测

从 API12 开始,更推荐使用@ObservedV2装饰器和@Trace装饰器装饰类以及类中的属性,来管理状态。

@ObservedV2
class Father {@Trace name: string = "Tom";
}
class Son extends Father {
}
@Entry
@Component
struct Index {son: Son = new Son();build() {Column() {// 当点击改变name时,Text组件会刷新Text(`${this.son.name}`).onClick(() => {this.son.name = "Jack";})}}
}

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

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

相关文章

【leetcode面试经典150题】63. 删除链表的倒数第 N 个结点(C++)

【leetcode面试经典150题】专栏系列将为准备暑期实习生以及秋招的同学们提高在面试时的经典面试算法题的思路和想法。本专栏将以一题多解和精简算法思路为主&#xff0c;题解使用C语言。&#xff08;若有使用其他语言的同学也可了解题解思路&#xff0c;本质上语法内容一致&…

软考141-上午题-【软件工程】-杂题+小结

一、杂题 真题1&#xff1a; 真题2&#xff1a; 真题3&#xff1a; 真题4&#xff1a; 真题5&#xff1a; 真题6&#xff1a; 真题7&#xff1a; 真题8&#xff1a; 真题9&#xff1a; 真题10&#xff1a; 真题11&#xff1a; 真题12&#xff1a; 真题13&#xff1a; 真题14&a…

paddlepaddle-gpu安装

背景 之前安装paddlepaddle-gpu遇到各种问题&#xff0c;安装不成功&#xff0c;之前使用了wsldocker的方式&#xff0c;可查看我之前博客&#xff1a;记录paddlepaddle-gpu安装&#xff0c;这要会导致我整个开发流程比较割裂 cuda版本 强烈推荐cuda11.8&#xff0c;paddlep…

SpringBoot项目错误:找不到主类(解决办法)

清理和重新编译项目即可&#xff0c;在项目中点击右键Maven-Reload project&#xff0c;之后再重新运行就行了

蓝桥杯第十五界软件测试线下省赛题目分析及解决

PS 需要第十五界蓝桥杯被测系统或者功能测试模板、单元测试被测代码、自动化测试被测代码请加&#x1f427;:1940787338 备注&#xff1a;15界蓝桥杯省赛软件测试 题目1&#xff1a;功能测试 题目描述 ​ 某物流公司的货运收费标准根据重量、距离和节假日三个因素来确定。如…

聊聊应用商城评分4.9的Apipost IDEA插件

Apipost Helper&#xff0c;作为IDEA插件&#xff0c;可以快速生成和查询API文档&#xff0c;直观友好地在IDE中调试接口。它简化了开发流程并提升效率&#xff0c;即使新手也能够迅速掌握。Apipost Helper提供了诸多便捷功能&#xff0c;如通过代码查找接口或者通过接口查找代…

UE5、CesiumForUnreal实现建筑白模生成及白模美化功能

1.实现目标 在专栏上篇文章基于GeoJson文件生成城市级白模(本文建筑白模数量12w+)的基础上修改,计算法线和纹理坐标,并基于特定材质进行美化,美化后的白模GIF动图如下所示: 文章目录 1.实现目标2.实现过程2.1 基于Cesium材质美化2.1.1实现原理2.1.2 C++代码2.1.3 蓝图应…

(自学用)正演理论

基于波动方程如何解决数值频散问题——快速正演方法 NAD方法&#xff1a; 怎样离散/逼近高阶偏导数&#xff08;如何采样&#xff09;&#xff1a; 传统方法是用某一点及其周围点的函数f的线性组合来逼近导数。只有函数值&#xff0c;要想提高精度&#xff0c;压制数值频散就必…

【Django】学习笔记

文章目录 [toc]MVC与MTVMVC设计模式MTV设计模式 Django下载Django工程创建与运行创建工程运行工程 子应用创建与注册安装创建子应用注册安装子应用 数据模型ORM框架模型迁移 Admin站点修改语言和时区设置管理员账号密码模型注册显示对象名称模型显示中文App显示中文 视图函数与…

分布式锁实现方案-基于zookeeper的分布式锁实现(原理与代码)

目录 一、基于zookeeper的分布式锁 1.1 基于Zookeeper实现分布式锁的原理 1.1.1 分布式锁特性说明 1.1.1.1 特点分析 1.1.1.2 本质 1.1.2 Zookeeper 分布式锁实现原理 1.1.2.1 Zookeeper临时顺序节点特性 1.1.2.2 Zookeeper满足分布式锁基本要求 1.1.2.3 Watcher机制 …

UE5增强输入系统 Enhanced Input

关键字&#xff1a; Enhanced Input 、 输入、映射、事件、鼠标、键盘、键鼠、动作、Trigger、触发器、 疑问&#xff1a; 新输入系统怎么做一个基础的案例&#xff1f;Trigger修改器中每个项都是什么功能&#xff1f;功能边界问题&#xff1a;如时刻、时段、单次事件、持续事…

Linux驱动开发——(一)设备树的基本属性及其应用

目录 一、常见基本属性 1.1 compatible属性 1.2 status属性 1.3 reg属性 1.4 #address-cells属性和#size-cells属性 二、基本属性在设备树的表现 三、基本属性在驱动代码的表现 3.1 驱动代码 3.2 驱动代码中的OF函数 3.2.1 of_find_node_by_path 3.2.2 of_find_prope…

Unity类银河恶魔城学习记录13-5,6 p146 Delete save file,p147 Encryption of saved data源代码

Alex教程每一P的教程原代码加上我自己的理解初步理解写的注释&#xff0c;可供学习Alex教程的人参考 此代码仅为较上一P有所改变的代码 【Unity教程】从0编程制作类银河恶魔城游戏_哔哩哔哩_bilibili FileDataHandler.cs using System; using System.IO; using UnityEngine; p…

Spring Boot + Thymeleaf 实现的任务发布网站

角色&#xff1a; 管理员雇主雇员 功能 雇主&#xff1a;登录、注册、发布任务、选择中标雇员、评价雇员雇员&#xff1a;登录、注册、查看任务列表、投标任务、收藏任务、完成任务管理员、登录、任务管理、雇主管理、雇员管理 部分功能截图 部署 导入数据库…

.NET 邮件发送 SMTP邮件发送

SMTP&#xff08;Simple Mail Transfer Protocol&#xff09;是用于电子邮件传输的规则集&#xff0c;可以从邮件客户端向接收电子邮件服务器发送、中继或转发邮件。发件人可使用SMTP 服务器来执行发送电子邮件的过程。SMTP服务器则是按照这些规则中转电子邮件的服务器。 IMAP…

视频质量评价 PSNR 算法详细介绍

PSNR PSNR(Peak Signal-to-Noise Ratio,峰值信噪比)是一种常用的评价图像质量的指标,尤其在图像压缩和图像处理领域。它基于最大可能的图像信号功率和图像的噪声功率之间的比率,通常用于衡量图像恢复或图像压缩算法的效果。 原理 PSNR是基于MSE(Mean Squared Error,均…

node-sass报错

node-sass报错 解决方案 有几种解决方案&#xff0c;但感觉都是为了下载vsta_sdk这个工具的。 有的电脑下载C开发程序时可以顺带下载这个插件。 可以直接下载VS之后点击下载C桌面开发&#xff0c;但是有的不行&#xff0c;所以网上也就有另外一种方式&#xff0c;就是下载V…

C# danbooru Stable Diffusion 提示词反推 OpenVINO Demo

C# danbooru Stable Diffusion 提示词反推 OpenVINO Demo 目录 说明 效果 模型信息 项目 代码 下载 说明 模型下载地址&#xff1a;https://huggingface.co/deepghs/ml-danbooru-onnx 效果 模型信息 OVVersion { BuildNumber 2023.1.0-12185-9e6b00e51cd-releases/20…

桌面软件使用到的开源库

想了解一下桌面软件开发中可能使用到的dll库 联想锁屏 libcef-常用概念-框架特点-CSDN博客 libcurl库使用详情、libcurl库的制作-CSDN博客 使用Cef和Qt做一个跨平台的多标签多窗口浏览器_cef3 多个标签-CSDN博客 cef 依赖的文件 libcef - Bigben - 博客园 (cnblogs.com) Q…

Hikyuu 2.0.2 发布,高性能量化交易研究框架

新增特性 历史财务信息入库&#xff0c;对于使用 MySQL 存储&#xff0c;可以直接使用服务端的财务数据&#xff08;之前只能在执行数据下载的机器上获取&#xff09;增加指标 FINANCE 获取相应历史财务数据&#xff0c;具体财务字段信息可通过StockManager.get_history_finan…