控制台程序默认只能通过拖动滚动条来查看窗口中打印的内容,操作起来十分不方便。
本文通过多线程技术为控制台窗体添加鼠标滚轮滑动功能。值得注意的是,在有内容输出时,窗口会自动定位到输出的光标处;
这种情况最好是先暂停住主线程,然后再滚动鼠标查看打印的内容,查看完毕后,再继续执行主线程。
首先,需要让控制台程序的屏幕缓冲区高度 > 窗口高度(此时窗口右侧会产生滚动条),否则无需滚动窗口。
下列代码实现了如下功能:
(1)滚动鼠标滑动窗口
(2)按空格键,暂停/继续主线程
#include <windows.h> /** * Scroll console window by relative coordinate */ static int ScrollByRelativeCoord(int iRows) { CONSOLE_SCREEN_BUFFER_INFO csbiInfo; SMALL_RECT srctWindow; // Get the current screen buffer window position. HANDLE hConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE); if (! GetConsoleScreenBufferInfo(hConsoleOutput, &csbiInfo)) { return 0; } // Check whether the window is too close to the screen buffer top or bottom if (csbiInfo.srWindow.Top < iRows) { iRows = csbiInfo.srWindow.Top; } else if (csbiInfo.srWindow.Bottom > csbiInfo.dwSize.Y+iRows-1) { iRows = -1* (csbiInfo.dwSize.Y -1 - csbiInfo.srWindow.Bottom); } srctWindow.Top =- (SHORT)iRows; // move top up srctWindow.Bottom =- (SHORT)iRows; // move bottom up srctWindow.Left = 0; // no change srctWindow.Right = 0; // no change if (! SetConsoleWindowInfo( hConsoleOutput, // screen buffer handle FALSE, // relative coordinates &srctWindow)) // specifies new location { return 0; } return iRows; } DWORD WINAPI ConsoleInputEventProc(LPVOID lParam) { // vc6 version sdk don‘t has OpenThread API, need get by call GetProcAddress; HANDLE hMainThreadHandle = NULL; #if _MSC_VER <= 1200 HMODULE hDll =::LoadLibrary("Kernel32.dll"); if (hDll) { typedef HANDLE (__stdcall *OPENTHREAD) (DWORD, BOOL, DWORD); OPENTHREAD fnOpenThread = (OPENTHREAD)::GetProcAddress(hDll, "OpenThread"); if (fnOpenThread) { hMainThreadHandle = fnOpenThread(THREAD_SUSPEND_RESUME, FALSE, (DWORD)lParam); } } #else hMainThreadHandle = OpenThread(THREAD_SUSPEND_RESUME, FALSE, (DWORD)lParam); #endif HANDLE hConsoleInput = GetStdHandle(STD_INPUT_HANDLE); BOOL bSuspend = FALSE; BOOL fContinue = TRUE; DWORD dwEvents; INPUT_RECORD input; while (fContinue && ReadConsoleInput(hConsoleInput, &input, 1, &dwEvents) && dwEvents > 0) { switch (input.EventType) { case KEY_EVENT: if (input.Event.KeyEvent.wVirtualKeyCode == VK_SPACE) { if (input.Event.KeyEvent.bKeyDown && hMainThreadHandle != NULL) { HANDLE hConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE); if (bSuspend) { SetConsoleTextAttribute(hConsoleOutput, FOREGROUND_GREEN); printf("Resume MainThread\n"); ResumeThread(hMainThreadHandle); } else { SetConsoleTextAttribute(hConsoleOutput, FOREGROUND_RED); printf("Suspend MainThread\n"); SuspendThread(hMainThreadHandle); } SetConsoleTextAttribute(hConsoleOutput, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); bSuspend = !bSuspend; } } case MOUSE_EVENT: if (input.Event.MouseEvent.dwEventFlags==4)// mousewheel { const int nLine = 5; if ((int)input.Event.MouseEvent.dwButtonState>0)// scroll up { ScrollByRelativeCoord(nLine); } else// scroll up { ScrollByRelativeCoord(-1*nLine); } } break; } } CloseHandle(hMainThreadHandle); return 0; } int main(int argc, char* argv[]) { CreateThread(NULL, 0, ConsoleInputEventProc, (LPVOID)GetCurrentThreadId(), 0, NULL); int nLine = 60; while (nLine--) { printf("Hello World!\n"); Sleep(1000); } Sleep(INFINITE); return 0; }
时间: 2024-10-24 22:02:26