【问题标题】:Setting text color of the Windows console is not working as expected设置 Windows 控制台的文本颜色未按预期工作
【发布时间】:2017-10-23 17:40:22
【问题描述】:

我正在尝试使用 winapi 和 kernel32 crates 使用 Rust 更改 Windows 控制台前景文本颜色。

[dependencies]
winapi = "0.2.8"
kernel32-sys = "0.2.1" 

代码

我存储前景色值的枚举:

#[repr(u16)]
pub enum ForegroundColor {
    RED =  (winapi::FOREGROUND_INTENSITY | winapi::FOREGROUND_RED) as u16,
    CYAN = (winapi::FOREGROUND_INTENSITY | winapi::FOREGROUND_GREEN | winapi::FOREGROUND_BLUE) as u16,
    // ...
}

获取输出句柄的函数:

use winapi;
use winapi::{CONSOLE_SCREEN_BUFFER_INFO, COORD, HANDLE, SMALL_RECT, WORD};
use kernel32;

static mut CONSOLE_OUTPUT_HANDLE: Option<HANDLE> = None;
pub fn get_output_handle() -> HANDLE {
    unsafe {
        if let Some(handle) = CONSOLE_OUTPUT_HANDLE {
            handle_check(handle);
            handle
        } else {
            let handle = kernel32::GetStdHandle(winapi::STD_OUTPUT_HANDLE);
            handle_check(handle);
            CONSOLE_OUTPUT_HANDLE = Some(handle);
            handle
        }
    }
}

fn handle_check(handle: HANDLE) {
    if handle == winapi::INVALID_HANDLE_VALUE {
        panic!("NoConsole")
    }
}

设置前景色的函数 使用kernel32;

// ForegroundColor is a struct containing win32 colors
pub fn set_foreground_color(for_color: ForegroundColor) {
    // function shown above
    let output_handle = kernel::get_output_handle();
    // cast the enum value to a u16: fn to_u16(&self) -> u16 { *self as u16 }
    let forground_color = for_color.to_u16();

    unsafe {
        kernel32::SetConsoleTextAttribute(output_handle, forground_color);
    }
}

在我的main.rs 中,我正在创建一个在 X 上为 20 个块,在 Y 上为 20 个块的框。我想给边框颜色 CYAN 和内部颜色 RED。

// for example 1 has to be cyan and 2 red but than on larger scale
// 1111
// 1221
// 1111
for y in 0..21 {
    for x in 0..21 {
        if (x == 0 || y == 0) || (x == 20 || y == 20) {
            // function shown above
            set_foreground_color(ForegroundColor::CYAN);
            // Print a cyan colored ■
            print!("■")
        } else {
            // function shown above
            set_foreground_color(ForegroundColor::RED);
            // Print a red colored ■
            print!("■")
        }
    }
    // reset cursor to start of new line
    println!();
}

由于某种原因,所有■ 都将具有CYAN 颜色,并且不会有任何红色。

当我使用相同的代码并将print!() 替换为println!() 时,它将按预期打印RED 和CYAN 彩色块。所有■ 都具有预期的正确颜色,但现在的问题是■ 在它们自己的行上。

为什么在使用println!() 时文本的颜色会按预期变化?为什么我不能在print!() 的同一行上使用不同的颜色? winapi 中是否有一些缓冲区来存储控制台行的颜色?我需要在某处指定它才能在一行中使用多种颜色吗?

【问题讨论】:

  • Windows 控制台对于非 ASCII 值是出了名的棘手;尝试比■更简单的东西?
  • @Shepmaster ■ 如果你按下&lt;ALT&gt; + 254 就会被放置在 ASCII 表中,你会得到这个块。而且这个问题也出现在普通号码上(刚试了)。
  • 我强烈建议您返回并重新阅读 ASCII 是什么。只有小于 128 的数值是 ASCII。
  • @Shepmaster 好的,但是如果我使用 1 或 2 而不是 ■ 这些数字仍然具有相同的颜色:CYAN 而不是 1 是青色和 @ 987654346@ 是红色的。所以这可能不是问题吗?
  • 是的,在这种情况下,它似乎不太可能是非 ASCII 问题。

标签: winapi colors console rust kernel32


【解决方案1】:

Rust 的标准输出是行缓冲的。因此,您的文本一次一行被发送到控制台,这意味着整行将具有相同的颜色。

您可以在每个 print! 之后使用以下命令刷新输出:

use std::io::Write;

std::io::stdout().flush().expect("Flush stdout failed");

【讨论】:

  • 完美运行!!这解释了很多。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-09
  • 2013-10-12
  • 1970-01-01
  • 2018-09-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多