一区二区三区三上|欧美在线视频五区|国产午夜无码在线观看视频|亚洲国产裸体网站|无码成年人影视|亚洲AV亚洲AV|成人开心激情五月|欧美性爱内射视频|超碰人人干人人上|一区二区无码三区亚洲人区久久精品

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

如何利用ChatGPT快速實(shí)現(xiàn)一個(gè)控制臺(tái)進(jìn)度條小工具?

CPP開發(fā)者 ? 來源:CppMore ? 2024-01-18 13:41 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

本篇講解如何利用 ChatGPT 快速實(shí)現(xiàn)一個(gè)控制臺(tái)進(jìn)度條小工具,相比單純介紹某些特性,此種方式涉及知識(shí)的綜合運(yùn)用,也順便談?wù)勅绾谓Y(jié)合 AI 進(jìn)行編程。

問題描述

控制臺(tái)程序執(zhí)行一些耗時(shí)任務(wù)時(shí),需要向用戶顯示當(dāng)前任務(wù)執(zhí)行的進(jìn)度,以提供清晰的感知。比如一個(gè)下載程序,通過進(jìn)度條便能告知用戶當(dāng)前的下載進(jìn)度。

進(jìn)度條可以單獨(dú)顯示,也可以在程序輸出的最下方顯示,下圖是一個(gè)示例。

這是一種單控制條需求,執(zhí)行任務(wù),顯示進(jìn)度,輸出流依舊是從上至下依序進(jìn)行,適合單線程的場(chǎng)景。

多控制條顯示的效果如下圖,實(shí)現(xiàn)要更加復(fù)雜一些,本文暫時(shí)不會(huì)涉及該部分。

e338dba2-b5b5-11ee-8b88-92fbcf53809c.gif

初步分析

控制臺(tái)上顯示的這種符號(hào),稱為 ASCII Art,就是以字符構(gòu)建的某種圖案,不借助圖片,也能夠有一個(gè)生動(dòng)的展示效果,比如下圖這種。

e36393e2-b5b5-11ee-8b88-92fbcf53809c.png

因此控制臺(tái)進(jìn)度條也稱為 ASCII Progress Bar,通過字符圖案來模擬進(jìn)度條的顯示,通常分為已完成部分及未完成部分,使用兩個(gè)字符,動(dòng)態(tài)改變字符數(shù)量,便能夠模擬出一個(gè)進(jìn)度條。

模擬方式既定,下一問題在于進(jìn)度條刷新。如果每更新一次進(jìn)度,便輸出一個(gè)字符圖案,那么屏幕上將滿是進(jìn)度條,需要針對(duì)一條進(jìn)度條,不斷刷新其數(shù)據(jù),而非每次都輸出一條新的。具體實(shí)現(xiàn)時(shí),便需要尋找定位進(jìn)度條的方法,每次清除當(dāng)前數(shù)據(jù),重新打印新的數(shù)據(jù),視覺上顯示的是連續(xù)動(dòng)畫。

刷新思路亦成,接著的問題在于如何在進(jìn)度條之上插入其他輸出。進(jìn)度條始終顯示在用戶輸出下方,因此每次用戶輸出時(shí),可以立即定位到進(jìn)度條,定位之后清除當(dāng)前進(jìn)度條,輸出用戶內(nèi)容,再重新打印進(jìn)度條,便能夠達(dá)到這一效果。

細(xì)枝末節(jié),便需依賴具體的實(shí)現(xiàn)手法。

借助 ChatGPT 快速構(gòu)建基本代碼

需求明確,思路既定,接著便要著手設(shè)計(jì)庫(kù)的結(jié)構(gòu)和細(xì)節(jié),實(shí)現(xiàn)細(xì)節(jié)這部分代碼無需從零編寫,可以借助 AI 快速生成。

我們所需做的,就是詳細(xì)描述需求,以及預(yù)想的思路,讓 ChatGPT 生成代碼,驗(yàn)證是否符合需求,若不符合,糾正錯(cuò)誤,讓它再次生成,不斷重復(fù)這個(gè)過程,直到基本滿足期待的效果。如果一開始的效果就完全牛頭不對(duì)馬嘴,那也可以讓它基于 Python 生成,等到效果尚可,再讓它把代碼轉(zhuǎn)換成 C++ 代碼。

