AWTK-MVVM的一些使用技巧总结(1)

在项目中用了一段时间的AWTK-MVVM框架,由于AWTK-MVVM本身的文档十分欠缺,自己经过一段时间的研究折腾出了几个技巧,在此记录总结。

用fscript启用传统UI代码

AWTK-MVVM里面重新设计了navigator机制,重定位了navigator_to的调用方向,原版AWTK的navigator_to调用很简单,是直接向navigator中请求窗口并对窗口做初始化:

demo.exe!home_page_init(_widget_t * win, void * ctx) Line 25 
demo.exe!navigator_window_init(const char * name, _widget_t * win, void * ctx) Line 10 
demo.exe!navigator_window_open_and_close(const char * name, _widget_t * to_close, void * ctx) Line 32 
demo.exe!navigator_to_with_context(const char * target, void * ctx) Line 51 
demo.exe!navigator_to(const char * target) Line 45 
demo.exe!application_init() Line 56 
demo.exe!wWinMain(HINSTANCE__ * hinstance, HINSTANCE__ * hprevinstance, wchar_t * lpcmdline, int ncmdshow) Line 255 
demo.exe!invoke_main() Line 123 
demo.exe!__scrt_common_main_seh() Line 288 
demo.exe!__scrt_common_main() Line 331 
demo.exe!wWinMainCRTStartup(void * __formal) Line 17 
kernel32.dll!00007fff4c88259d() (Unknown Source:0)
ntdll.dll!00007fff4dc6af78() (Unknown Source:0)

但是MVVM里面就重定义成了对窗口绑定的v-model的初始化,原先的窗口init函数没法直接进入了:

awtk.dll!tk_calloc(unsigned int nmemb, unsigned int size, const char * func, unsigned int line) Line 152 
demo.exe!m_home_create(_navigator_request_t * req) Line 19 
demo.exe!m_home_view_model_create(_navigator_request_t * req) Line 155 
mvvm.dll!view_model_factory_create_model_one(const char * type, _navigator_request_t * req) Line 106 
mvvm.dll!view_model_factory_create_model(const char * type, _navigator_request_t * req) Line 115 
mvvm.dll!binding_context_awtk_create_one_view_model(_view_model_t * parent, const char * type, _navigator_request_t * req) Line 68 
mvvm.dll!binding_context_awtk_create_view_model(_view_model_t * parent, const char * type, _navigator_request_t * req) Line 100 
mvvm.dll!binding_context_awtk_create(_binding_context_t * parent, const char * vmodel, _navigator_request_t * req, _widget_t * widget) Line 1266 
mvvm.dll!ui_loader_mvvm_build_widget(_ui_loader_mvvm_t * loader, _rbuffer_t * rbuffer, _ui_builder_t * builder, unsigned int * cursor, const _value_t * id) Line 515 
mvvm.dll!ui_loader_mvvm_load_a_snippet(_ui_loader_mvvm_t * loader, _rbuffer_t * rbuffer, _ui_builder_t * builder, _widget_t * end_widget) Line 971 
mvvm.dll!ui_loader_mvvm_load_bin(_ui_loader_t * l, const unsigned char * data, unsigned int size, _ui_builder_t * b) Line 1030 
mvvm.dll!ui_loader_mvvm_load(_ui_loader_t * l, const unsigned char * data, unsigned int size, _ui_builder_t * b) Line 1074 
mvvm.dll!ui_loader_mvvm_load_widget_with_parent(_navigator_request_t * req, _widget_t * parent) Line 1124 
mvvm.dll!ui_loader_mvvm_load_widget(_navigator_request_t * req) Line 1091 
mvvm.dll!navigator_handler_awtk_window_open_and_close(_navigator_request_t * req, _widget_t * to_close) Line 217 
mvvm.dll!navigator_handler_awtk_window_open(_navigator_request_t * req) Line 253 
mvvm.dll!navigator_handler_awtk_on_request(_navigator_handler_t * handler, _navigator_request_t * req) Line 321 
mvvm.dll!navigator_handler_on_request(_navigator_handler_t * handler, _navigator_request_t * req) Line 51 
mvvm.dll!navigator_handle_request(_navigator_t * nav, _navigator_request_t * req) Line 90 
mvvm.dll!navigator_to(const char * args) Line 138 
demo.exe!application_init() Line 67 
demo.exe!wWinMain(HINSTANCE__ * hinstance, HINSTANCE__ * hprevinstance, wchar_t * lpcmdline, int ncmdshow) Line 255 
demo.exe!invoke_main() Line 123 
demo.exe!__scrt_common_main_seh() Line 288 
demo.exe!__scrt_common_main() Line 331 
demo.exe!wWinMainCRTStartup(void * __formal) Line 17 
kernel32.dll!00007fff4c88259d() (Unknown Source:0)
ntdll.dll!00007fff4dc6af78() (Unknown Source:0)

