標籤:
控制台程式預設只能通過拖動捲軸來查看視窗中列印的內容,操作起來十分不方便。
本文通過多線程技術為控制台表單添加滑鼠滾輪滑動功能。值得注意的是,在有內容輸出時,視窗會自動定位到輸出的游標處;
這種情況最好是先暫停住主線程,然後再滾動滑鼠查看列印的內容,查看完畢後,再繼續執行主線程。
首先,需要讓控制台程式的螢幕緩衝區高度 > 視窗高度(此時視窗右側會產生捲軸),否則無需滾動視窗。
下列代碼實現了如下功能:
(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;}
控制台程式添加滾輪滑動支援