有没有一种使用Rust覆盖控制台输出而不是简单地附加的方法?
一个示例是将进度打印为百分比;我宁愿覆盖该行而不是打印新行。
通常通过打印“控制字符”来控制控制台,但这取决于平台和终端类型。你可能不想重新发明轮子来做这个。
你可以使用crossterm crate来获取这种控制台控制。一个简单的例子是:
use std::{thread, time};
use std::io::{Write, stdout};
use crossterm::{QueueableCommand, cursor, terminal, ExecutableCommand};
fn main() {
let mut stdout = stdout();
stdout.execute(cursor::Hide).unwrap();
for i in (1..30).rev() {
stdout.queue(cursor::SavePosition).unwrap();
stdout.write_all(format!("{}: FOOBAR ", i).as_bytes()).unwrap();
stdout.queue(cursor::RestorePosition).unwrap();
stdout.flush().unwrap();
thread::sleep(time::Duration::from_millis(100));
stdout.queue(cursor::RestorePosition).unwrap();
stdout.queue(terminal::Clear(terminal::ClearType::FromCursorDown)).unwrap();
}
stdout.execute(cursor::Show).unwrap();
println!("Done!");
}
如果采用底层方法,你可以使用\r
转义字符使光标返回到行首并从那里开始覆盖。
use std::{
io::{stdout, Write},
thread::sleep,
time::Duration,
};
fn main() {
let mut stdout = stdout();
for i in 0..=100 {
print!("\rProcessing {}%...", i);
// or
// stdout.write(format!("\rProcessing {}%...", i).as_bytes()).unwrap();
stdout.flush().unwrap();
sleep(Duration::from_millis(20));
}
println!();
}
您也可以使用退格字符将光标向后移动一个位置。
const BACKSPACE: char = 8u8 as char;
print!("{}\rThis replaces the previous line", BACKSPACE);
这种方法最适用于像这样简单的递增值。如果您写入Hello, World!
然后是\rbar
, 您将得到baro, World!
。如果您想要清除输出,最好的方法是跟踪您已经写入的字符数,并用空格覆盖它们,或者您可以使用一个可以给您终端大小的库。
started
然后再写入done
将会留下doneted
。有没有一种方法可以清除行呢?(现在正在查看crossterm::terminal::Clear
,但是没有示例很难理解) - Jonathan Woollett-lightterminal::Clear(ClearType::CurrentLine)
。 - Michael AndersonSavePosition
/RestorePosition
调用无法正常工作的问题?只需在每个queue
调用后添加.unwrap()
可能就足以得到一些想法。 (它们对我肯定有效,我认为这可能取决于您的终端功能/类型。) - Michael Anderson