有些场景还是需要直接操作界面widget来实现一些效果的,而model文件显然不能也不应该(否则UI和model代码就耦合了)直接获取这些widget,怎么办呢?

AWTK的fscript脚本提供了一个解决方案,步骤如下:

1.在需要使用界面代码的窗口顶部windows标签上,比如home_page.xml,声明一个on:window_open="func_navigator_window_init()"

<window v-model="m_home" name="home_page" on:window_open="func_navigator_window_init()">...
</window>

2.在application.c上注册fscript函数。

ret_t application_init(void) {...fscript_register_func("func_navigator_window_init", func_navigator_window_init);...
}

3.修改common/navigator.c,把navigator_window_init函数从#ifndef WITH_MVVM的宏范围里面提取出来,这是AWTK原版的窗口路由函数,func_navigator_window_init可以直接通过调用这个函数来路由到对应的窗口,缺点就是每次添加新窗口的时候都要手动修改下navigator_window_init内部代码。

common/navigator.c

extern ret_t home_page_init(widget_t* win, void* ctx);ret_t navigator_window_init(const char* name, widget_t* win, void* ctx) {if (tk_str_eq(name, "home_page")) {return home_page_init(win, ctx);}return RET_OK;
}
ret_t func_navigator_window_init(fscript_t *fscript, fscript_args_t *args, value_t *result)
{widget_t *widget = WIDGET(tk_object_get_prop_pointer(fscript->obj, STR_PROP_SELF));widget_t *win = widget_get_window(widget);return navigator_window_init(win->name, win, NULL);
}#ifndef WITH_MVVM
...

这样程序启动的时候,窗口打开会触发fscript函数,在fscript里面能通过fscript自带的对象获取到绑定的widget指针,就能路由到原来的页面init文件了。

跨页面同步数据的model

有些页面, 比如声纳的画面->声纳菜单->某某设置条,几个页面数据来源大量重复, 而且这些页面之间还有线性导航关系,这个时候用AWTK-MVVM原来文档的数据同步的方法显得就有些麻烦了,进页面和出页面都要在给下一个窗口的传递对象中指明传输数据,两个页面就是两处修改,三个页面就是四处修改。

干脆让这些页面都采用同一个model好了,看起来更好处理,但是怎么让这几个页面的model在页面进出时都能共享上一个页面的数据呢?

这个问题之前已在https://blog.csdn.net/Tracker647/article/details/147169060讨论过了,不过最近发现全局model getter的写法有点问题,需要上一个页面手动向下一个页面提供自己当前的model,实际上完全可以改成用一个栈或者链表来维护同类的model。

