// SMachine.cpp: 实现文件 // //#include #include "resource.h" // 主符号 #include "stdafx.h" #include "SMachineDlg.h" //控件ID #define Dlg_Button_ManualTriggered 1 //手动触发事件按钮 #define Dlg_Button_JumpToNext 2 //跳转至下一状态确认按钮 #define Dlg_Edit_ManualEventName 101 //手动触发事件名称 #define Dlg_Edit_NextStateName 102 //自动动触发事件名称 #define Dlg_Edit_WaitEventList 103 //当前等待事件列表 #define Dlg_Edit_RunHistory 104 //执行历史记录 #define Dlg_Radio_GroupJump 301 //跳转方式 #define Dlg_Radio_ManualJump 302 //手动跳转 #define Dlg_Radio_AutoJump 303 //自动跳转 #define Dlg_Check_1 201 #define Dlg_Check_2 202 SMachineDlg::CallMap SMachineDlg::g_HandleDlgMap; //消息处理窗口句柄集 static int glo_BaseUnitX = LOWORD(GetDialogBaseUnits()); static int glo_BaseUnitY = HIWORD(GetDialogBaseUnits()); SMachineDlg::SMachineDlg(string title, string windowClass, SMDlgCallback object) { m_strTitle = title; m_strWindowClass = windowClass; m_DlgCallback = object; } SMachineDlg::~SMachineDlg() { if(m_hWnd) StopThread(); } HWND SMachineDlg::GetWindowHandle() { return m_hWnd; } ATOM SMachineDlg::RegisterWindowClass(HINSTANCE hInstance) { WNDCLASSEX winDlg; memset(&winDlg, 0, sizeof(WNDCLASSEX)); winDlg.lpszClassName = m_strWindowClass.c_str(); //设置类名称 winDlg.cbSize = sizeof(WNDCLASSEX); //窗口类内存大小 winDlg.cbClsExtra = 0; //为类额外分配内存,一般为0 winDlg.cbWndExtra = 0; //为窗口额外分配内存,一般为0 winDlg.style = CS_HREDRAW | CS_VREDRAW; //设置窗口格式,一般设置为水平重画与垂直重画:CS_HREDRAW | CS_VREDRAW winDlg.hIcon = LoadIcon(NULL, IDI_APPLICATION); //设置程序图标 winDlg.hCursor = LoadCursor(NULL, IDC_ARROW); //设置程序光标 winDlg.hbrBackground = (HBRUSH)GetStockObject(BLACK_PEN); //设置程序背景色:(HBRUSH)(COLOR_WINDOW + 1),(HBRUSH)GetStockObject(GRAY_BRUSH) //winDlg.lpszMenuName = MAKEINTRESOURCE(IDC_WIN32UI); //设置菜单名称 //winDlg.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL)); // winDlg.lpfnWndProc = WndTotalProc; //窗口的回调函数,也就是窗口接收到消息后,交给哪个函数处理 if (hInstance) //程序实例,这里就用到了WinMain函数的第一个参数hInstance winDlg.hInstance = hInstance; else winDlg.hInstance = GetModuleHandle(NULL); return RegisterClassEx(&winDlg); //填入要注册的窗口结构 } HWND SMachineDlg::OpenWindow(int nCmdShow) { m_hWnd = CreateWindow( m_strWindowClass.c_str(), //窗口类名,也就是上面注册窗口类时填的类名 m_strTitle.c_str(), //窗口名,也就是窗口显示时,左上角显示的名称 WS_OVERLAPPED|WS_BORDER|WS_CAPTION|WS_SYSMENU, //窗口风格,一般填WS_OVERLAPPEDWINDOW即可,这样创建的窗口就有最大化,最小化等等等等属性 CW_USEDEFAULT, //窗口最开始被创建位置,这里填X坐标,一般默认CW_USEDEFAULT即可 CW_USEDEFAULT, //窗口最开始被创建位置,这里填Y坐标,一般默认CW_USEDEFAULT即可 100 * glo_BaseUnitX, //窗口创建的宽度,一般默认CW_USEDEFAULT即可 25 * glo_BaseUnitY, //窗口创建的高度,一般默认CW_USEDEFAULT即可 NULL, //父窗口的句柄,没有,填NULL NULL, //菜单句柄,没有,填NULL GetModuleHandle(NULL), //应用程序实例,这里就又用到了WinMain的第一个参数 NULL);//额外的数据,挺复杂的,咱们也不需要,填NULL就行了 if (m_hWnd) { g_HandleDlgMap[m_hWnd] = this; ShowWindow(m_hWnd, nCmdShow); //显示窗口:SW_SHOWNORMAL if (UpdateWindow(m_hWnd)) //更新窗口客户区 { m_ExitFlag = GetExitEvt(); //添加界面元素 CreateUIElement(m_hWnd); } } else { //mLog::FERROR("Create Window[{$}] failed", m_strTitle.c_str()); } return m_hWnd; } void SMachineDlg::CreateUIElement(HWND& hMainWnd) { //创建元素 auto FUN_CreateElement = [this, hMainWnd](int ID_Element) -> void { auto item = m_ElementMap.find(ID_Element); if (item != m_ElementMap.end()) { if(nullptr == item->second.m_hHandle) item->second.m_hHandle = CreateWindow( item->second.m_strClassName.c_str(), item->second.m_strWindowName.c_str(), WS_CHILD | WS_VISIBLE | item->second.m_nStyle, item->second.m_nPosX * glo_BaseUnitX, item->second.m_nPosY * glo_BaseUnitY, item->second.m_nXsize * glo_BaseUnitX, item->second.m_nYsize * glo_BaseUnitY, hMainWnd, (HMENU)ID_Element, (HINSTANCE)GetWindowLongPtr(hMainWnd, GWLP_HINSTANCE), NULL); if (item->second.m_hHandle) { ShowWindow(item->second.m_hHandle, item->second.m_nShow); UpdateWindow(item->second.m_hHandle); } else { //mLog::FERROR("Create [{$}:{$}] failed", item->second.m_strClassName.c_str(), item->second.m_strWindowName.c_str()); } } else { //mLog::FDEBUG("[{$}:{$}] already Create", item->second.m_strClassName.c_str(), item->second.m_strWindowName.c_str()); } }; m_ElementMap[Dlg_Button_ManualTriggered] = stuWindowElement("button", "ManualTriggered", BS_PUSHBUTTON, 1, 1, 20, 2, SW_SHOW); m_ElementMap[Dlg_Edit_ManualEventName] = stuWindowElement("edit", "ManualEventName", ES_MULTILINE, 27, 1, 20, 2, SW_SHOW); m_ElementMap[Dlg_Button_JumpToNext] = stuWindowElement("button", "JumpToNext", BS_PUSHBUTTON, 1, 4, 20, 2, SW_SHOW); m_ElementMap[Dlg_Edit_NextStateName] = stuWindowElement("edit", "NextStateName", ES_MULTILINE | ES_READONLY, 27, 4, 20, 2, SW_SHOW); m_ElementMap[Dlg_Radio_GroupJump] = stuWindowElement("button", "Auto or Manual Jump", BS_GROUPBOX, 0, 7, 48, 4, SW_SHOW); m_ElementMap[Dlg_Radio_ManualJump] = stuWindowElement("button", "AutoJump", BS_AUTORADIOBUTTON, 1, 8, 20, 2, SW_SHOW); m_ElementMap[Dlg_Radio_AutoJump] = stuWindowElement("button", "ManualJump", BS_AUTORADIOBUTTON, 27, 8, 20, 2, SW_SHOW); m_ElementMap[Dlg_Edit_WaitEventList] = stuWindowElement("edit", "WaitEventList", ES_MULTILINE | ES_READONLY | ES_AUTOVSCROLL, 49, 1, 48, 10, SW_SHOW); m_ElementMap[Dlg_Edit_RunHistory] = stuWindowElement("edit", "RunHistory", ES_MULTILINE | ES_READONLY | ES_AUTOVSCROLL, 1, 12, 96, 10, SW_SHOW); for (auto& item : m_ElementMap) { FUN_CreateElement(item.first); } } bool SMachineDlg::CloseWindow() { if (m_hWnd) { CallMap::iterator iter = g_HandleDlgMap.find(m_hWnd); if (iter != g_HandleDlgMap.end()) { g_HandleDlgMap.erase(iter); } m_hWnd = nullptr; } return true; } bool SMachineDlg::OnStartThread() { //1.向系统注册一个窗体类 RegisterWindowClass(); //2.根据窗体类创建窗口 return OpenWindow(SW_SHOW); } bool SMachineDlg::OnEndThread() { return CloseWindow(); } bool SMachineDlg::Exec() //只会执行一次 { MSG msg; while (WaitForSingleObject(m_ExitFlag, 0) == WAIT_TIMEOUT) { //3.进入消息循环 if (GetMessage(&msg, //拿到的消息 m_hWnd, //拿哪个窗口的消息,一般填NULL,即拿属于该线程所有窗口的消息 0, //过滤消息,最小值,一般填0 0) //过滤消息,最大值,一般填0,当两个均为0,则不进行过滤 ) { TranslateMessage(&msg); //消息转换,如将WMWM_KEYDOWN和WM_KEYUP翻译成一个WM_CHAR消息 DispatchMessage(&msg); //该函数就是把消息派发给对应的窗口 } else { return false; } } return false; } //窗口函数 LRESULT SMachineDlg::WndTotalProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { CallMap::iterator iter = g_HandleDlgMap.find(hWnd); if (iter != g_HandleDlgMap.end()) { switch (message)//通过判断消息进行消息响应 { case WM_CREATE: //应用程序创建一个窗口 { return 0; }break; case WM_DESTROY: //一个窗口被销毁 { PostQuitMessage(0); //发出WM_QUIT消息,结束消息循环 iter->second->StopThread(); return 0; }break; case WM_CLOSE: //当一个窗口或应用程序要关闭时发送一个信号 { DestroyWindow(hWnd); //销毁窗口并发送WM_DESTROY消息,但是程序没有退出 return 0; }break; //case WM_PAINT: //{ // PAINTSTRUCT ps; // RECT rect; // HDC hdc = BeginPaint(hWnd, &ps); // SetRect(&rect, 10, 10, 300, 200); // FrameRect(hdc, &rect, (HBRUSH)GetStockObject(BLACK_BRUSH)); // GetClientRect(hWnd, &rect); // rect.left += 20; // rect.top += 2; // //SetTextColor(hdc, RGB(255,0,0)); //可以用RGB三原色设置文本颜色 // DrawText(hdc, TEXT(" Hello, Dev-C++! "), -1, &rect, DT_SINGLELINE | DT_TOP | DT_LEFT); // EndPaint(hWnd, &ps); // return 0; //}break; case WM_COMMAND: //各控件的_click()事件 { switch (LOWORD(wParam)) { case LOWORD(Dlg_Button_ManualTriggered): { if (iter->second->m_DlgCallback) { // 获取编辑控件的文本长度 int length = GetWindowTextLength(iter->second->m_ElementMap[Dlg_Edit_ManualEventName].m_hHandle) + 1; // 创建一个字符串缓冲区 std::vector buffer(length); // 获取编辑控件的文本 GetWindowText(iter->second->m_ElementMap[Dlg_Edit_ManualEventName].m_hHandle, buffer.data(), length); string temp = buffer.data(); iter->second->m_DlgCallback("TriggerEvent", temp); } return 0; }break; case LOWORD(Dlg_Button_JumpToNext): { if (iter->second->m_DlgCallback) { iter->second->m_DlgCallback("SetRunningState", ""); } return 0; }break; case LOWORD(Dlg_Radio_ManualJump): { iter->second->SetJumpMode(1); return 0; }break; case LOWORD(Dlg_Radio_AutoJump): { iter->second->SetJumpMode(0); return 0; }break; } }break; #if 0 //调试使用 case WM_LBUTTONDOWN: // WM_LBUTTONDOWN是鼠标左键按下的事件 { POINT mouse; RECT rect; GetCursorPos(&mouse); GetWindowRect(hWnd, &rect); int mX = mouse.x - rect.left; int mY = mouse.y - rect.top; char x[5]{ 0 }, y[5]{ 0 }; _itoa(mX, x, 10); _itoa(mY, y, 10); string strXy = "坐标(" + string(x) + "," + string(y) + ")"; SetWindowText(iter->second->m_ElementMap[Dlg_Edit_ManualEventName].m_hHandle, strXy.c_str()); return 0; }break; #endif } } return DefWindowProc(hWnd, message, wParam, lParam); //对不感兴趣的消息进行缺省处理,必须有该代码,否则程序有问题 } void SMachineDlg::SetJumpMode(int mode) { switch (mode) { case 0: //auto {EnableWindow(m_ElementMap[Dlg_Button_JumpToNext].m_hHandle, FALSE); EnableWindow(m_ElementMap[Dlg_Edit_NextStateName].m_hHandle, FALSE); SendMessage(m_ElementMap[Dlg_Radio_ManualJump].m_hHandle, BM_SETCHECK, 0, 0); SendMessage(m_ElementMap[Dlg_Radio_AutoJump].m_hHandle, BM_SETCHECK, 1, 0); }break; case 1: //manual { EnableWindow(m_ElementMap[Dlg_Button_JumpToNext].m_hHandle, TRUE); EnableWindow(m_ElementMap[Dlg_Edit_NextStateName].m_hHandle, TRUE); SendMessage(m_ElementMap[Dlg_Radio_ManualJump].m_hHandle, BM_SETCHECK, 1, 0); SendMessage(m_ElementMap[Dlg_Radio_AutoJump].m_hHandle, BM_SETCHECK, 0, 0); }break; default: break; } } void SMachineDlg::SetWaitEventList(string& text) { SetWindowText(m_ElementMap[Dlg_Edit_WaitEventList].m_hHandle, text.c_str()); } void SMachineDlg::SetRunHistory(string& text) { SetWindowText(m_ElementMap[Dlg_Edit_RunHistory].m_hHandle, text.c_str()); }