經(jīng)過多次調(diào)教,最終生成的代碼如下:

 1#include
 2#include
 3#include
 4
 5voidprint_progress_bar(intiteration,inttotal,intbar_length=50){
 6floatprogress=static_cast(iteration)/total;
 7intarrow_length=static_cast(bar_length*progress);
 8intspaces=bar_length-arrow_length;
 9
10std::cout<

生成的最終代碼基本滿足需求,能夠按預(yù)期顯示進(jìn)度條。

對(duì)于進(jìn)度條,生成的代碼使用 - 表示完成部分, 表示未完成部分,每隔 100ms 刷新一次進(jìn)度數(shù)據(jù)。進(jìn)度條長(zhǎng)度固定為 50,依據(jù)當(dāng)前進(jìn)度和控制條長(zhǎng)度,動(dòng)態(tài)計(jì)算已完成和未完成字符長(zhǎng)度,通過循環(huán)打印出來。

而刷新顯示,這也是調(diào)教時(shí)最麻煩的一個(gè),起初生成的代碼一直會(huì)不斷打印控制條,最終告訴它使用 ANSI escape codes 才糾正為 ?33[2K 。

這個(gè)轉(zhuǎn)義碼可以分為兩部分,?33[2K 和 。后者比較常見,就是將光標(biāo)移動(dòng)到當(dāng)前行的開頭,而前者的作用是清除當(dāng)前光標(biāo)所在行,其實(shí)包含三個(gè)參數(shù),意義分別為:

0K:清除從光標(biāo)所在位置到行尾的內(nèi)容;

1K:清除從行首到光標(biāo)所在位置的內(nèi)容;

2K:清除整行內(nèi)容。

組合起來,作用是每次輸出用戶內(nèi)容(用戶內(nèi)容最后需要換行,否則最后一行內(nèi)容可能會(huì)被清除)時(shí),先清除最后一行內(nèi)容,再將光標(biāo)移至行首,達(dá)到的效果就是清除當(dāng)前進(jìn)度條并回到行首。如果僅僅將光標(biāo)移至行首,而不清除當(dāng)前行,后面打印的內(nèi)容若是比原有內(nèi)容(進(jìn)度條)長(zhǎng)度短,便會(huì)留下原有內(nèi)容的殘余部分,致界面混亂。

用戶的最后一行輸出是換行符,生成代碼利用 將光標(biāo)移至行首,再輸出進(jìn)度條,其實(shí)完全多余,光標(biāo)本來就在行首,每次打印的進(jìn)度條本身就在用戶內(nèi)容的下方。

封裝成類,微調(diào)代碼

ChatGPT 生成的代碼,雖然能夠達(dá)到效果,但最多只有六十分,只是快速實(shí)現(xiàn)細(xì)節(jié),省些力氣而已,仍需要進(jìn)一步微調(diào)。

構(gòu)建一個(gè) cpp-progress-bar 項(xiàng)目,以 Header-only 的形式添加一個(gè) progress_bar 類,將變化點(diǎn)全部封裝起來。

首先,將所有可定制的數(shù)據(jù),全部抽離出來。比如控制條長(zhǎng)度、數(shù)據(jù)長(zhǎng)度、已完成字符和未完成字符等等。

 1classprogress_bar{
 2public:
 3progress_bar(inttotal,intbar_length=50,std::ostream&os=std::cout)
 4:m_bar_length{bar_length}
 5,m_data_length{total}
 6,m_done_char{'#'}
 7,m_undone_char{'.'}
 8,m_opening_bracket{'['}
 9,m_closing_bracket{']'}
10,m_os{os}
11,m_desc{"Progress"}
12{}
13
14autobar_length(intlen)->void{
15m_bar_length=len;
16}
17
18autobar_length()const->int{
19returnm_bar_length;
20}
21
22//...
23
24private:
25intm_bar_length;//控制條長(zhǎng)度
26intm_data_length;//數(shù)據(jù)長(zhǎng)度
27charm_done_char;//已完成字符
28charm_undone_char;//未完成字符
29charm_opening_bracket;//開括號(hào)
30charm_closing_bracket;//閉括號(hào)
31std::ostream&m_os;//輸出流
32std::stringm_desc;//控制條描述信息
33};

其次,將「清除并回到行首」和「輸出控制條」這兩部分抽離出來,它們一個(gè)在用戶內(nèi)容之前輸出,一個(gè)在之后輸出,于是增加一個(gè) before() 和 after() 接口來表示。

 1autoprogress_bar::before()const->void{
 2m_os<void{
 6autoprogress=static_cast(cur)/m_data_length;
 7autofinished_length=static_cast(progress*m_bar_length);
 8
 9m_os<

最后,以一個(gè) update() 接口來調(diào)用以上這兩個(gè)接口,更新進(jìn)度條。

 1autoprogress_bar::update(intcur)const->void{
 2this->before();
 3this->after(cur);
 4}
 5
 6autoprogress_bar::update(intcur,std::invocableautofn)const->void{
 7this->before();
 8std::invoke(fn,cur);
 9this->after(cur);
10}

提供兩個(gè)重載版本,以應(yīng)對(duì)無用戶輸出時(shí)的變化性。

現(xiàn)在,便可以這樣使用:

 1intmain(){
 2inttotal=50;
 3cpb::progress_barprogress(total);
 4for(autoi:std::iota(0,total)){
 5//Updatetheprogressbar
 6progress.update(i+1,[](intv){
 7std::cout<

這便是一個(gè)輕量級(jí)庫(kù)的雛形。

優(yōu)化實(shí)現(xiàn)

雛形已成,但實(shí)現(xiàn)方面依舊是 ChatGPT 的實(shí)現(xiàn),盡管只有幾行代碼,生成的代碼還是相當(dāng)丑陋而低效。到這一步,便要開始替換生成的實(shí)現(xiàn)。

也就是說,ChatGPT 生成的代碼僅僅是能跑,雛形交給它來快速生成,后續(xù)的封裝和優(yōu)化工作則全由自己來做,替換所有低效實(shí)現(xiàn)。

當(dāng)前留下的生成代碼只有生成已完成字符和未完成字符,這部分可以使用 C++20 Fomatting Library 進(jìn)行優(yōu)化,簡(jiǎn)化代碼。

1autoprogress_bar::after(intcur)const->void{
2autoprogress=static_cast(cur)/m_data_length;
3autofinished_length=static_cast(progress*m_bar_length);
4
5autoprogress_info=std::format("Progress:[{3:>3}%][{0:#^{1}}{0:.^{2}}]","",finish_length,bar_length-finish_length,static_cast(progress*100));
6m_os<

通過優(yōu)化,核心代碼只剩下一行,這就是 fmt 庫(kù)的強(qiáng)大所在。

但是,格式化時(shí)沒有動(dòng)態(tài)指定填充字符,這是因?yàn)?fmt 暫時(shí)不支持這種代碼:

1//"====="
2std::cout<

由于會(huì)產(chǎn)生復(fù)雜的開銷,默認(rèn)的 std::formatter 并不支持動(dòng)態(tài)指定填充字符。

可以通過定制來手動(dòng)實(shí)現(xiàn),代碼如下:

 1namespacecpb{
 2
 3structfill{
 4charvalue;
 5intwidth;
 6};
 7
 8}//namespacecpb
 9
10
11template<>
12structstd::formatter{
13constexprautoparse(format_parse_context&ctx){returnctx.begin();}
14
15autoformat(constcpb::fill&f,auto&ctx)const{
16returnstd::fill_n(ctx.out(),f.width,f.value);
17}
18};

別看僅有幾行代碼,fmt 的定制存在巨坑。

這種實(shí)現(xiàn)是錯(cuò)誤的:

 1namespacecpb
 2{
 3structfill{
 4charvalue;
 5intwidth;
 6};
 7}
 8
 9template<>
10structstd::formatter{
11constexprautoparse(format_parse_context&ctx){returnctx.begin();}
12
13autoformat(constcpb::fill&f,auto&ctx){
14returnstd::fill_n(ctx.out(),f.width,f.value);
15}
16};

這種實(shí)現(xiàn)也是錯(cuò)誤的:

 1namespacecpb
 2{
 3structfill{
 4charvalue;
 5intwidth;
 6};
 7}
 8
 9template<>
10structstd::formatter{
11autoparse(format_parse_context&ctx){returnctx.begin();}
12
13autoformat(constcpb::fill&f,auto&ctx)const{
14returnstd::fill_n(ctx.out(),f.width,f.value);
15}
16};

這種實(shí)現(xiàn)還是錯(cuò)誤的:

 1namespacecpb
 2{
 3structfill{
 4charvalue;
 5intwidth;
 6};
 7}
 8
 9template<>
10structstd::formatter{
11constexprautoparse(format_parse_context&ctx){returnctx.begin();}
12
13autoformat(constcpb::fill&f,format_parse_context&ctx)const{
14returnstd::fill_n(ctx.out(),f.width,f.value);
15}
16};

這種實(shí)現(xiàn)依舊是錯(cuò)誤的:

 1structfill{
 2charvalue;
 3intwidth;
 4};
 5
 6template<>
 7structstd::formatter{
 8constexprautoparse(format_parse_context&ctx){returnctx.begin();}
 9
10autoformat(constfill&f,auto&ctx)const{
11returnstd::fill_n(ctx.out(),f.width,f.value);
12}
13};

尤其是最后一個(gè),因?yàn)闃?biāo)準(zhǔn)存在 std::fill,此時(shí)特化 std::formatter 中使用的 fill 是 std::fill,而不是自己定義的 fill,所以必須將其置入命名空間內(nèi)。

由此也可見,基于特化的這種定制方式非常不友好,出現(xiàn)錯(cuò)誤較為莫名其妙。

有了這個(gè)定制,便可以使用 fill 來進(jìn)一步簡(jiǎn)化原有實(shí)現(xiàn):

1autoafter(intcur)const->void{
2autoprogress=static_cast(cur)/m_data_length;
3autofinished_length=static_cast(progress*m_bar_length);
4
5autoprogress_info=std::format("{}:[{:>3}%]{}{}{}{}",m_desc,static_cast(progress*100),m_opening_bracket,fill{m_done_char,finished_length},fill{m_undone_char,m_bar_length-finished_length},m_closing_bracket);
6m_os<

現(xiàn)在這個(gè)實(shí)現(xiàn)便精簡(jiǎn)多了。

AOP 優(yōu)化

當(dāng)前接口存在 before() 和 after(),這不正是 AOP 要解決的問題,我們幾年前也使用 C++20 實(shí)現(xiàn)過一個(gè)輕量級(jí)的 AOP 庫(kù),此處可以基此稍微擴(kuò)展一下,滿足當(dāng)前需求。

于是實(shí)現(xiàn)進(jìn)一步簡(jiǎn)化為:

1autoupdate(intcur)const->void{
2aopcxx::make_aspect(this,cur);
3}
4
5autoupdate(intcur,std::invocableautofn)const->void{
6aopcxx::make_aspect(this,fn,cur);
7}

原理幾年前便已講過,擴(kuò)展的源碼可以自行去看。

示例

至此,三兩下庫(kù)已成型,可以這樣使用:

 1intmain(){
 2inttotal=50;
 3cpb::progress_barprogress(total);
 4for(autoi:std::iota(0,total)){
 5//Updatetheprogressbar
 6progress.update(i+1,[](intv){
 7std::cout<

如果想親自測(cè)試一下代碼或查看源碼,可以通過以下指令:

1gitclonehttps://github.com/lkimuk/cpp-progress-bar.git
2mkdirbuild&&cdbuild
3cmake..
4make
5./test

總結(jié)

思路想法確定,借助 ChatGPT 快速生成代碼雛形,能夠加快開發(fā)速度,讓你避開細(xì)枝末節(jié),快速讓目標(biāo)運(yùn)行起來。

在此基礎(chǔ)上,自己只需專注代碼優(yōu)化,將精力放在核心功能上。

盡管后期可能會(huì)替換掉 AI 生成的所有實(shí)現(xiàn),但也要事半功倍。先快速讓程序跑起來,再去優(yōu)化局部細(xì)節(jié),比完全從局部細(xì)節(jié)構(gòu)建起整體結(jié)構(gòu),要高效得多。

大家可以嘗試使用起來。





審核編輯:劉清

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • ASCII
    +關(guān)注

    關(guān)注

    5

    文章

    172

    瀏覽量

    35773
  • C++語(yǔ)言
    +關(guān)注

    關(guān)注

    0

    文章

    147

    瀏覽量

    7259
  • python
    +關(guān)注

    關(guān)注

    56

    文章

    4825

    瀏覽量

    86444
  • ChatGPT
    +關(guān)注

    關(guān)注

    29

    文章

    1589

    瀏覽量

    8945

原文標(biāo)題:借助 ChatGPT 快速實(shí)現(xiàn)一個(gè)輕量級(jí)的控制臺(tái)進(jìn)度條庫(kù)

文章出處:【微信號(hào):CPP開發(fā)者,微信公眾號(hào):CPP開發(fā)者】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    如何使用Github上的advcpmv來實(shí)現(xiàn)Linux中的cp和mv命令的進(jìn)度條

    由于 cp 和 mv 命令都是屬于 coreutils 工具包下的,因此我們的主要操作就是在編譯 coreutils 的時(shí)候加入補(bǔ)丁從而實(shí)現(xiàn)進(jìn)度條功能。
    的頭像 發(fā)表于 07-23 08:27 ?2022次閱讀

    如何顯示個(gè)vi程序運(yùn)行的進(jìn)度條

    程序調(diào)用mtalab腳本節(jié)點(diǎn),運(yùn)行很慢,想設(shè)計(jì)個(gè)進(jìn)度條,實(shí)時(shí)顯示運(yùn)行進(jìn)度,求各位大神幫忙
    發(fā)表于 04-01 13:53

    labview的進(jìn)度條

    這是個(gè)labview的進(jìn)度條程序,比較好用
    發(fā)表于 08-04 14:30

    求教利用Labview和其它語(yǔ)言混合編程如何設(shè)計(jì)個(gè)弧形進(jìn)度條?

    1.利用Labview和其它語(yǔ)言混合編程如何設(shè)計(jì)個(gè)弧形進(jìn)度條?2.求自定義控件Demo
    發(fā)表于 03-10 18:25

    labview進(jìn)度條

    我用labview2017做了個(gè)文件解壓和復(fù)制的vi,解壓過程中不知道真實(shí)的解壓進(jìn)度,怎么才能做一個(gè)真實(shí)的進(jìn)度條,要真是的,不是自己規(guī)定的
    發(fā)表于 04-26 09:10

    labview實(shí)現(xiàn)進(jìn)度條

    進(jìn)度條
    發(fā)表于 03-25 17:06

    怎么設(shè)置進(jìn)度條?

    RT!比如 我創(chuàng)建個(gè)隨意長(zhǎng)度的進(jìn)度條然后我知道個(gè)文件的大小 當(dāng)把這個(gè)文件里的數(shù)據(jù)讀完后進(jìn)度條
    發(fā)表于 08-22 04:35

    HarmonyOS實(shí)戰(zhàn)——ProgressBar進(jìn)度條組件基本使用

    ProgressBar案例——點(diǎn)擊進(jìn)度條增加實(shí)際進(jìn)度值需求分析:每單擊進(jìn)度條組件時(shí),進(jìn)度條就加 5% 的
    發(fā)表于 09-22 23:31

    分享個(gè)開源的ESP32 物聯(lián)網(wǎng)小工具

    描述ESP32 物聯(lián)網(wǎng)小工具這個(gè)小工具是學(xué)習(xí)多種技術(shù)和技能的機(jī)會(huì)。這是個(gè)摘要:了解如何使用 PlatformIO 和 Microsoft Visual Studio Code 對(duì) E
    發(fā)表于 06-17 10:03

    自寫小工具

    個(gè)自己寫的小工具感覺還不錯(cuò),分享給大家。
    發(fā)表于 05-17 09:49 ?41次下載

    射頻工程類計(jì)算小工具

    射頻工程類計(jì)算小工具,有LC諧振頻率計(jì)算、PCB特性阻抗計(jì)算工具軟件、電感量計(jì)算等共19個(gè)計(jì)算小工具。
    發(fā)表于 03-21 14:50 ?58次下載

    電阻分壓計(jì)算小工具

    個(gè)計(jì)算電阻分壓的小工具
    發(fā)表于 09-07 14:54 ?45次下載

    教你在Linux上寫個(gè)進(jìn)度條小程序

    在 Linux 上寫下一個(gè)簡(jiǎn)易的進(jìn)度條小程序。
    的頭像 發(fā)表于 01-29 11:37 ?1491次閱讀

    介紹兩種LabVIEW里實(shí)現(xiàn)進(jìn)度條的方式

    進(jìn)度條,是個(gè)非常重要的UI元素。
    的頭像 發(fā)表于 07-14 09:29 ?1.1w次閱讀
    介紹兩種LabVIEW里<b class='flag-5'>實(shí)現(xiàn)</b><b class='flag-5'>進(jìn)度條</b>的方式

    【AWTK使用經(jīng)驗(yàn)】如何設(shè)計(jì)立體電池進(jìn)度條?

    AWTK是基于C語(yǔ)言開發(fā)的跨平臺(tái)GUI框架。《AWTK使用經(jīng)驗(yàn)》系列文章將介紹開發(fā)AWTK過程中些常見問題與解決方案,例如:如何加載外部資源?如何設(shè)計(jì)自定義進(jìn)度條?這些都會(huì)在系列文章進(jìn)行解答
    的頭像 發(fā)表于 04-18 08:25 ?728次閱讀
    【AWTK使用經(jīng)驗(yàn)】如何設(shè)計(jì)立體電池<b class='flag-5'>進(jìn)度條</b>?