0
已解决
薛乘志
初级启示者
初级启示者
众所周知,无论是system("cls")还是自己写的cls()函数,都有一个问题:屏幕显示区上下部分的输出时间不一致
经过我的一番查找及研究,我找出了最终极的解决方法:双缓冲
原理:
windows下的屏幕输出方式如图:
其中程序->屏幕缓冲区可能没有输出完,屏幕缓冲区->屏幕就已经发送了,导致输出了一半的界面出现在用户的眼前
再说一句,win下可以创建多个屏幕缓冲区,但是只有活动屏幕缓冲区的能发送信息给屏幕
所以,可以人为修改输出模式为:
代码:
#include <bits/stdc++.h>
#include <windows.h>
namespace DoubleBuffer {
COORD Size;
HANDLE buf1 = GetStdHandle(STD_OUTPUT_HANDLE);
HANDLE buf2 = CreateConsoleScreenBuffer(
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, CONSOLE_TEXTMODE_BUFFER, NULL);
HANDLE Nowhandle;
DWORD written;
void setsize(SHORT width, SHORT height) {
HANDLE hStdOutput = Nowhandle;
SMALL_RECT wrt = {0, 0, short(width - 1), short(height - 1)};
SetConsoleWindowInfo(hStdOutput, TRUE, &wrt);
COORD coord = {width, height};
SetConsoleScreenBufferSize(hStdOutput, coord);
}
HANDLE handle(DWORD type) {
if (type == STD_OUTPUT_HANDLE) {
return Nowhandle;
} else {
return GetStdHandle(type);
}
}
void print(const char* format, ...) {
va_list args;
va_start(args, format);
char tmp_str[1024];
size_t sizes = vsprintf(tmp_str, format, args);
WriteConsoleA(Nowhandle, tmp_str, sizes, &written, NULL);
va_end(args);
}
bool nowbuf = true; //true:buf1 | false:buf2
void swap_buffer() {
nowbuf = !nowbuf;
if (nowbuf) {
Nowhandle = buf1;
} else {
Nowhandle = buf2;
}
setsize(Size.Y, Size.X);
}
void print_buffer() {
SetConsoleActiveScreenBuffer(Nowhandle);
}
void _initbuf(short SizeX, short SizeY) { //SizeX为高、SizeY为宽
DoubleBuffer::Size.X = SizeX, DoubleBuffer::Size.Y = SizeY;
DoubleBuffer::swap_buffer();
}
void _stopbuf() {
Nowhandle = buf1;
SetConsoleActiveScreenBuffer(buf1);
}
#define endl '\n'
class stdio_output {
public:
#define _output(T, F) stdio_output operator<<(T data) {print(F, data); return *this;}
_output(const bool, "%d");
_output(const int, "%d");
_output(const short, "%d");
_output(const long long, "%d");
_output(const long int, "%d");
_output(const unsigned int, "%u");
_output(const unsigned short, "%u");
_output(const unsigned long long, "%u");
_output(const unsigned long int, "%d");
_output(const float, "%g");
_output(const double, "%g");
_output(const char, "%c");
_output(const char*, "%s");
_output(const void*, "%p");
#undef _output
stdio_output operator<<(std::string data) {
WriteConsoleA(Nowhandle, data.c_str(), data.size(), &written, NULL);
return *this;
}
};
stdio_output _cout;
}
#define initbuf (DoubleBuffer::_initbuf)
#define GetStdHandle(nStdHandle) (DoubleBuffer::handle(nStdHandle))
#define printf (DoubleBuffer::print)
#define swapbuf (DoubleBuffer::swap_buffer)
#define printbuf (DoubleBuffer::print_buffer)
#define cout (DoubleBuffer::_cout)
#define stopbuf (DoubleBuffer::_stopbuf)
void clrscr() { //清屏
HANDLE hdout = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_SCREEN_BUFFER_INFO csbi;
GetConsoleScreenBufferInfo(hdout, &csbi);
DWORD size = csbi.dwSize.X * csbi.dwSize.Y, num = 0;
COORD pos = {0, 0};
FillConsoleOutputCharacterA(hdout, ' ', size, pos, &num);
FillConsoleOutputAttribute(hdout, 255, size, pos, &num );
SetConsoleCursorPosition(hdout, pos);
}
int main() {
initbuf(25, 80); //初始化双缓冲,并设置窗口高和宽
while (1) {
swapbuf(); //交换缓冲区
clrscr(); //清屏
//自己写输出信息的代码,可使用printf或cout,其余暂时无效
printbuf(); //设为活动缓冲区
}
stopbuf(); //停止使用双缓冲
return 0;
}
使用双缓冲的XACRAFT3.2与原版对比: