简体   繁体   中英

Setting text color of the Windows console is not working as expected

I am trying to change the Windows console foreground text color with Rust using the winapi and kernel32 crates.

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

Code

Enum where I store the foreground color values:

#[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,
    // ...
}

Function that gets the output handle:

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")
    }
}

Function that sets the foreground color use 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);
    }
}

In my main.rs I am creating a box that is 20 blocks on X and 20 on Y. I want to give the border a color of CYAN and the inside a RED color.

// 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!();
}

For some reason, all will have the CYAN color and there will not be any red ones.

When I have the same code and replace the print!() with println!() , it will print both the RED and CYAN colored blocks as expected. All the have the right color as expected but the problem now is that the are on their own row.

Why is the color of the text changing as expected when using println!() ? Why can I not have different colors on the same line with print!() ? Is there some buffer in winapi that stores the color of the console lines? Do I need to specify it somewhere before I can use multiple colors in one line?

Rust's standard output is line-buffered. So your text gets sent to the console one line at a time, meaning the entire line will have the same color.

You can flush the output after each print! using:

use std::io::Write;

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM