2008-09-13 86 views
74

我一直想知道人們如何更新命令行中的上一行。一個很好的例子就是在linux中使用wget命令。它創建各種各樣的ASCII加載條看起來像這樣:如何動畫命令行?

[======>                                        ] 37%

當然還有loa丁棒移動和百分比變化,但它並沒有形成一個新的線。我無法弄清楚如何做到這一點。有人能指引我朝着正確的方向嗎?

回答

42

有兩種方法,我知道要做到這一點:

  • 用退格轉義字符(「\ B」)刪除您的線路
  • 使用curses包,如果您選擇的編程語言對它有約束力。

而谷歌透露ANSI Escape Codes,這似乎是一個好方法。作爲參考,在這裏是在C++函數來做到這一點:

void DrawProgressBar(int len, double percent) { 
    cout << "\x1B[2K"; // Erase the entire current line. 
    cout << "\x1B[0E"; // Move to the beginning of the current line. 
    string progress; 
    for (int i = 0; i < len; ++i) { 
    if (i < static_cast<int>(len * percent)) { 
     progress += "="; 
    } else { 
     progress += " "; 
    } 
    } 
    cout << "[" << progress << "] " << (static_cast<int>(100 * percent)) << "%"; 
    flush(cout); // Required. 
} 
+7

假設他正在一個Win32控制檯應用程序(不DOS)在最新版本的Windows上(即2000+),ANSI轉義碼完全不起作用。正如您鏈接到的維基百科文章所述。 – 2008-09-25 02:58:46

+0

如果在Windows上使用ANSI Escape Sequences,則可以使用Ansicon。 https://github.com/adoxa/ansicon – 2014-12-17 19:42:17

56

的一種方式做,這是反覆更新的文本與當前進度行。例如:

def status(percent): 
    sys.stdout.write("%3d%%\r" % percent) 
    sys.stdout.flush() 

注意,我使用的sys.stdout.write代替print(這是Python的),因爲print自動打印爲「\ r \ n」個(回車換行)在每一行的末尾。我只是想要返回光標回到行的開始。此外,flush()是必要的,因爲默認情況下,sys.stdout只在換行符後(或其緩衝區滿了之後)刷新其輸出。

+0

和'c'中的printf和'\ r'一樣。 – 2008-09-13 01:21:49

+0

`flush()`後面到底是什麼「刷新」?只是好奇... – Nearoo 2017-02-04 00:43:43

+0

@Nearoo通常stdout緩衝其輸出,直到寫入換行符(\ n)。沖洗使局部線條立即出現。 – 2017-02-04 02:36:33

3

PowerShell有一個Write-Progress cmdlet,它可以創建一個控制檯內進度條,您可以在腳本運行時更新和修改該進度條。

0

如果您使用腳本語言,您可以使用「tput cup」命令來完成此操作... P.S.這是在Linux/Unix的東西只就我所知...

2

作爲後續行動,以Greg's answer,這裏是他的功能的擴展版,它允許您顯示多行消息;只需傳入要顯示/刷新的字符串的列表或元組即可。

def status(msgs): 
    assert isinstance(msgs, (list, tuple)) 

    sys.stdout.write(''.join(msg + '\n' for msg in msgs[:-1]) + msgs[-1] + ('\x1b[A' * (len(msgs) - 1)) + '\r') 
    sys.stdout.flush() 

注:我這使用的是Linux終端,所以你的里程可能會在基於Windows的系統只改變測試。

3

這裏是你的問題的答案......(蟒蛇)

def disp_status(timelapse, timeout): 
    if timelapse and timeout: 
    percent = 100 * (float(timelapse)/float(timeout)) 
    sys.stdout.write("progress : ["+"*"*int(percent)+" "*(100-int(percent-1))+"]"+str(percent)+" %") 
    sys.stdout.flush() 
    stdout.write("\r \r") 
4
下面

就是我的回答,使用Windows API Consoles(Windows),C的編碼

/* 
* file: ProgressBarConsole.cpp 
* description: a console progress bar Demo 
* author: lijian <[email protected]> 
* version: 1.0 
* date: 2012-12-06 
*/ 
#include <stdio.h> 
#include <windows.h> 

HANDLE hOut; 
CONSOLE_SCREEN_BUFFER_INFO bInfo; 
char charProgress[80] = 
    {"================================================================"}; 
char spaceProgress = ' '; 

/* 
* show a progress in the [row] line 
* row start from 0 to the end 
*/ 
int ProgressBar(char *task, int row, int progress) 
{ 
    char str[100]; 
    int len, barLen,progressLen; 
    COORD crStart, crCurr; 
    GetConsoleScreenBufferInfo(hOut, &bInfo); 
    crCurr = bInfo.dwCursorPosition; //the old position 
    len = bInfo.dwMaximumWindowSize.X; 
    barLen = len - 17;//minus the extra char 
    progressLen = (int)((progress/100.0)*barLen); 
    crStart.X = 0; 
    crStart.Y = row; 

    sprintf(str,"%-10s[%-.*s>%*c]%3d%%", task,progressLen,charProgress, barLen-progressLen,spaceProgress,50); 
#if 0 //use stdand libary 
    SetConsoleCursorPosition(hOut, crStart); 
    printf("%s\n", str); 
#else 
    WriteConsoleOutputCharacter(hOut, str, len,crStart,NULL); 
#endif 
    SetConsoleCursorPosition(hOut, crCurr); 
    return 0; 
} 
int main(int argc, char* argv[]) 
{ 
    int i; 
    hOut = GetStdHandle(STD_OUTPUT_HANDLE); 
    GetConsoleScreenBufferInfo(hOut, &bInfo); 

    for (i=0;i<100;i++) 
    { 
     ProgressBar("test", 0, i); 
     Sleep(50); 
    } 

    return 0; 
} 
13

祕密是隻打印\ r而不是\ n或\ r \ n在行和行。

\ r被稱爲回車和它在該行

\ n被稱爲換行的開始移動光標並將其移動光標到下一行 在控制檯。如果您僅使用\ r覆蓋先前寫入的行。 所以先寫類似下面的一行:

[   ] 

然後加了個手勢,每個刻度

\r[=   ] 

\r[==  ] 

... 

\r[==========] 

等。 您可以使用10個字符,每個字符代表10%。 另外,如果你想在完成時顯示一條消息,不要忘了,讓你覆蓋以前寫等號像這樣還補充足夠的白色字符:

\r[done  ]