目錄
一,進度條的必備知識
1,緩沖區的粗略介紹
2,回車與換行
二,進度條的初步制作
1,進度條的初步礦建
2,進度條的版本一
3,進度條的版本二
一,進度條的必備知識
1,緩沖區的粗略介紹
? ? ? ??緩沖區是內存的一部分空間,用于臨時存儲輸入和輸出的數據。它可分為輸入緩沖區和輸出緩沖區。每當我們輸入數據時都是往輸入緩沖區中存放數據,當刷新緩沖區時,數據將會從緩沖區中拿出輸入到某個變量中。每當我們輸出數據時,系統將會把數據輸出到輸出緩沖區中,當刷新輸出緩沖區時,數據將會從輸出緩沖區輸出到指定地方。
? ? ? ? 其中,緩沖區的刷新時機是不同的。行緩沖會在遇到換行符時刷新,全緩沖會在緩沖區寫滿時刷新,而無緩沖則沒有緩沖區,代表是系統調用。在C/C++中,通常用 fflush(FILE* stream) 來強制刷新指定流的緩沖區。
? ? ? ? C/C++中類似于sleep函數功能控制的就是緩沖區,當系統調用到sleep是,將會被緩沖區暫時保存起來,一旦sleep運行完畢之后緩沖區才刷新。進度條有時控制的就是緩沖區的刷新時間。
2,回車與換行
? ? ? ? “ 回車 ” 是把光標從當前位置直接指向最開頭位置。“ 換行?” 是把光標從當前位置直接指向下一行同一列的位置。我們在C語言階段常用的 “ \n?” 指的是?換行?+ 回車。而 “ \r ” 只表示回車。
二,進度條的初步制作
1,進度條的初步礦建
? ? ? ? 首先,我們先來編寫進度條的簡單倒計時程序,這就需要運用回車和sleep來控制程序的運行。
#include <iostream>
#include <iomanip> //setw的頭文件
#include <unistd.h> //usleep()的頭文件,對應參數單位為微秒? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
#include <cstdio>
using namespace std;
int main()
{
? ? int n = 10;
? ? while (n >= 0) {
?? ??? ?cout << left << setw(2) << n << '\r'; //跟C語言中printf("%-2d\r", n)效果一樣
? ? ? ? fflush(stdout); ? //強制刷新輸出緩沖區
? ? ? ? n--;
? ? ? ? usleep(500000); ? ?//這里我們控制緩沖時間為0.5秒
?? ?}
? ? cout << endl;
? ? return 0;
}
? ? ? ? 下一步,要思考進度條的框架設計。這里的進度條將外圍用 " = " 表示進度的加載,外圍設置了百分比顯示加載數據。用 "|/-\" 來表示其中的加載,即順時針旋轉。
2,進度條的版本一
? ? ? ? 首先,外面設置一個頭文件 "process.h" 進行必要的設置
#include <iostream>
#include <string>
#include <unistd.h>
#include <iomanip>
#include <cstdio>
using namespace std;#define Body '='? ?//使用body來表示進度
#define Head '>'? ?//Head表示目前加載的終點,這里用 ' > ' 表示void process1();? //進度條函數
? ? ? ? 下面,進行進度功能的編寫。這里使用 usleep 功能來控制進度的的運行,這里需注意的是輸出緩沖區的刷新。
void process1()
{? ? //用lable表示進度條的加載
? ? string lable("|/-\\");??
? ? string nums;
? ? int count = 0;
? ? int lablesize = lable.size();
? ? nums.push_back(Head);
? ? while (count <= 100)
? ? {
? ? ? ? cout << "[" << left << setw(100) << nums << "]";
? ? ? ? cout << "[" << "%" << count << "]";
? ? ? ? cout << "[" << lable[count % lablesize] << "]" << '\r';
? ? ? ? fflush(stdout);
? ? ? ? nums.clear();
? ? ? ? count++;
? ? ? ? nums.append(count, Body);
? ? ? ? if (count < 100)
? ? ? ? {
? ? ? ? ? ? nums.push_back(Head);
? ? ? ? }????????//這里我們設置每0.6秒加載一次
? ? ? ? usleep(60000);?
? ? }
? ? cout << endl;
}
運行最終結果:
[====================================================================================================][%100][|]
3,進度條的版本二
? ? ? ? 進度條一般都是運用在一種應用上,表示應用的加載過程。很顯然,版本一的進度條只是無腦運行,不知道程序進度是多少,即沒有依附應用進度,比如下載程序,這時的進度條需依附于下載進度來跟進。
? ? ? ? 頭文件 "process.h" 添加如下:
#include <iostream>
#include <string>
#include <unistd.h>
#include <iomanip>
#include <cstdio>
#include <cstdlib>
using namespace std;#define Body '='
#define Head '>'
#define Max 103
#define FileSize 1024*1024*1024? //設置FileSize文件內存為1G,表示下載程序的總大小typedef void (*callback_t)(double);? //利用函數指針來進行封裝進度運用
void download(callback_t);? //模擬一種下載進度
void process2(double rate); //進度條跟進程序
? ? ? ? 這里,在設置download下載時要將每一次的下載進度傳遞給進度條讓其顯示百分比。
void download(callback_t cb)? ?//利用回調函數的形式設置進度
{
? ? srand(time(0)*1024);
? ? int total = FileSize;
? ? while (total)
? ? {
? ? ? ? //下面表示一次下載動作
? ? ? ? usleep(10000);
? ? ? ? int one = rand() % (1024 * 1024 * 5);
? ? ? ? total -= one;
? ? ? ? if (total < 0)?
? ? ? ? {
? ? ? ? ? ? total = 0;
? ? ? ? }
? ? ? ? //表示當前的進度
? ? ? ? int download = FileSize - total;
? ? ? ? double rate = (download * 1.0 / (FileSize)) * 100.0;
? ? ? ? cb(rate); //每一次進度條的傳遞
? ? }
}
進度條設置時要說明以下幾點:
????????1,我們使用?"|/-\\" 表示進度跟進時是根據下載進度進行的,與當前的進度無關。
????????2,進度條的總設置需與下載程序緊緊聯系。比如當程序加載完時,“ > ” 進度條中表示進? ? ? ? ? 度運行的就要停止,即刪除。
????????3,在輸出進度運行過程,我們可添加其色彩表示美觀,鏈接:色彩文本的增添
void process2(double rate)
{? ??//用lable表示下載任務一直在跟進
? ? string lable("|/-\\");?? ??//注意,這里要保留之前的進度,需設置靜態
? ? static char buffer[Max] = { 0 };
? ? static int cnt = 0;
? ? if (rate <= 1.0)
? ? {
? ? ? ? buffer[0] = Head;
? ? }
? ? printf("\033[1;31;46m[%-100s]\033[0m[%.1lf%%][%c]\r", buffer, rate, lable[cnt % lable.size()]);? //設置色彩,這里我們設置高亮/加粗,青色背景,紅色字體的色彩
? ? fflush(stdout);? ? //下面控制進度的跟進
? ? buffer[(int)rate] = Body;
? ? if ((int)rate + 1 < 100)
? ? {
? ? ? ? buffer[(int)(rate + 1)] = Head;
? ? }
? ? if (rate >= 100.0)
? ? {
? ? ? ? cout << endl;
? ? }
? ? cnt++;
? ? cnt %= lable.size();
}
總代碼如下:
#include "process.h"
//版本一
void process1()
{string lable("|/-\\");string nums;int count = 0;int lablesize = lable.size();nums.push_back(Head);while (count <= 100){cout << "[" << left << setw(100) << nums << "]";cout << "[" << "%" << count << "]";cout << "[" << lable[count % lablesize] << "]" << '\r';fflush(stdout);nums.clear();count++;nums.append(count, Body);if (count < 100){nums.push_back(Head);}usleep(60000);}cout << endl;
}
//版本二
void download(callback_t cb)
{srand(time(0) * 1024);int total = FileSize;while (total){usleep(10000);int one = rand() % (1024 * 1024 * 5);total -= one;if (total < 0){total = 0;}int download = FileSize - total;double rate = (download * 1.0 / (FileSize)) * 100.0;cb(rate);}
}
void process2(double rate)
{static string lable("|/-\\");static char buffer[Max] = { 0 };static int cnt = 0;if (rate <= 1.0){buffer[0] = Head;}printf("\033[1;31;46m[%-100s]\033[0m[%.1lf%%][%c]\r", buffer, rate, lable[cnt % lable.size()]);fflush(stdout);buffer[(int)rate] = Body;if ((int)rate + 1 < 100){buffer[(int)(rate + 1)] = Head;}if (rate >= 100.0){cout << endl;}cnt++;cnt %= lable.size();
}
int main()
{//process1(); //使用進度條粗略版本一download(process2); //使用進度條進化版本二return 0;
}
????????最后,要說明的是,以上程序都是在Linux系統下運行進行的,在VS或其它編譯器下可能會出現錯誤消息,這時因為不同平臺支持的C標準或系統設置不同而造成的差異。