static std::list<m_sonar_t*> g_model_list;
m_sonar_t* get_m_sonar_model(void) {if(g_model_list.empty()){return NULL;}//栈最顶层为当前的modelreturn g_model_list.back();
}m_sonar_t* m_sonar_create() {m_sonar_t* m_sonar = TKMEM_ZALLOC(m_sonar_t);return_value_if_fail(m_sonar != NULL, NULL);emitter_init(EMITTER(m_sonar));m_sonar_t* prev_model = get_m_sonar_model();//通过AWTK的app conf持久化机制中转数据,实现prev_model到目前model的数据同步m_sonar_config_save(prev_model);m_sonar_config_load(m_sonar);//当前model入栈g_model_list.push_back(m_sonar);return m_sonar;
}ret_t m_sonar_destroy(m_sonar_t* m_sonar) {return_value_if_fail(m_sonar != NULL, RET_BAD_PARAMS);m_sonar_config_save(m_sonar);//退出,当前model出栈g_model_list.remove(m_sonar);m_sonar_t* prev_model = get_m_sonar_model();m_sonar_config_load(prev_model);emitter_deinit(EMITTER(m_sonar));return RET_OK;
}ret_t m_sonar_config_load(m_sonar_t* m_sonar) {m_sonar_set_zoom_mode(m_sonar, app_conf_get_int(CONF_KEY_GAIN_MODE, DEFAULT_VALUE_GAIN_MODE));m_sonar_set_zoom_mode(m_sonar, app_conf_get_int(CONF_KEY_FREQENCY, DEFAULT_VALUE_FREQENCY));m_sonar_set_zoom_mode(m_sonar, app_conf_get_int(CONF_KEY_ZOOM_MODE, DEFAULT_VALUE_ZOOM_MOD));emitter_dispatch_simple_event(EMITTER(m_sonar), EVT_PROPS_CHANGED);return RET_OK;
}ret_t m_sonar_config_save(m_sonar_t* m_sonar) {if(m_sonar == NULL){return RET_FAIL;}app_conf_set_int(CONF_KEY_GAIN_MODE, m_sonar->gain_mode);app_conf_set_int(CONF_KEY_FREQENCY, m_sonar->freqenct);app_conf_set_int(CONF_KEY_ZOOM_MODE, m_sonar->zoom_mode);return RET_OK;
}

这个方法有局限性,只适用于需要同步的这些页面的v-model都是全局的唯一的的情况下, 如果一个页面多次声明同一个v-model就不行了,得另作修改。
而且上一章的model数据同步到这里就不管用了,必须修改,好在这些声纳model只是一层类型不同而已,让声纳model自身的model链表都只进出同类型的声纳model就行了。

写model getter和setter将UI代码和model代码联系到一起

有时候UI交互造成的一些数据变化需要同步到model里面去,而且这些数据变化没办法或者是不想直接在xml上做命令绑定。

比如需要考虑灵活维护,想直接从UI代码接口获取可变量做参数,不想在xml里用给定参数写死的命令绑定,通过用户UI代码事件回调而不是view_model来触发model更新;

