// 这段 MFC 示例源代码演示如何使用 MFC Microsoft Office Fluent 用户界面 // (“Fluent UI”)。该示例仅供参考, // 用以补充《Microsoft 基础类参考》和 // MFC C++ 库软件随附的相关电子文档。 // 复制、使用或分发 Fluent UI 的许可条款是单独提供的。 // 若要了解有关 Fluent UI 许可计划的详细信息,请访问 // https://go.microsoft.com/fwlink/?LinkId=238214. // // 版权所有(C) Microsoft Corporation // 保留所有权利。 #include "stdafx.h" #include "framework.h" #include "IRControlWnd.h" #include "Resource.h" #include "MainFrm.h" #include "VideoCapture.h" #include #ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[] = __FILE__; #define new DEBUG_NEW #endif ///////////////////////////////////////////////////////////////////////////// // CResourceViewBar unsigned char TwoHexChar2Char(char ch1, char ch2) { char Numb1; char Numb2; if (ch1 >= 'A') Numb1 = (toupper(ch1) - '0' - 7) * 16; else Numb1 = (ch1 - '0') * 16; if (ch2 >= 'A') Numb2 = (toupper(ch2) - '0' - 7); else Numb2 = (ch2 - '0'); return (Numb1 + Numb2); } COLORREF HexColor2RGB(std::string strHexColor) { DWORD r = TwoHexChar2Char(strHexColor[0], strHexColor[1]); DWORD g = TwoHexChar2Char(strHexColor[2], strHexColor[3]); DWORD b = TwoHexChar2Char(strHexColor[4], strHexColor[5]); return RGB(r, g, b); } CIRControlWnd::CIRControlWnd() noexcept { m_nComboHeight = 0; } CIRControlWnd::~CIRControlWnd() { FreeLogLibarary(); for (std::vector::iterator it = m_vtBtnInfo.begin(); it != m_vtBtnInfo.end(); it++) { if (it->pBTN) it->pBTN->DestroyWindow(); it->pBTN = NULL; } m_vtBtnInfo.clear(); } // 重启进程按钮id; #define ID_BUTTON_RESTART_PROC 1 // 复制框控件id; #define ID_CHECKBOX_SIGNAL_TYPE 2 // 下拉框控件id; #define ID_COMBOBOX_SIGNAL_FILE 3 BEGIN_MESSAGE_MAP(CIRControlWnd, CDockablePane) ON_WM_CREATE() ON_WM_SIZE() ON_COMMAND(ID_EXPAND_ALL, OnExpandAllProperties) ON_UPDATE_COMMAND_UI(ID_EXPAND_ALL, OnUpdateExpandAllProperties) ON_COMMAND(ID_SORTPROPERTIES, OnSortProperties) ON_UPDATE_COMMAND_UI(ID_SORTPROPERTIES, OnUpdateSortProperties) ON_COMMAND(ID_PROPERTIES1, OnProperties1) ON_UPDATE_COMMAND_UI(ID_PROPERTIES1, OnUpdateProperties1) ON_COMMAND(ID_PROPERTIES2, OnProperties2) ON_UPDATE_COMMAND_UI(ID_PROPERTIES2, OnUpdateProperties2) ON_WM_SETFOCUS() ON_WM_SETTINGCHANGE() ON_WM_PAINT() // 信号按钮; ON_COMMAND_RANGE(BTNID, BTNID + 100, OnSignalBtnClick) ON_UPDATE_COMMAND_UI_RANGE(BTNID, BTNID + 100, OnUpdateSignalBtn) // checkbox ON_UPDATE_COMMAND_UI(ID_CHECKBOX_SIGNAL_TYPE, OnUpdateCheckBox) ON_COMMAND(ID_CHECKBOX_SIGNAL_TYPE, OnCheckBoxClicked) // ON_CBN_SELCHANGE(ID_COMBOBOX_SIGNAL_FILE, &CIRControlWnd::OnCbnSelchangeSignal) ON_UPDATE_COMMAND_UI(ID_BUTTON_RESTART_PROC, OnUpdateBtnRestartProc) ON_COMMAND(ID_BUTTON_RESTART_PROC, OnBtnRestartProcClicked) END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CResourceViewBar 消息处理程序 void CIRControlWnd::AdjustLayout() { if (GetSafeHwnd() == nullptr || (AfxGetMainWnd() != nullptr && AfxGetMainWnd()->IsIconic())) { return; } CRect rectClient; GetClientRect(rectClient); m_btnRestart.SetWindowPos(nullptr, rectClient.left + 5, rectClient.top + 5, 120, m_nComboHeight, SWP_NOACTIVATE | SWP_NOZORDER); m_wndSignalCheck.SetWindowPos(nullptr, rectClient.left + 130, rectClient.top + 5, 120, m_nComboHeight, SWP_NOACTIVATE | SWP_NOZORDER); m_wndSignalCombo.SetWindowPos(nullptr, rectClient.left + 5, rectClient.top + m_nComboHeight + 10, 245, m_nComboHeight + 210, SWP_NOACTIVATE | SWP_NOZORDER); #if __PANE_DLG__ m_dlgIRControl.SetWindowPos(nullptr, rectClient.left, rectClient.top + m_nComboHeight + 50, rectClient.Width(), rectClient.Height(), SWP_NOACTIVATE); #endif } int CIRControlWnd::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CDockablePane::OnCreate(lpCreateStruct) == -1) return -1; CRect rectDummy; rectDummy.SetRectEmpty(); // 创建组合: const DWORD dwViewStyle = WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | WS_BORDER | CBS_SORT | WS_CLIPSIBLINGS | WS_CLIPCHILDREN; if (!m_btnRestart.Create(_T("重启遥控器服务进程"), WS_CHILD | WS_VISIBLE, rectDummy, this, ID_BUTTON_RESTART_PROC)) { TRACE0("未能创建遥控器组合 \n"); return -1; // 未能创建 } if (!m_wndSignalCheck.Create(_T("通用遥控器选择"), WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX, rectDummy, this, ID_CHECKBOX_SIGNAL_TYPE)) { TRACE0("未能创建信号集下拉框 \n"); return -1; // 未能创建 } m_wndSignalCheck.SetCheck(Global::g_Config.bGenerics ? BST_CHECKED : BST_UNCHECKED); m_wndSignalCheck.m_bHighlightChecked = TRUE; // CMFCButton只能用图标来显示check; m_wndSignalCheck.SetImage(IDB_UNCHECKED); m_wndSignalCheck.SetCheckedImage(IDB_CHECKED); m_wndSignalCheck.m_bTransparent = FALSE; m_wndSignalCheck.m_bDrawFocus = FALSE; m_wndSignalCheck.m_nFlatStyle = CMFCButton::BUTTONSTYLE_FLAT; m_wndSignalCheck.SizeToContent(); if (!m_wndSignalCombo.Create(dwViewStyle| WS_VSCROLL, rectDummy, this, ID_COMBOBOX_SIGNAL_FILE)) { TRACE0("未能创建信号集下拉框 \n"); return -1; // 未能创建 } LoadSignals(); CRect rectCombo; m_wndSignalCombo.GetClientRect(&rectCombo); m_nComboHeight = rectCombo.Height(); #if __PANE_DLG__ if (!m_dlgIRControl.Create(IDD_DLG_IRCONTROL, this)) { TRACE0("未能创建遥控器主窗口 \n"); return -1; // 未能创建 } m_dlgIRControl.ShowWindow(SW_SHOW); #else Loadlayout(m_vtBtnInfo); #endif // 设置最小窗体; SetMinSize((530, 260)); // 校正布局; AdjustLayout(); ////////////////////////////////////////////////////////////////////////// // 启动红老鼠; if (!LoadLogLibarary()) { AfxMessageBox("加载遥控dll失败,请检测dll是否正常!"); } StartIRDevice(FALSE); return 0; } void CIRControlWnd::OnSize(UINT nType, int cx, int cy) { CDockablePane::OnSize(nType, cx, cy); TRACE2("坐标:%d,%d\n", cx, cy); AdjustLayout(); } void CIRControlWnd::OnExpandAllProperties() { //m_wndPropList.ExpandAll(); } void CIRControlWnd::OnUpdateExpandAllProperties(CCmdUI* /* pCmdUI */) { } void CIRControlWnd::OnSortProperties() { //m_wndPropList.SetAlphabeticMode(!m_wndPropList.IsAlphabeticMode()); } void CIRControlWnd::OnUpdateSortProperties(CCmdUI* pCmdUI) { //pCmdUI->SetCheck(m_wndPropList.IsAlphabeticMode()); } void CIRControlWnd::OnProperties1() { // TODO: 在此处添加命令处理程序代码 } void CIRControlWnd::OnUpdateProperties1(CCmdUI* /*pCmdUI*/) { // TODO: 在此处添加命令更新 UI 处理程序代码 } void CIRControlWnd::OnProperties2() { // TODO: 在此处添加命令处理程序代码 } void CIRControlWnd::OnUpdateProperties2(CCmdUI* /*pCmdUI*/) { // TODO: 在此处添加命令更新 UI 处理程序代码 } void CIRControlWnd::OnSetFocus(CWnd* pOldWnd) { CDockablePane::OnSetFocus(pOldWnd); } void CIRControlWnd::OnSettingChange(UINT uFlags, LPCTSTR lpszSection) { CDockablePane::OnSettingChange(uFlags, lpszSection); //SetPropListFont(); } void CIRControlWnd::OnCbnSelchangeSignal() { CString strSignal; int nCurSel = m_wndSignalCombo.GetCurSel(); if ( nCurSel != CB_ERR ) { std::string signalpath; m_wndSignalCombo.GetLBText(nCurSel, strSignal); // 保存到配置文件中; Global::g_Config.use_signal = strSignal.GetString(); WritePrivateProfileString("ir-device", "use-signal", strSignal.GetString(), Global::g_szConfig); } DisableSignalBtn(); ReLoadSignalXml(); } void CIRControlWnd::SetPropListFont() { ::DeleteObject(m_fntPropList.Detach()); LOGFONT lf; afxGlobalData.fontRegular.GetLogFont(&lf); NONCLIENTMETRICS info; info.cbSize = sizeof(info); afxGlobalData.GetNonClientMetrics(info); lf.lfHeight = info.lfMenuFont.lfHeight; lf.lfWeight = info.lfMenuFont.lfWeight; lf.lfItalic = info.lfMenuFont.lfItalic; m_fntPropList.CreateFontIndirect(&lf); //m_wndObjectCombo.SetFont(&m_fntPropList); } void CIRControlWnd::StartIRDevice(BOOL bReStart) { std::thread t([&](BOOL _bReStart_) { // 结束进程; if (_bReStart_ && g_CloseApp) g_CloseApp(); // 默认加载配置的信号集文件; std::string signale = Global::g_Config.bGenerics ? Global::g_Config.signaldir + "\\general\\" : Global::g_Config.signaldir + "\\product\\"; signale.append(Global::g_Config.use_signal + ".xml"); if (!PathFileExists(signale.c_str())) { m_wndSignalCombo.SetCurSel(-1); signale = ".\\default.xml"; } else { m_wndSignalCombo.SelectString(0, Global::g_Config.use_signal.c_str()); } if ( !g_IsAppRunning(Global::g_Config.redratpath.c_str()) ) { if (g_StartIRApp(Global::g_Config.redratpath.c_str(), signale.c_str(), 40000)) { TRACE("启动红老鼠进程启动成功\r"); } else { TRACE("启动红老鼠进程启动失败\r"); AfxMessageBox("启动红老鼠进程启动失败!"); return 0; } } BOOL bRet = FALSE; // 连接服务器; for (int i = 0; i < 5; i++) { if ((bRet = g_Connect(_T("127.0.0.1"), 40000))) break; Sleep(1000); } if (!bRet) AfxMessageBox("连接红老鼠服务端失败,请重启设备!"); // 更新按钮状态; UpdateSignalBtnStatus(); // 获取设备列表,以逗号分隔; std::string devices = g_getDeviceNames(); if (devices.size() == 0) { AfxMessageBox("当前无红老鼠设备连接!"); } return 1; }, bReStart); t.detach(); } void CIRControlWnd::ReLoadSignalXml() { std::string signaldir,signalpath; if (Global::g_Config.bGenerics) { signaldir = Global::g_Config.signaldir + "\\general\\"; } else { signaldir = Global::g_Config.signaldir + "\\product\\"; } signalpath = signaldir; signalpath.append(Global::g_Config.use_signal + ".xml"); if (!PathFileExists(signalpath.c_str())) { AfxMessageBox(_T("该信号文件不存在!")); // 设置默认的; CString strSignal; m_wndSignalCombo.SetCurSel(0); m_wndSignalCombo.GetLBText(0, strSignal); signalpath = signaldir; signalpath.append(strSignal.GetString()); signalpath.append(".xml"); // 保存到配置文件中; Global::g_Config.use_signal = strSignal.GetString(); WritePrivateProfileString("ir-device", "use-signal", strSignal.GetString(), Global::g_szConfig); } else // 切换通用类型时用到; { m_wndSignalCombo.SelectString(0, Global::g_Config.use_signal.c_str()); } // 加载指定目录的xml信号集文件; if (!g_loadSignalDataSet(signalpath.c_str())) { TRACE("加载信号集文件失败\r"); } else { TRACE("加载信号集文件成功\r"); UpdateSignalBtnStatus(); } } void CIRControlWnd::LoadSignals() { filehelper fh; fh.getfolderfiles((Global::g_Config.signaldir + "\\general\\").c_str(), NULL, &m_vtsignal_gen); fh.getfolderfiles((Global::g_Config.signaldir + "\\product\\").c_str(), NULL, &m_vtsignal_pro); // 添加到combobox中; if (Global::g_Config.bGenerics ) { m_wndSignalCombo.ResetContent(); for ( auto it : m_vtsignal_gen) { m_wndSignalCombo.AddString(fh.getfilename(it).c_str()); } } else { m_wndSignalCombo.ResetContent(); for (auto it : m_vtsignal_pro) { m_wndSignalCombo.AddString(fh.getfilename(it).c_str()); } } } void CIRControlWnd::Loadlayout(std::vector& vt) { // 解析xml; std::string path; path.append(Global::g_szCurModuleDir); path.append("layout.xml"); tinyxml2::XMLDocument doc; if (tinyxml2::XML_SUCCESS != doc.LoadFile(path.c_str())) { return; } vt.clear(); std::string data; tinyxml2::XMLElement* pXmlRoot = NULL; if ((pXmlRoot = doc.RootElement()) != NULL) { if (_tcsicmp(pXmlRoot->Value(), "ButtonList") == 0) { // 子项; tinyxml2::XMLElement* pXmlElent = pXmlRoot->FirstChildElement(); while (pXmlElent) { BtnInfo btninfo; if (_tcsicmp(pXmlElent->Value(), _T("ITEM")) == 0) { tinyxml2::XMLElement* pItem = pXmlElent->FirstChildElement(); while (pItem) { if (_tcsicmp(pItem->Value(), _T("NAME")) == 0) { btninfo.name = pItem->GetText(); } else if (_tcsicmp(pItem->Value(), _T("WIDTH")) == 0) { data = pItem->GetText(); btninfo.width = _ttol(data.c_str()); } else if (_tcsicmp(pItem->Value(), _T("HEIGHT")) == 0) { data = pItem->GetText(); btninfo.height = _ttol(data.c_str()); } else if (_tcsicmp(pItem->Value(), _T("COLOR")) == 0) { data = pItem->GetText(); btninfo.color = HexColor2RGB(data); } btninfo.pBTN = new CMFCButton(); pItem = pItem->NextSiblingElement(); } } vt.push_back(btninfo); pXmlElent = pXmlElent->NextSiblingElement(); } } } int sx = 0, sy = m_nComboHeight*2+15; int i = 0, id = 10000; DWORD dwStyle = WS_CHILD | WS_VISIBLE; for (std::vector::iterator it = vt.begin(); it != vt.end(); it++) { if (i != 0 && i % 4 == 0) {//换行; sy += it->height + 5; } sx = (i % 4) * it->width + (i % 4 + 1) * 5; it->pBTN->Create(it->name.c_str(), dwStyle, CRect(sx, sy, sx + it->width, sy + it->height), this, BTNID + i); // 设置透明false以显示背景色 it->pBTN->m_bTransparent = FALSE; it->pBTN->m_bDontUseWinXPTheme = TRUE; // 设置背景色; it->pBTN->SetFaceColor(it->color, TRUE); // 消除单击时黑色内圈; it->pBTN->m_bDrawFocus = FALSE; // 设置按钮扁平样式; it->pBTN->m_nFlatStyle = CMFCButton::FlatStyle::BUTTONSTYLE_FLAT; // 设置鼠标形状; it->pBTN->SetMouseCursorHand(); // 存入map中; m_map_btn.insert(std::pair(BTNID+i, *it)); i++; } } // 如果CDockablePane无控件,改变大小时背景会刷新失败; // 所以要重载onpaint; void CIRControlWnd::OnPaint() { CPaintDC dc(this); // device context for painting // TODO: 在此处添加消息处理程序代码 // 不为绘图消息调用 CDockablePane::OnPaint(); CRect rc; GetClientRect(rc); CBrush brush; brush.CreateSolidBrush(0xFFEFD5); dc.FillRect(&rc, &brush); } void CIRControlWnd::OnSignalBtnClick(UINT uId) // 发送遥控信号; { CWnd* pWnd = GetFocus(); int id = pWnd->GetDlgCtrlID(); if (id >= BTNID && id <= BTNID + 100) { CString text; pWnd->GetWindowText(text); // 发送单信号; if (g_sendSignal(text.GetString(), 1, 20)) { TRACE("发送单信号成功\n"); } else { TRACE("发送单信号失败\n"); } } } void CIRControlWnd::OnUpdateSignalBtn(CCmdUI* pCmdUI) { pCmdUI->Enable(m_map_btn.find(pCmdUI->m_nID)->second.bEnable); } void CIRControlWnd::OnUpdateCheckBox(CCmdUI* pCmdUI) { pCmdUI->Enable(); } void CIRControlWnd::OnCheckBoxClicked() { Global::g_Config.bGenerics = m_wndSignalCheck.IsChecked(); // 保存到配置文件中; WritePrivateProfileString("ir-device", "generics", Global::g_Config.bGenerics ? "1" : "0", Global::g_szConfig); // 添加到combobox中; if (Global::g_Config.bGenerics) { m_wndSignalCombo.ResetContent(); for (auto it : m_vtsignal_gen) { m_wndSignalCombo.AddString(filehelper::getfilename(it).c_str()); } } else { m_wndSignalCombo.ResetContent(); for (auto it : m_vtsignal_pro) { m_wndSignalCombo.AddString(filehelper::getfilename(it).c_str()); } } DisableSignalBtn(); ReLoadSignalXml(); } void CIRControlWnd::OnUpdateBtnRestartProc(CCmdUI* pCmdUI) { pCmdUI->Enable(TRUE); } void CIRControlWnd::OnBtnRestartProcClicked() // 重启红老鼠; { DisableSignalBtn(); StartIRDevice(); } void CIRControlWnd::UpdateSignalBtnStatus() { // 获取信号集; if (g_getSignalsName ) { // 获取信号数据集,以\n分隔; std::string data = g_getSignalsName(); CString signals = data.append(1, '\n').c_str(); signals.MakeUpper(); for ( std::vector::iterator it = m_vtBtnInfo.begin(); it != m_vtBtnInfo.end(); it++) { if ( signals.Find((it->name+'\n').c_str()) == -1 ) { it->bEnable = false; } else { it->bEnable = true; } } } }