Windows控制台函数:设置区域属性函数FillConsoleOutputAttribute()
目录
什么是 FillConsoleOutputAttribute?
函数签名
参数详解
用法
为什么 DWORD cells = 10 * 10 显示像只有一行,而不是正方形?
为什么像一行?
为什么不是正方形?
怎么改成正方形?
跟 SetConsoleTextAttribute 的区别
有趣的例子
注意事项
什么是 FillConsoleOutputAttribute?
FillConsoleOutputAttribute 是一个 Windows API 函数,用来给控制台的一个区域设置属性(主要是文字颜色和背景色)。它不像 SetConsoleTextAttribute 只影响后续输出,而是可以一次性填充一大片区域的属性,不管有没有文字。
把它想象成一个“油漆刷”:
-
你告诉它从哪里开始刷、刷多大一片、用什么颜色,它就帮你把控制台的背景或文字属性涂满。
函数签名
FillConsoleOutputAttribute
的全称是 "Fill Console Output Attribute",这个函数的作用是填充(Fill)控制台(Console)输出区域(Output)的文本属性(Attribute)。
-
Fill
:表示填充(用某个值填满一段区域)。 -
Console
:指的是控制台(Console),即 Windows 终端窗口。 -
Output
:表示输出区域,即控制台的显示内容。 -
Attribute
:指的是属性,在这里主要指文本颜色和背景颜色的属性。
它的定义是:
BOOL FillConsoleOutputAttribute(
HANDLE hConsoleOutput, // 屏幕的“钥匙”
WORD wAttribute, // 要刷的“颜色”
DWORD nLength, // 刷多大一片(多少个单元格)
COORD dwWriteCoord, // 从哪里开始刷
LPDWORD lpNumberOfAttrsWritten // 记录实际刷了多少
);
返回值:BOOL,TRUE 表示成功,FALSE 表示失败。
参数详解
1. HANDLE hConsoleOutput - 屏幕的“钥匙”
-
这是什么:你用 GetStdHandle(STD_OUTPUT_HANDLE) 拿到的屏幕句柄。
-
作用:告诉函数:“我要刷的是这个屏幕。”
-
怎么用:
HANDLE screen = GetStdHandle(STD_OUTPUT_HANDLE);
2. WORD wAttribute - 要刷的“颜色”
-
这是什么:一个 16 位数字,表示文字颜色(前景色)和背景色的组合。
-
作用:决定刷上去的属性,比如绿色背景。
-
怎么用:
-
用之前学的颜色值,比如:
-
BACKGROUND_GREEN(32):绿色背景。
-
FOREGROUND_RED | BACKGROUND_BLUE(4 | 16 = 20):红字蓝底。
-
-
示例:
-
WORD color = BACKGROUND_GREEN;
3. DWORD nLength - 刷多大一片
-
这是什么:一个数字,表示要刷多少个单元格(字符位置)。
-
作用:控制刷的范围,比如 30×30 = 900 个单元格。
-
怎么用:
-
如果刷一行 30 列:nLength = 30。
-
如果刷 30×30:nLength = 30 * 30。
-
示例:
-
DWORD cells = 30 * 30; // 900 个单元格
4. COORD dwWriteCoord - 从哪里开始刷
-
这是什么:一个 COORD 结构体,指定起始坐标(列和行)。
-
作用:告诉函数从哪个位置开始填充。
-
怎么用:
-
COORD 定义:
-
COORD start;
start.X = 0; // 列号(从 0 开始)
start.Y = 0; // 行号(从 0 开始)
-
比如从左上角开始:start = {0, 0}。
-
居中开始(比如 50×50 窗口中的 10,10):start = {10, 10}。
5. LPDWORD lpNumberOfAttrsWritten - 记录实际刷了多少
-
这是什么:一个变量的地址,函数会写下“实际填充了多少单元格”。
-
作用:确认填充是否完整。
-
怎么用:
DWORD written;
传地址:
&written
用法
我们写个简单例子,把 10×10 的区域背景刷成绿色:
#include <windows.h>
int main() {
// 1. 获取屏幕句柄
HANDLE screen = GetStdHandle(STD_OUTPUT_HANDLE);
if (screen == INVALID_HANDLE_VALUE) {
return 1;
}
// 2. 设置填充参数
COORD start = {0, 0}; // 从左上角开始
DWORD cells = 10 * 10; // 10 行 × 10 列 = 100 个单元格
DWORD written;
// 3. 填充绿色背景
FillConsoleOutputAttribute(screen, BACKGROUND_GREEN, cells, start, &written);
return 0;
}
运行结果
-
控制台左上角 10×10 的区域背景变成绿色。
-
如果窗口够大(比如 80×25),其他部分保持黑色。
为什么 DWORD cells = 10 * 10 显示像只有一行,而不是正方形?
你期待的是一个 10×10 的正方形区域,但实际看起来像一行,这是个很常见的问题,原因跟控制台的填充规则和窗口设置有关。我们来分析并解决。
为什么像一行?
-
填充方向:
-
FillConsoleOutputAttribute 从 start 开始,按行优先顺序填充。
-
它先填满一行(从左到右),再换到下一行。
-
如果你的控制台窗口宽度(列数)小于 100,100 个单元格可能不会完整显示成 10 行。
-
-
窗口大小的影响:
-
默认控制台窗口可能是 80 列 × 25 行(或你电脑的其他设置)。
-
cells = 100 表示填充 100 个单元格:
-
第一行填 80 个(0 到 79 列)。
-
第二行填剩下的 20 个(0 到 19 列)。
-
-
结果是:
-
第一行占满 80 个单元格。
-
第二行占 20 个,视觉上只看到部分。
-
如果窗口高度不够(比如只有 1 行可见),你可能只看到第一行。
-
-
-
显示问题:
-
如果窗口高度小于 10 行,你看不到完整的 10×10。
-
或者滚动条把后续行藏起来了。
-
为什么不是正方形?
-
你期待的是一个 10 列 × 10 行的绿色方块。
-
但如果窗口宽度超过 10 列(比如 80 列),cells = 100 会填充成“扁平”的形状,而不是正好 10×10。
-
控制台不会自动限制每行填充 10 个,它按实际窗口宽度走。
怎么改成正方形?
要确保显示一个 10×10 的绿色正方形,我们需要:
-
控制每行填充数量。
-
确保窗口够大。
方法 1:逐行填充
用循环,每次填 10 列,重复 10 行:
#include <windows.h>
int main() {
// 设置窗口足够大
system("mode con cols=20 lines=20");
HANDLE screen = GetStdHandle(STD_OUTPUT_HANDLE);
if (screen == INVALID_HANDLE_VALUE) {
return 1;
}
DWORD written;
for (int y = 0; y < 10; y++) {
COORD start = {0, (SHORT)y}; // 每行从第 0 列开始
FillConsoleOutputAttribute(screen, BACKGROUND_GREEN, 10, start, &written);
}
return 0;
}
SHORT是一个 16 位有符号整数,取值范围为 -32,768 到 32,767。在 Windows 头文件(如 <windows.h>)中,它被定义为:
typedef short SHORT;
控制台的行列数通常不会超过 32,767(16 位有符号整数的上限),这个范围足够表示大多数控制台窗口的坐标。使用 16 位整数比 32 位(int 或 LONG)更节省内存,符合早期系统设计时的优化需求。
可能的问题:
-
字体比例:控制台字体不是正方形(比如宽度 8 像素,高度 16 像素),视觉上可能是长方形。
跟 SetConsoleTextAttribute 的区别
特性 | SetConsoleTextAttribute | FillConsoleOutputAttribute |
---|---|---|
作用范围 | 只影响后续输出的文字属性 | 填充指定区域的属性 |
需要输出文字吗 | 是(不写文字不生效) | 否(直接改属性) |
控制区域 | 没法指定范围 | 可以精确指定起始点和大小 |
用途 | 动态输出彩色文字 | 批量设置背景或前景色 |
有趣的例子
我们在 50×50 窗口中画一个 20×20 的红底框:
#include <windows.h>
int main() {
system("mode con cols=50 lines=50");
HANDLE screen = GetStdHandle(STD_OUTPUT_HANDLE);
if (screen == INVALID_HANDLE_VALUE) {
return 1;
}
// 填充 20x20 红底,从 (15,15) 开始
COORD start = {15, 15};
DWORD cells = 20 * 20;
DWORD written;
FillConsoleOutputAttribute(screen, BACKGROUND_RED, cells, start, &written);
// 在框内写白字
SetConsoleTextAttribute(screen, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
COORD text_pos = {20, 20};
SetConsoleCursorPosition(screen, text_pos);
const char* msg = "框内文字";
WriteConsoleA(screen, msg, strlen(msg), &written, NULL);
return 0;
}
效果
-
50×50 窗口。
-
从 (15,15) 到 (34,34) 是红底(20×20)。
-
框内有白色“框内文字”,外面是黑色。
注意事项
-
缓冲区大小:
-
填充范围不能超过缓冲区大小(用 system("mode con ...") 设置的)。
-
如果 start + nLength 超出缓冲区,函数会失败。
-
-
只改属性:
-
它不改文字内容,原有文字颜色可能不变(前景色没改)。
-
想清空文字,用 FillConsoleOutputCharacterA 配合。
-
-
检查返回值:
if (!FillConsoleOutputAttribute(screen, BACKGROUND_GREEN, cells, start, &written)) {
return 1; // 出错了
}