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
英文地址,請注明出處:http://en.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;并通…