<!-- Don't -->
<window v-model="calculator"><edit name="expr" x="c" y="10" w="90%" h="30" focus="true" readonly="true" input_type="custom" text="" tips="expression" v-data:text="{expr}"/><view y="60" x="c" w="90%" h="-60" is_keyboard="true" children_layout="default(r=4,c=4,m=5,s=5)" ><button name="0" text="0" v-on:click="{addChar, Args=0}"/><button name="1" text="1" v-on:click="{addChar, Args=1}"/><button name="2" text="2" v-on:click="{addChar, Args=2}"/><button name="3" text="3" v-on:click="{addChar, Args=3}"/><button name="4" text="4" v-on:click="{addChar, Args=4}"/><button name="5" text="5" v-on:click="{addChar, Args=5}"/><button name="6" text="6" v-on:click="{addChar, Args=6}"/><button name="7" text="7" v-on:click="{addChar, Args=7}"/><button name="8" text="8" v-on:click="{addChar, Args=8}"/><button name="9" text="9" v-on:click="{addChar, Args=9}"/><button name="+" text="+" v-on:click="{addChar, Args=+}"/><button name="-" text="-" v-on:click="{addChar, Args=-}"/><button name="*" text="*" v-on:click="{addChar, Args=*}"/><button name="/" text="/" v-on:click="{addChar, Args=/}"/><button name="=" text="=" v-on:click="{eval}"/><button name="backspace" text="<=" v-on:click="{removeChar}"/></view>
</window>
// Do
calculator.xml
<window v-model="calculator"><edit name="expr" x="c" y="10" w="90%" h="30" focus="true" readonly="true" input_type="custom" text="" tips="expression" v-data:text="{expr}"/><view y="60" x="c" w="90%" h="-60" is_keyboard="true" children_layout="default(r=4,c=4,m=5,s=5)" ><button name="button" text="0" /><button name="button" text="1" /><button name="button" text="2" /><button name="button" text="3" /><button name="button" text="4" /><button name="button" text="5" /><button name="button" text="6" /><button name="button" text="7" /><button name="button" text="8" /><button name="button" text="9" /><button name="button" text="+" /><button name="button" text="-" /><button name="button" text="*" /><button name="button" text="/" /><button name="button" text="=" /><button name="button" text="<=" /></view>
</window>//calculator.c
ret_t on_button_button_click(void* ctx, event_t* e) {pointer_event_t* evt = pointer_event_cast(e);m_calculator *m_calculator = get_m_calculator();return_value_if_fail(m_calculator != NULL, RET_BAD_PARAMS);widget_t *btn = WIDGET(e->target);int index = widget_index_of(btn);// 直接通过界面文字给计算器model提供符号数据char text[32];widget_get_text_utf8(btn, text, sizeof(text));m_calculator_set_expr(m_calculator, text);}static ret_t visit_init_child(void* ctx, const void* iter) {widget_t* win = WIDGET(ctx);widget_t* widget = WIDGET(iter);const char* name = widget->name;// 初始化指定名称的控件(设置属性或注册事件),请保证控件名称在窗口上唯一if (name != NULL && *name != '\0') {if (tk_str_eq(name, "button")) {widget_on(widget, EVT_CLICK, on_button_button_click, win);}}return RET_OK;
}

又或者菜单几十个单选按钮,按钮功能大致相同,xml上几十个按钮标签,与其一个个在xml写命令绑定(这样维护性很差),不如直接给这些按钮设置相同的名字(可以设置相同名字来遍历控件设置同一个回调,QT上好像做不到这么方便),然后在visit_init_child函数上遍历这些控件注册同一个回调,然后给这些按钮设置一个类似唯一id的自定义属性(或者干脆就是按钮上的文本)用于分支判断,在回调中决定设置哪一个数据;

怎么做?

方法很简单,手动实现这些model的getter和setter函数,setter属性完成之后,通过emitter_dispatch_simple_event来通知模型更新界面。

