1.添加头文件,导入库文件;定义控件标识;定义全局的句柄:主窗口,富编辑框控件,lable控件,下拉列表控件;
//添加头文件,导入库文件 #include <richedit.h> #include <commctrl.h> #pragma comment(lib,"comctl32.lib") //定义控件标识 #define IDC_RICHED_LOGWND 33001 #define IDC_STATIC_POKERSEL 33002 #define IDC_COMBO_POKERSEL 33003 //定义全局的句柄:主窗口,富编辑框控件,lable控件,下拉列表控件 HWND g_hMainWnd=NULL; HWND g_hLogWnd=NULL; HWND g_hPokerSelStatic=NULL; HWND g_hPokerSelCombo=NULL;
2.在创建完主窗口后,创建子窗体/控件
// 目的: 保存实例句柄并创建主窗口 BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) { HWND hWnd; hInst = hInstance; // 将实例句柄存储在全局变量中 hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL); if (!hWnd) {return FALSE;} g_hMainWnd = hWnd; // 保存主窗口句柄 CreateChildWindows();//调用创建子窗体 ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); return TRUE; } //创建子窗口 BOOL CreateChildWindows() { // RichEdit,加载dll HINSTANCE hRichED = LoadLibrary(_T("riched20.dll")); if (hRichED == NULL) { return FALSE; } //创建3个子窗体,富编辑框控件,lable控件,下拉列表控件 g_hLogWnd = CreateWindow(RICHEDIT_CLASS, NULL, WS_CHILD | WS_VSCROLL | WS_HSCROLL | ES_DISABLENOSCROLL | ES_SUNKEN | ES_MULTILINE | ES_READONLY, 0, 0, 0, 0, g_hMainWnd, (HMENU)IDC_RICHED_LOGWND, hInst, NULL); int mask=SendMessage(g_hLogWnd,EM_SETEVENTMASK,0,0); SendMessage(g_hLogWnd,EM_SETEVENTMASK,0,ENM_KEYEVENTS | mask);//发送按键消息消息,在父窗体的消息处理函数中捕获按键消息 g_hPokerSelStatic = CreateWindow(_T("STATIC"), _T("洗牌算法: "), WS_CHILD | SS_RIGHT, 0, 0, 0, 0, g_hMainWnd, (HMENU)IDC_STATIC_POKERSEL, hInst, NULL); g_hPokerSelCombo = CreateWindow(WC_COMBOBOX, NULL, WS_CHILD | WS_VSCROLL | CBS_DROPDOWNLIST | CBS_DISABLENOSCROLL, 0, 0, 0, 0, g_hMainWnd, (HMENU)IDC_COMBO_POKERSEL, hInst, NULL); // 设置子窗口字体,弃用系统默认字体 SendMessage(g_hLogWnd, WM_SETFONT, (WPARAM)GetStockObject(SYSTEM_FIXED_FONT), (LPARAM)FALSE); SendMessage(g_hPokerSelStatic, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), (LPARAM)FALSE); return TRUE; }
3.调整子窗口尺寸大小
// 目的: 处理主窗口的消息。 // WM_COMMAND - 处理应用程序菜单 // WM_PAINT - 绘制主窗口 // WM_DESTROY - 发送退出消息并返回 LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { int wmId, wmEvent; PAINTSTRUCT ps; HDC hdc; switch (message) { case WM_COMMAND: wmId = LOWORD(wParam); wmEvent = HIWORD(wParam); // 分析菜单选择: switch (wmId) { case IDM_ABOUT: DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About); break; case IDM_EXIT: DestroyWindow(hWnd); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } break; case WM_NOTIFY://获取富文本框的按键消息 { NMHDR* hdr=(NMHDR*)lParam; MSGFILTER * pF = (MSGFILTER *)lParam; if(pF->nmhdr.hwndFrom == g_hLogWnd) { if(pF->msg == WM_KEYDOWN) { if(VK_F2 == pF->wParam) { MessageBox(NULL,L"F2",L"快捷键",MB_OK); } } } break; } case WM_SIZE: if (wParam != SIZE_MINIMIZED) { EnumChildWindows(hWnd, EnumChildWndProc, lParam);//调整子窗口尺寸大小 } else { return DefWindowProc(hWnd, message, wParam, lParam); } break; case WM_PAINT: hdc = BeginPaint(hWnd, &ps); // TODO: 在此添加任意绘图代码... EndPaint(hWnd, &ps); break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } // 调整子窗口尺寸大小 BOOL CALLBACK EnumChildWndProc(HWND hWnd, LPARAM lParam) { int id = GetWindowLong(hWnd, GWL_ID); int width = LOWORD(lParam); int height = HIWORD(lParam); int x = 0; int y = 0; int cx = 0; int cy = 0; #define MY_STARTX 0 #define MY_STARTY 4 #define MY_CHECKBOX_WIDTH 100 #define MY_BTN_HEIGHT 24 #define MY_BTN_WIDTH 100 if ((width < MY_BTN_WIDTH) || (height < MY_BTN_HEIGHT)) { return FALSE; } if (id == IDC_STATIC_POKERSEL) { x = MY_STARTX; y = MY_STARTY + 4; cx = 70; cy = MY_BTN_HEIGHT - 4; } else if (id == IDC_COMBO_POKERSEL) { x = 70; y = MY_STARTY; cx = 120; cy = 160; } else if (id == IDC_RICHED_LOGWND) { x = MY_STARTX; y = MY_STARTY + MY_BTN_HEIGHT + MY_STARTY; cx = width; cy = height - (MY_STARTY + MY_BTN_HEIGHT + MY_STARTY); } else { return TRUE; } //WriteLog(LOG_INFO, _T("初始化完成,%d,%d开始运行..."),23,45); MoveWindow(hWnd, x, y, cx, cy, TRUE); ShowWindow(hWnd, SW_SHOW); return TRUE; }
// 最多允许一次输出日志的字符数量 #define MAX_LOG_LEN 256 // 有效的字符数量,(最大值除去回车换行和结束符) #define VALID_LOG_LEN (MAX_LOG_LEN - 3) static const TCHAR* s_logLevelString[] = { _T("INFO"), _T("WARNING"), _T("ERROR"), _T("DEBUG") }; void WriteLog(LOG_LEVEL level, TCHAR* fmt, ...) { //if ((level & s_logCurLevel) == 0) { return; } if (fmt == NULL) { return; } if (level > LOG_DEBUG) { level = LOG_DEBUG; } int len = 0; int index = 0; SYSTEMTIME time = { 0 }; TCHAR szTime[32] = { 0 }; TCHAR szLogBuf[MAX_LOG_LEN] = { 0 }; if (level == LOG_INFO) { index = 0; } else if (level == LOG_WARN) { index = 1; } else if (level == LOG_ERROR) { index = 2; } else if (level == LOG_DEBUG) { index = 3; } GetLocalTime(&time); _stprintf_s(szTime, sizeof(szTime) / sizeof(szTime[0]), _T("%04d-%02d-%02d %02d:%02d:%02d"), time.wYear, time.wMonth, time.wDay, time.wHour, time.wMinute, time.wSecond); // time len += _stprintf_s(szLogBuf + len, VALID_LOG_LEN - len, _T("[")); len += _stprintf_s(szLogBuf + len, VALID_LOG_LEN - len, _T("%s"), szTime); len += _stprintf_s(szLogBuf + len, VALID_LOG_LEN - len, _T("]")); // log type len += _stprintf_s(szLogBuf + len, VALID_LOG_LEN - len, _T(" %s: "), s_logLevelString[index]); // log message va_list va; va_start(va, fmt); int nStrLen = (int)_vsctprintf(fmt, va); if (nStrLen >= MAX_LOG_LEN - 30) { index = 1; len += _stprintf_s(szLogBuf, VALID_LOG_LEN - len, _T(" [WARNING]: MESSAGE TOO LONG TO BE LOGGED!\r\n")); va_end(va); goto READY_TO_WRITE_LOG; } len += _vstprintf_s(szLogBuf + len, VALID_LOG_LEN - len, fmt, va); va_end(va); len += _stprintf_s(szLogBuf + len, VALID_LOG_LEN - len, _T("\r\n")); READY_TO_WRITE_LOG: GETTEXTLENGTHEX gtlex; gtlex.codepage = 1200; gtlex.flags = GTL_DEFAULT; int nCurLen; nCurLen = (int)SendMessage(g_hLogWnd, EM_GETTEXTLENGTHEX, (WPARAM)>lex, 0); CHARRANGE cr; cr.cpMin = nCurLen; cr.cpMax = -1; // 将文本追加到末尾 SendMessage(g_hLogWnd, EM_EXSETSEL, 0, (LPARAM)&cr); SendMessage(g_hLogWnd, EM_REPLACESEL, (WPARAM)&cr, (LPARAM)szLogBuf); // 设置刚追加到末尾的文本的颜色与字符集 SendMessage(g_hLogWnd, EM_EXSETSEL, 0, (LPARAM)&cr); CHARFORMAT cf; cf.cbSize = sizeof(CHARFORMAT); SendMessage(g_hLogWnd, EM_GETCHARFORMAT, (WPARAM)SCF_SELECTION, (LPARAM)&cf); cr.cpMax = cr.cpMin = -1; SendMessage(g_hLogWnd, EM_EXSETSEL, 0, (LPARAM)&cr); // 将滚动条移到最底端 SendMessage(g_hLogWnd, WM_VSCROLL, (WPARAM)SB_BOTTOM, 0); }5.效果图
RichEdit使用手册