私はいつも、コマンドラインの前の行をどのように更新するのか疑問に思っていました。この良い例は、Linuxでwgetコマンドを使用する場合です。これは、次のような種類のASCIIロードバーを作成します。
[======>] 37%
もちろん、ローディングバーが移動し、パーセントが変化しますが、新しい行は作成されません。これを行う方法がわかりません。誰かが私を正しい方向に向けることができますか?
私はいつも、コマンドラインの前の行をどのように更新するのか疑問に思っていました。この良い例は、Linuxでwgetコマンドを使用する場合です。これは、次のような種類のASCIIロードバーを作成します。
[======>] 37%
もちろん、ローディングバーが移動し、パーセントが変化しますが、新しい行は作成されません。これを行う方法がわかりません。誰かが私を正しい方向に向けることができますか?
回答:
これを行うために私が知っている2つの方法があります:
curses選択したプログラミング言語にバインディングがある場合は、パッケージを使用してください。そしてグーグルはANSIエスケープコードを明らかにしました、それは良い方法であるように見えます。参考までに、これを行うための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.
}
これを行う1つの方法は、現在の進行状況でテキスト行を繰り返し更新することです。例えば:
def status(percent):
sys.stdout.write("%3d%%\r" % percent)
sys.stdout.flush()
各行の終わりに「\ r \ n」(キャリッジリターン改行)が自動的に出力されるためsys.stdout.write、print(これはPythonです)の代わりに使用したことに注意してくださいprint。カーソルを行の先頭に戻すキャリッジリターンが必要です。また、flush()デフォルトでsys.stdoutは、改行の後(またはバッファがいっぱいになった後)にのみ出力をフラッシュするため、が必要です。
秘訣は、行のとに\ nまたは\ r \ nではなく\ rのみを出力することです。
\ rはキャリッジリターンと呼ばれ、行の先頭にカーソルを移動します
\ nは改行と呼ばれ、コンソールの次の行にカーソルを移動します。\ rのみを使用する場合は、前に書き込んだ行を上書きします。したがって、最初に次のような行を記述します。
[ ]
次に、ティックごとに記号を追加します
\r[= ]
\r[== ]
...
\r[==========]
等々。それぞれが10%を表す10文字を使用できます。また、終了時にメッセージを表示する場合は、次のように以前に記述した等号を上書きするために、十分な数の白い文字も追加することを忘れないでください。
\r[done ]
以下は私の答えです、Windows APIコンソール(Windows)、Cのコーディングを使用してください。
/*
* file: ProgressBarConsole.cpp
* description: a console progress bar Demo
* author: lijian <hustlijian@gmail.com>
* 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;
}
bInfo定義されていますか?
PowerShellには、スクリプトの実行時に更新および変更できるコンソール内のプログレスバーを作成するWrite-Progressコマンドレットがあります。
グレッグの答えのフォローアップとして、複数行のメッセージを表示できるようにする彼の関数の拡張バージョンを次に示します。表示/更新する文字列のリストまたはタプルを渡すだけです。
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ベースのシステムではマイレージが異なる場合があります。
\nまし\r\nたが、それでもWindowsで動作させることができませんでした(そうですか?)。私はなってきた←[A←[A私は疑う、いくつかのメッセージの後に'\x1b[A'シーケンスは、それが何にすべき行いませんcmd.exe。