<view name="v_setting_zoom_mode" style="onwa_setting" x="c" y="m" w="562" on:key_down="menu_rbtn_set_scroll_view(widget_get('self','name'))" h="184"><label name="setting_title" h="34" style="setting_title" focusable="true" x="0" y="0" w="562" tr_text="Zoom mode"/><view name="radio_view2_2" h="150" children_layout="default(c=2,r=2,s=10)" style:normal:bg_color="#00244400" x="0" y="b:0" w="562"><!-- 设定自定义的key属性 --><radio_button name="radio_button" style="onwa_radio2" key="zoom_mode" v-data:value="{zoom_mode==0}" focusable="true" value="true" tr_text="No Zoom"/><radio_button name="radio_button" style="onwa_radio2" key="zoom_mode"  v-data:value="{zoom_mode==1}" focusable="true" tr_text="Bottom Lock"/><radio_button name="radio_button" style="onwa_radio2" key="zoom_mode" v-data:value="{zoom_mode==2}" focusable="true"  tr_text="Auto"/><radio_button name="radio_button" style="onwa_radio2" key="zoom_mode" v-data:value="{zoom_mode==3}" focusable="true"  tr_text="Manual"/></view>
</view>
ret_t on_radio_button_click(void* ctx, event_t* e) {pointer_event_t* evt = pointer_event_cast(e);m_sonar_t *m_sonar = get_m_sonar_model();return_value_if_fail(m_sonar != NULL, RET_BAD_PARAMS);int sonar_mode = m_sonar->sonar_mode;widget_t *btn = WIDGET(e->target);int index = widget_index_of(btn);//获取控件上自定义的key属性const char *key = widget_get_prop_str(btn, "key", "unknown");m_sonar_t* m_sonar = get_m_sonar_model();if (index >= 0) {// Call the m_sonar function with the title and button indexm_sonar_set_prop_int(m_sonar, key, index);}}ret_t m_sonar_set_prop_int(m_sonar_t* m_sonar, const char* key, int value) {if (!m_sonar) {printf("Error: Could not get m_sonar model\r\n");return RET_FAIL;}if (tk_str_end_with(key, CONF_KEY_GAIN_MODE)) {m_sonar_set_gain_mode(m_sonar, value);} else if (tk_str_end_with(key, CONF_KEY_FREQUENCY)) {m_sonar_set_frequency(m_sonar, value);} else if (tk_str_end_with(key, CONF_KEY_ZOOM_MODE)) {m_sonar_set_zoom_mode(m_sonar, value);} ...// 设置完成后,同步modelemitter_dispatch_simple_event(EMITTER(m_sonar), EVT_PROPS_CHANGED);return;
}

动态加载绑定model的UI片段

在AWTK,可以通过navigator_request_t给model设置初始化的参数,但是设置初始化参数的场景AWTK-MVVM原文档里只写明了从一个窗口导航到另一个窗口,对于重复的UI片段就语焉不详了,而如果遇到了一个页面就有这些重复的UI片段,外加这些UI片段都绑定了某个同样的model的场景呢?

项目开发就遇到了这种情况,声纳本身有多个类型,海图机产品有一种能把这些不同的声纳类型画面都显示出来的分屏模式,最多支持3个不同类型声纳的同时显示,要命的是,由于这些声纳类型的参数和模型逻辑高度重合,我都是用的同一个模型来处理的,没能把它们分开(一个声纳模型有几十个参数设置,总共3个类型,要分开就是两百多个参数,十分臃肿了,倒霉的是AWTK-MVVM没有一种类似于继承的机制能让派生类复用父类的数据和函数去做代码绑定),只通过导航到某个类型单个声纳显示的窗口时,通过指定初始化参数来确定不同的声纳类型。

最简单直接的方法就是,一个分屏就是一个model绑定的UI片段,窗口三个分屏就是窗口里面有3个model, 这样可以直接使用原来单屏模式就写好的model代码。

但是业务限制,分屏的数量和各个分屏的模式都不是固定的,这部分的UI只能在代码中动态生成。

对于UI复用,AWTK有提供一个组件机制(本质是简单粗暴的include替换)来实现,通过ui_loader_load_widget_with_parent(组件xml名,父widget)可把对应的组件加载到UI中, 但是接口是属于原版AWTK的,并没有考虑到mvvm的绑定机制,那么这种API有没有MVVM的版本?

查找AWTK-MVVM代码,还真发现有这么一个API:

/*** @method ui_loader_mvvm_load_widget_with_parent* 加载导航请求指定的控件,并指定父控件对象。* @param {navigator_request_t*} req 导航请求。* @param {widget_t*} parent 父控件对象。** @return {widget_t*} 控件对象。*/
widget_t* ui_loader_mvvm_load_widget_with_parent(navigator_request_t* req, widget_t* parent);

声纳模式m_sonar是通过mode来区分不同类型的,那么对于分屏同时显示多个类型的声纳,就可以这么处理:

// 伪代码,看看理解就行了,可以自己试试
sonar_combo.xml
<view v-model="m_sonar"></view>split_window.xml
<view name="combo_views" x="0" y="0" w="800" h="480"><!-- 假如要动态生成下面三个标签: --><view v-model="m_sonar"></view><view v-model="m_sonar"></view><view v-model="m_sonar"></view>
</view>split_window.c
ret_t init_window(widget_t *win)
{widget_t *combo_views = widget_lookup(win, "combo_views", TRUE);...for(int i = 0; i < split_num; i++){navigator_request_t *req = navigator_request_create("sonar_combo", NULL);tk_object_set_prop_pointer(TK_OBJECT(req), "sonar_mode", get_sonar_mode(i));widget_t *combo_view = ui_loader_mvvm_load_widget_with_parent(req, combo_views);return_value_if_fail(combo_view != NULL, RET_BAD_PARAMS);}return RET_OK;
}

这种方法也有缺陷,如果加载的组件标签里面有来自其他model的数据/命令绑定,那么就算当前窗口顶层已经声明了这个model,也是没法绑定的。

修改已经加载了的UI片段的绑定属性

研究AWTK-MVVM代码的的另一个小收获,可以用于解决上面提到的顶层model属性没法绑定的问题。

直接放测试代码,另外也可以看mvvm控件的binding_context_test.cc来了解awtk-mvvm怎么实现绑定。

static binding_context_t* binding_context_create(binding_context_t* parent, const char* vmodel,widget_t* widget) {navigator_request_t* req = navigator_request_create("test", NULL);binding_context_t* ctx = binding_context_awtk_create(parent, vmodel, req, widget);tk_object_unref(TK_OBJECT(req));return ctx;
}static binding_rule_t* binding_rule_create(widget_t* widget, const char* name, const char* val) {binding_rule_t* rule = binding_rule_parse(name, val, widget->vt->inputable);rule->widget = widget;return rule;
}void mvvm_test(widget_t* win, void* ctxx){binding_context_t* ctx;binding_rule_t* rule;ctx = widget_get_prop_pointer(win, WIDGET_PROP_V_MODEL);return_if_fail(ctx != NULL);widget_t *slider = widget_lookup(win, "slider", TRUE);return_if_fail(slider != NULL);rule = binding_rule_create(slider, "v-data:value", "{conf_test.value, Trigger=Changing}");tk_object_set_prop_bool(TK_OBJECT(rule), BINDING_RULE_PROP_INITED, TRUE);binding_context_bind_data(ctx, rule);binding_context_set_bound(ctx, TRUE);// 必须声明这个,不然model的数据没法更新到viewbinding_context_update_to_view(ctx);
}
/*** 初始化窗口*/
ret_t test_mvvm_dynamic_load_init(widget_t* win, void* ctx) {(void)ctx;return_value_if_fail(win != NULL, RET_BAD_PARAMS);widget_foreach(win, visit_init_child, win);mvvm_test(win, ctx);return RET_OK;
}

binding_context_t可以理解为对xml上声明的v-model功能的实际对象,内部对于数据绑定和命令绑定各自维护了一套链表。

对于数据绑定,当数据事件发生时,就会通过查找链表data_binding来找到绑定属性指定的控件,并更改控件数据。

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

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

相关文章

openwrt使用quilt工具制作补丁

前言&#xff1a;简单聊一下为什么需要制作补丁&#xff0c;因为openwrt的编译是去下载很多组件放到dl目录下面&#xff0c;这些组件都是压缩包。如果我们要修改这些组件里面的源码&#xff0c;就需要对这些组件打pacth&#xff0c;也就是把我们的差异点在编译的时候合入到对应…

强化学习 (1)基本概念

grid-world example 一个由多个格子组成的二维网格 三种格子&#xff1a;accessible可通行的&#xff1b; forbidden禁止通行的&#xff1b; target目标 state状态 state是智能体相对于环境的状态&#xff08;情况&#xff09; 在grid-world example里&#xff0c;state指的…

【Typst】纵向时间轴

概述 6月10日实验了一个纵向时间轴排版效果&#xff0c;当时没有做成单独的模块&#xff0c;也存在一些Bug。 今天(6月29日)在原基础上进行了一些改进&#xff0c;并总结为模块。 目前暂时发布出来&#xff0c;可用&#xff0c;后续可能会进行大改。 使用案例 导入模块使用…

【Visual Studio Code上传文件到服务器】

在 Visual Studio Code (VS Code) 中上传文件到 Linux 系统主要通过 SSH 协议实现&#xff0c;结合图形界面&#xff08;GUI&#xff09;或命令行工具操作。以下是具体说明及进度查看、断点续传的实现方法&#xff1a; ⚙️ 一、VS Code 上传文件到 Linux 的机制 SSH 远程连接 …

手机控车一键启动汽车智能钥匙

手机一键启动车辆的方法 手机一键启动车辆是一种便捷的汽车启动方式&#xff0c;它通过智能手机应用程序实现对车辆的远程控制。以下是详细的步骤&#xff1a; 完成必要的认证与激活步骤。打开手机上的相关移动管家手机控车APP&#xff0c;并与车载蓝牙建立连接。在APP的主界面…

基于深度学习的语音增强技术:时间增强多尺度频域卷积网络模型解析

基于深度学习的语音增强技术&#xff1a;时间增强多尺度频域卷积网络模型解析 近年来&#xff0c;随着语音处理技术的不断发展&#xff0c;语音增强&#xff08;Speech Enhancement&#xff09;逐渐成为研究热点。语音增强的主要目标是通过消除噪声和改善信噪比来提高语音质量…

计算机组成原理-数据表示与运算(三)

### 文字提取结果&#xff1a; #### 题目内容&#xff1a; 34. 【2009 统考真题】浮点数加、减运算过程一般包括对阶、尾数运算、规格化、舍入和判断溢出等步骤。设浮点数的阶码和尾数均采用补码表示&#xff0c;且位数分别为 5 和 7&#xff08;均含 2 位符号位&#xff09;。…

Learning Fully Convolutional Networks for Iterative Non-blind Deconvolution论文阅读

Learning Fully Convolutional Networks for Iterative Non-blind Deconvolution 1. 研究目标与实际问题1.1 研究目标1.2 实际意义2. 创新方法与模型设计2.1 核心框架:迭代式梯度域处理2.1.1 模型架构2.2 关键技术实现2.2.1 梯度域去噪网络2.2.2 解卷积模块(核心公式实现)2.…

Vue3——组件传值

父传子 props ——最推荐的方法&#xff08;TOP1级别&#xff09; 父组件文件 <sidebar :text"textname" ></sidebar> //父组件通过 :text 将父组件的数据textname传递给子组件 const textname:Ref<dataFather[]> ref([{name:刘亦菲,age:18 },…

DOP数据开放平台(真实线上项目)

什么是数据开放平台&#xff1f; 数据开放平台是一种通过公开应用程序编程接口&#xff08;API&#xff09;或结构化数据&#xff0c;允许第三方开发者或机构访问、使用和共享数据的平台‌&#xff0c;旨在促进数据流通、打破信息孤岛并激发创新应用。 DOP数据开放平台简单演示…

InfluxDB 3 Core数据库管理指南:从概念到实操的完整流程

本文深入解析InfluxDB 3 Core的数据库管理核心概念&#xff0c;涵盖数据库与历史版本的兼容性差异、关键限制&#xff08;数据库/表/列数量&#xff09;、以及创建/查看/删除数据库的完整命令行操作。通过结构化流程和实用建议&#xff0c;帮助用户高效管理时序数据存储&#x…

JVM(11)——详解CMS垃圾回收器

CMS (Concurrent Mark-Sweep) 垃圾回收器。它是 JDK 1.4 后期引入&#xff0c;并在 JDK 5 - JDK 8 期间广泛使用的一种以低停顿时间 (Low Pause Time) 为主要目标的老年代垃圾回收器。它是 G1 出现之前解决 Full GC 长停顿问题的主要方案。 一、CMS 的设计目标与定位 核心目标…

使用Java和iText库填充PDF表单域的完整指南

PDF表单是企业和机构常用的数据收集工具&#xff0c;而通过编程方式自动填充PDF表单可以大大提高工作效率。本文将详细介绍如何使用Java和iText库来实现PDF表单的自动化填充。 为什么选择iText库&#xff1f; iText是一个强大的PDF操作库&#xff0c;具有以下优势&#xff1a…

跟着AI学习C#之项目实践Day6

&#x1f4c5; Day 6&#xff1a;实现文章搜索功能&#xff08;Search System&#xff09; ✅ 今日目标&#xff1a; 实现按 标题、内容、作者 搜索文章使用 LINQ 构建动态查询条件添加搜索框 UI 界面可选&#xff1a;使用全文搜索优化&#xff08;如 SQL Server 全文索引&am…

Learning to Prompt for Continual Learning

Abstract 持续学习背后的主流范式是使模型参数适应非平稳数据分布&#xff0c;其中灾难性遗忘是核心挑战。典型方法依赖于排练缓冲区或测试时已知的任务标识来检索已学知识并解决遗忘问题&#xff0c;而这项工作提出了一种持续学习的新范式&#xff0c;旨在训练一个更简洁的记…

【论文阅读笔记】知网SCI——基于主成分分析的空间外差干涉数据校正研究

论文词条选择 —— 知网 【SCI】【数据分析】 题目&#xff1a;基于主成分分析的空间外差干涉数据校正研究 原文摘要&#xff1a; 空间外差光谱技术(SHS)是一种新型的高光谱遥感探测技术&#xff0c;被广泛应用于大气观测、天文遥感、物质识别等领域。通过空间外差光谱仪获取…

如何用VS Code、Sublime Text开发51单片机

文章目录 一、前置工作二、VS Code2.1 Code Runner配置2.2 编译快捷键 三、Sublime Text3.1 Build System创建3.2 编译快捷键 四、使用STC-ISP下载代码到单片机 使用VS Code开发51单片机的好处自不必多说&#xff0c;直接进入正题。本博客的目标是让你能够使用VS Code或者Subli…

信息抽取数据集全景分析:分类体系、技术演进与挑战_DEEPSEEK

信息抽取数据集全景分析&#xff1a;分类体系、技术演进与挑战 摘要 信息抽取&#xff08;IE&#xff09;作为自然语言处理的核心任务&#xff0c;是构建知识图谱、支持智能问答等应用的基础。近年来&#xff0c;随着深度学习技术的发展和大规模预训练模型的兴起&#xff0c;…

利用 Python 脚本批量查找并删除指定 IP 的 AWS Lightsail 实例

在 AWS Lightsail 管理中&#xff0c;随着实例数量的增多&#xff0c;我们常常会遇到这样一个问题&#xff1a; “我知道某个公网 IP 地址&#xff0c;但不知道它关联的是哪台实例。” 或者&#xff1a; “我有一批老旧的实例只知道 IP&#xff0c;需要一键定位并选择删除。…

CompletableFuture 深度解析

本文将探讨 Java 8 引入的 CompletableFuture&#xff0c;一个在异步编程中实现非阻塞、可组合操作的强大工具。我们将从 CompletableFuture 的基本概念、与传统 Future 的区别、核心 API 用法&#xff0c;到复杂的链式调用、组合操作以及异常处理进行全面解析&#xff0c;并通…