// IOMonitoringDlg.cpp: 实现文件 // #include "stdafx.h" #include "BondEq.h" #include "afxdialogex.h" #include "IOMonitoringDlg.h" #include "ToolUnits.h" #define TIMER_INIT 1 #define TIMER_READ_PLC_DATA 2 #define TIMER_READ_UPDATE 3 #define LABEL_ID_BEGIN 2000 #define ADDR_WND _T("ADDR_WND") #define ID_MSG_IO_CLICK WM_USER + 101 // CIOMonitoringDlg 对话框 IMPLEMENT_DYNAMIC(CIOMonitoringDlg, CDialogEx) CIOMonitoringDlg::CIOMonitoringDlg(CWnd* pParent /*=nullptr*/) : CDialogEx(IDD_DIALOG_IO_MONITORING, pParent) { m_nCurrentPage = 1; m_nTotalPages = 1; m_nRowsPerPage = 16; m_nCols = 6; } CIOMonitoringDlg::~CIOMonitoringDlg() { for (auto& pair : m_mapFonts) { if (pair.second) { pair.second->DeleteObject(); delete pair.second; } } m_mapFonts.clear(); ClearDynamicControls(); } void CIOMonitoringDlg::DoDataExchange(CDataExchange* pDX) { CDialogEx::DoDataExchange(pDX); DDX_Control(pDX, IDC_STATIC_PAGE_NUMBER, m_staticPageNum); } void CIOMonitoringDlg::SetIOManager(const std::string& machineName) { IOManager manager; manager.loadFromFile(machineName); m_machineName = machineName; // 加载数据 m_displayData = manager.GetMachineData(machineName); // 计算页数 m_nCurrentPage = 1; m_nTotalPages = ((int)m_displayData.size() + m_nRowsPerPage - 1) / m_nRowsPerPage; } void CIOMonitoringDlg::SetPLC(CPLC* pPLC) { ASSERT(pPLC); m_pPLC = pPLC; } CFont* CIOMonitoringDlg::GetOrCreateFont(int nFontSize) { auto it = m_mapFonts.find(nFontSize); if (it != m_mapFonts.end()) { return it->second; } CFont* font = new CFont(); LOGFONT logFont = { 0 }; _tcscpy_s(logFont.lfFaceName, _T("Segoe UI")); logFont.lfHeight = -nFontSize; logFont.lfQuality = CLEARTYPE_QUALITY; font->CreateFontIndirect(&logFont); m_mapFonts[nFontSize] = font; return font; } void CIOMonitoringDlg::SetDefaultFont() { CFont* defaultFont = GetOrCreateFont(12); // 遍历所有控件,应用默认字体 CWnd* pWnd = GetWindow(GW_CHILD); while (pWnd) { pWnd->SetFont(defaultFont, TRUE); pWnd = pWnd->GetNextWindow(); } } void CIOMonitoringDlg::AdjustControls(float dScaleX, float dScaleY) { CWnd* pWnd = GetWindow(GW_CHILD); while (pWnd) { int nCtrlID = pWnd->GetDlgCtrlID(); if (nCtrlID != -1 && m_mapCtrlLayouts.find(nCtrlID) != m_mapCtrlLayouts.end()) { CRect originalRect = m_mapCtrlLayouts[nCtrlID]; CRect newRect( static_cast(originalRect.left * dScaleX), static_cast(originalRect.top * dScaleY), static_cast(originalRect.right * dScaleX), static_cast(originalRect.bottom * dScaleY)); pWnd->MoveWindow(&newRect); AdjustControlFont(pWnd, newRect.Width(), newRect.Height()); } pWnd = pWnd->GetNextWindow(); } } void CIOMonitoringDlg::AdjustControlFont(CWnd* pWnd, int nWidth, int nHeight) { TCHAR szClassName[256]; GetClassName(pWnd->m_hWnd, szClassName, sizeof(szClassName)); // 根据控件高度动态调整字体大小 int fontSize = nHeight / 2; if (fontSize < 8) fontSize = 8; if (fontSize < 24) fontSize = 24; // 获取或创建字体 CFont* pFont = GetOrCreateFont(fontSize); pWnd->SetFont(pFont); pWnd->Invalidate(); // 刷新控件显示 } void CIOMonitoringDlg::UpdatePageInfo() { // 格式化页码信息为 "当前页/总页数" CString pageInfo; pageInfo.Format(_T("%d/%d 页"), m_nCurrentPage, m_nTotalPages); m_staticPageNum.SetWindowText(pageInfo); } void CIOMonitoringDlg::CreateDynamicControls() { CRect rect; GetClientRect(&rect); // 获取按钮的大小 CWnd* pPrevButton = GetDlgItem(IDC_BUTTON_PREV_PAGE); CWnd* pNextButton = GetDlgItem(IDC_BUTTON_NEXT_PAGE); CRect prevButtonRect, nextButtonRect; pPrevButton->GetWindowRect(&prevButtonRect); pNextButton->GetWindowRect(&nextButtonRect); // 转换按钮坐标到对话框的坐标系统 ScreenToClient(&prevButtonRect); ScreenToClient(&nextButtonRect); int buttonHeight = prevButtonRect.Height(); // 按钮的高度 int topMargin = int(rect.Height() * 0.05); // 顶部保留 5% 的高度 int bottomMargin = buttonHeight + topMargin; // 底部保留按钮高度加间距 int sideMargin = topMargin; // 左右间距与顶部间距相同 int groupSpacing = 20; // 两组之间的间距 int verticalSpacing = 10; // 垂直间距 // 每行高度和列宽度 int availableHeight = rect.Height() - topMargin - bottomMargin; int rowHeight = (availableHeight / m_nRowsPerPage) - verticalSpacing; // 控件高度包含间距 int availableWidth = rect.Width() - 2 * sideMargin; // 可用宽度(减去左右间距) int colWidthSmall = availableWidth / 14; // 小宽度列更小 int colWidthLarge = availableWidth * 4 / 14; // 大宽度列比例 int groupWidth = colWidthSmall * 2 + colWidthLarge; // 每组总宽度 UINT id = LABEL_ID_BEGIN; for (int i = 0; i < m_nRowsPerPage; ++i) { // 每一行的起始 Y 坐标 int y = topMargin + i * (rowHeight + verticalSpacing); // 创建第 1 组 (0, 1, 2) int x = sideMargin; // 从左边距开始 CreateStaticControl(++id, x, y, colWidthSmall, rowHeight, _T("OFF"), true, AlignCenter); x += colWidthSmall; CreateStaticControl(++id, x, y, colWidthSmall, rowHeight, _T("X1000"), false, AlignCenter); x += colWidthSmall; CreateStaticControl(++id, x, y, colWidthLarge, rowHeight, _T("描述文本"), false); // 第 2 组起始位置,加上组间距 x += colWidthLarge + groupSpacing; // 创建第 2 组 (3, 4, 5) id++; CWnd* pBtn = CreateStaticControl(id, x, y, colWidthSmall, rowHeight, _T("OFF"), true, AlignCenter, [this, id, i, x, y]() { // 自定义点击事件的逻辑 auto* pControl = static_cast(m_staticControls[i * m_nCols + 3]); CString currentText; pControl->GetWindowText(currentText); PostMessage(ID_MSG_IO_CLICK, id, currentText == _T("OFF") ? 1 : 0); }); x += colWidthSmall; CWnd* pLabel = CreateStaticControl(++id, x, y, colWidthSmall, rowHeight, _T("Y1010"), false, AlignCenter); x += colWidthSmall; CreateStaticControl(++id, x, y, colWidthLarge, rowHeight, _T("描述文本"), false); ::SetProp(pBtn->GetSafeHwnd(), ADDR_WND, pLabel); } } CWnd* CIOMonitoringDlg::CreateStaticControl(UINT id, int x, int y, int width, int height, const CString& text, bool hasBorder, TextAlign alignment, std::function clickCallback) { // 创建动态控件 CBLLabel* pStatic = new CBLLabel(); DWORD style = WS_CHILD | WS_VISIBLE | SS_CENTERIMAGE; // 确保垂直居中 if (!hasBorder) { pStatic->DisableBorder(); } pStatic->Create(text, style, CRect(x, y, x + width, y + height), this, id); // 设置文本对齐方式 pStatic->SetAlignment(alignment); // 设置动态字体调整,并设置字体大小(动态字体会根据控件大小调整) int nSize = height / 3; CFont* pFont = GetOrCreateFont(nSize); pStatic->SetFont(pFont); pStatic->SetFontSize(nSize); pStatic->SetDynamicFont(TRUE); // 设置回调 UserManager& userManager = UserManager::getInstance(); UserRole enRole = userManager.getCurrentUserRole(); if (clickCallback && (enRole == UserRole::SuperAdmin || enRole == UserRole::Operator)) { pStatic->SetClickCallback(clickCallback); pStatic->SetRoundedCorners(TRUE, 5); pStatic->DisableBorder(); } // 存储控件指针 m_staticControls.push_back(pStatic); return pStatic; } CWnd* CIOMonitoringDlg::GetStaticControl(UINT id) { for (auto item : m_staticControls) { TRACE(">>id:%d\n", item->GetDlgCtrlID()); if (item->GetDlgCtrlID() == id) { return item; } } return nullptr; } CString& CIOMonitoringDlg::GetStaticControlAddrText(UINT id, CString& strAddr) { CWnd* pBtn = GetStaticControl(id); if (pBtn != nullptr) { CWnd* pLabel = (CWnd*)::GetProp(pBtn->GetSafeHwnd(), ADDR_WND); if (pLabel != nullptr) { pLabel->GetWindowText(strAddr); } } return strAddr; } void CIOMonitoringDlg::DisplayCurrentPage() { int startIndex = (m_nCurrentPage - 1) * m_nRowsPerPage; int endIndex = min(startIndex + m_nRowsPerPage, static_cast(m_displayData.size())); m_inputStates.clear(); m_outputStates.clear(); m_inputPLCAddresses.clear(); m_outputPLCAddresses.clear(); for (int i = 0; i < m_nRowsPerPage; ++i) { int row = i; if (startIndex + i < endIndex) { const auto& data = m_displayData[startIndex + i]; // 添加状态到容器中 m_inputStates.push_back(FALSE); // 0 列 m_outputStates.push_back(FALSE); // 3 列 // 添加 PLC 地址到容器中 m_inputPLCAddresses.push_back(CString(data.inputAddress.c_str())); // 1 列 m_outputPLCAddresses.push_back(CString(data.outputAddress.c_str())); // 4 列 // 显示控件并设置内容 m_staticControls[row * m_nCols + 0]->SetWindowText(_T("OFF")); m_staticControls[row * m_nCols + 0]->ShowWindow(SW_SHOW); m_staticControls[row * m_nCols + 0]->SetBkColor(RGB(255, 0, 0)); m_staticControls[row * m_nCols + 1]->SetWindowText(CString(data.inputAddress.c_str())); m_staticControls[row * m_nCols + 1]->ShowWindow(SW_SHOW); m_staticControls[row * m_nCols + 2]->SetWindowText(CString(data.inputDescription.c_str())); m_staticControls[row * m_nCols + 2]->ShowWindow(SW_SHOW); m_staticControls[row * m_nCols + 3]->SetWindowText(_T("OFF")); m_staticControls[row * m_nCols + 3]->ShowWindow(SW_SHOW); m_staticControls[row * m_nCols + 3]->SetBkColor(RGB(255, 0, 0)); m_staticControls[row * m_nCols + 4]->SetWindowText(CString(data.outputAddress.c_str())); m_staticControls[row * m_nCols + 4]->ShowWindow(SW_SHOW); m_staticControls[row * m_nCols + 5]->SetWindowText(CString(data.outputDescription.c_str())); m_staticControls[row * m_nCols + 5]->ShowWindow(SW_SHOW); } else { // 隐藏这一行的所有控件 for (int col = 0; col < m_nCols; ++col) { m_staticControls[row * m_nCols + col]->ShowWindow(SW_HIDE); } } } UpdatePageInfo(); } void CIOMonitoringDlg::ClearDynamicControls() { for (auto* pStatic : m_staticControls) { if (pStatic) { pStatic->DestroyWindow(); delete pStatic; } } m_staticControls.clear(); } bool CIOMonitoringDlg::ParsePLCAddress(const CString& address, MC::SOFT_COMPONENT& component, int& addr) { if (address.GetLength() < 2) { return false; } // 提取组件类型(第一个字符) TCHAR componentChar = address[0]; if (address.Left(2) == _T("ZR")) { component = MC::SOFT_COMPONENT::ZR; // 提取数字部分(去除ZR前缀) CString numericAddress = address.Mid(2); addr = _tcstoul(numericAddress, nullptr, 16); return addr != 0 || numericAddress.CompareNoCase(_T("0")) == 0; // 如果是 "0",也认为有效 } // 对于其他组件,按照常规规则处理 CString hexAddress = address.Mid(1); switch (componentChar) { case 'D': component = MC::SOFT_COMPONENT::D; addr = _ttoi(hexAddress); break; case 'M': component = MC::SOFT_COMPONENT::M; addr = _tcstoul(hexAddress, nullptr, 16); break; case 'X': component = MC::SOFT_COMPONENT::X; addr = _tcstoul(hexAddress, nullptr, 16); break; case 'Y': component = MC::SOFT_COMPONENT::Y; addr = _tcstoul(hexAddress, nullptr, 16); break; case 'W': component = MC::SOFT_COMPONENT::W; addr = _tcstoul(hexAddress, nullptr, 16); break; case 'L': component = MC::SOFT_COMPONENT::L; addr = _tcstoul(hexAddress, nullptr, 16); break; case 'S': component = MC::SOFT_COMPONENT::S; addr = _tcstoul(hexAddress, nullptr, 16); break; case 'B': component = MC::SOFT_COMPONENT::B; addr = _tcstoul(hexAddress, nullptr, 16); break; case 'F': component = MC::SOFT_COMPONENT::F; addr = _tcstoul(hexAddress, nullptr, 16); break; default: return false; } // 检查地址是否有效 if (addr == 0 && hexAddress.CompareNoCase(_T("0")) != 0) { return false; } return true; } bool CIOMonitoringDlg::GeneratePLCAddress(MC::SOFT_COMPONENT component, int addr, CString& address, bool bHexFormat) { // 根据组件类型生成前缀 CString prefix; switch (component) { case MC::SOFT_COMPONENT::D: prefix = _T("D"); break; case MC::SOFT_COMPONENT::M: prefix = _T("M"); break; case MC::SOFT_COMPONENT::X: prefix = _T("X"); break; case MC::SOFT_COMPONENT::Y: prefix = _T("Y"); break; case MC::SOFT_COMPONENT::W: prefix = _T("W"); break; case MC::SOFT_COMPONENT::L: prefix = _T("L"); break; case MC::SOFT_COMPONENT::S: prefix = _T("S"); break; case MC::SOFT_COMPONENT::B: prefix = _T("B"); break; case MC::SOFT_COMPONENT::F: prefix = _T("F"); break; case MC::SOFT_COMPONENT::ZR: prefix = _T("ZR"); break; default: return false; // 如果是未知组件类型,返回失败 } // 根据 bHexFormat 判断输出格式 CString strAddr; if (bHexFormat) { strAddr.Format(_T("%X"), addr); // 十六进制格式 } else { strAddr.Format(_T("%d"), addr); // 十进制格式 } // 生成最终的地址字符串 address = prefix + strAddr; return true; } // 处理PLC数据读取的通用方法 void CIOMonitoringDlg::ReadPLCData(MC::SOFT_COMPONENT softComponent, int startAddr, int endAddr, std::function callback) { int nSize; // 检查地址是否有效,以及组件是否匹配 nSize = endAddr - startAddr + 1; if (nSize < 1) { return; } // 读取数据 m_pPLC->readData(softComponent, startAddr, nSize, callback); } void CIOMonitoringDlg::ReadPLCStates() { if (m_displayData.empty()) { return; } auto startData = m_displayData.front(); auto endData = m_displayData.back(); MC::SOFT_COMPONENT startSoftComponent, endSoftComponent; int inputStartAddr, inputEndAddr; ParsePLCAddress(CString(startData.inputAddress.c_str()), startSoftComponent, inputStartAddr); ParsePLCAddress(CString(endData.inputAddress.c_str()), endSoftComponent, inputEndAddr); ASSERT(startSoftComponent == endSoftComponent); // 读取输入数据 ReadPLCData(startSoftComponent, inputStartAddr, inputEndAddr, [this, inputStartAddr](IMcChannel* pChannel, int addr, char* pData, unsigned int nDataSize, int flag) { if (!::IsWindow(m_hWnd)) return; for (auto& data : m_displayData) { int nAddress; MC::SOFT_COMPONENT enComponent; if (ParsePLCAddress(CString(data.inputAddress.c_str()), enComponent, nAddress)) { int nOffset = nAddress - inputStartAddr; if (nOffset >= 0 && nOffset < (int)nDataSize) { int byteIndex = nOffset / 8; int bitIndex = nOffset % 8; data.bInputStates = CToolUnits::getBit(pData[byteIndex], bitIndex); } } } }); // 读取输出数据 int outputStartAddr, outputEndAddr; ParsePLCAddress(CString(startData.outputAddress.c_str()), startSoftComponent, outputStartAddr); ParsePLCAddress(CString(endData.outputAddress.c_str()), endSoftComponent, outputEndAddr); ASSERT(startSoftComponent == endSoftComponent); ReadPLCData(startSoftComponent, outputStartAddr, outputEndAddr, [this, outputStartAddr](IMcChannel* pChannel, int addr, char* pData, unsigned int nDataSize, int flag) { if (!::IsWindow(m_hWnd)) return; for (auto& data : m_displayData) { int nAddress; MC::SOFT_COMPONENT enComponent; if (ParsePLCAddress(CString(data.outputAddress.c_str()), enComponent, nAddress)) { int nOffset = nAddress - outputStartAddr; if (nOffset >= 0 && nOffset < (int)nDataSize) { int byteIndex = nOffset / 8; int bitIndex = nOffset % 8; data.bOutputStates = CToolUnits::getBit(pData[byteIndex], bitIndex); TRACE(">>>> %d %d %d |||| %d\n", nOffset, byteIndex, bitIndex, data.bOutputStates); } } } }); } void CIOMonitoringDlg::UpdatePLCStatesToUI() { int startIndex = (m_nCurrentPage - 1) * m_nRowsPerPage; int endIndex = min(startIndex + m_nRowsPerPage, static_cast(m_displayData.size())); for (int i = 0; i < m_nRowsPerPage; ++i) { int row = i; if (startIndex + i < endIndex) { const auto& data = m_displayData[startIndex + i]; // 设置内容和背景颜色 if (m_inputStates[i] != data.bInputStates) { m_staticControls[row * m_nCols + 0]->SetText(data.bInputStates ? _T("ON") : _T("OFF")); m_staticControls[row * m_nCols + 0]->SetBkColor(data.bInputStates ? RGB(0, 255, 0) : RGB(255, 0, 0)); m_inputStates[i] = data.bInputStates; } if (m_outputStates[i] != data.bOutputStates) { m_staticControls[row * m_nCols + 3]->SetText(data.bOutputStates ? _T("ON") : _T("OFF")); m_staticControls[row * m_nCols + 3]->SetBkColor(data.bOutputStates ? RGB(0, 255, 0) : RGB(255, 0, 0)); m_outputStates[i] = data.bOutputStates; } } } } BEGIN_MESSAGE_MAP(CIOMonitoringDlg, CDialogEx) ON_BN_CLICKED(IDC_BUTTON_PREV_PAGE, &CIOMonitoringDlg::OnBnClickedButtonPrevPage) ON_BN_CLICKED(IDC_BUTTON_NEXT_PAGE, &CIOMonitoringDlg::OnBnClickedButtonNextPage) ON_MESSAGE(ID_MSG_IO_CLICK, &CIOMonitoringDlg::OnIoClicked) ON_WM_SIZE() ON_WM_TIMER() ON_WM_CLOSE() END_MESSAGE_MAP() // CIOMonitoringDlg 消息处理程序 BOOL CIOMonitoringDlg::OnInitDialog() { CDialogEx::OnInitDialog(); // TODO: 在此添加额外的初始化 CRect screenRect, dlgRect, clientRect; SystemParametersInfo(SPI_GETWORKAREA, 0, &screenRect, 0); GetClientRect(&clientRect); m_nInitialWidth = clientRect.Width(); m_nInitialHeight = clientRect.Height(); // 初始化默认字体 CFont* pDefaultFont = GetOrCreateFont(12); // 遍历所有子控件,记录初始位置并设置默认字体 CWnd* pWnd = GetWindow(GW_CHILD); while (pWnd) { int nCtrlID = pWnd->GetDlgCtrlID(); if (nCtrlID != -1) { // 记录控件初始布局 CRect ctrlRect; pWnd->GetWindowRect(&ctrlRect); ScreenToClient(&ctrlRect); m_mapCtrlLayouts[nCtrlID] = ctrlRect; // 跳过特殊控件(如 MFCGridCtrl) TCHAR szClassName[256]; GetClassName(pWnd->m_hWnd, szClassName, sizeof(szClassName)); if (_tcsicmp(szClassName, _T("MFCGridCtrl")) == 0) { pWnd = pWnd->GetNextWindow(); continue; } // 设置默认字体 pWnd->SetFont(pDefaultFont); } pWnd = pWnd->GetNextWindow(); } GetWindowRect(&dlgRect); int dlgWidth = dlgRect.Width() * 3; int dlgHeight = dlgRect.Height() * 3; if (dlgWidth > screenRect.Width()) { dlgWidth = screenRect.Width(); } if (dlgHeight > screenRect.Height()) { dlgHeight = screenRect.Height(); } int centerX = screenRect.left + (screenRect.Width() - dlgWidth) / 2; int centerY = screenRect.top + (screenRect.Height() - dlgHeight) / 2; MoveWindow(centerX, centerY, dlgWidth, dlgHeight); CreateDynamicControls(); DisplayCurrentPage(); GetDlgItem(IDC_BUTTON_PREV_PAGE)->EnableWindow(m_nCurrentPage > 1); GetDlgItem(IDC_BUTTON_NEXT_PAGE)->EnableWindow(m_nCurrentPage < m_nTotalPages); SetTimer(TIMER_READ_PLC_DATA, 500, nullptr); SetTimer(TIMER_READ_UPDATE, 200, nullptr); return TRUE; // return TRUE unless you set the focus to a control // 异常: OCX 属性页应返回 FALSE } void CIOMonitoringDlg::OnSize(UINT nType, int cx, int cy) { CDialogEx::OnSize(nType, cx, cy); // TODO: 在此处添加消息处理程序代码 if (nType == SIZE_MINIMIZED || m_mapCtrlLayouts.empty()) { return; } float dScaleX = static_cast(cx) / m_nInitialWidth; float dScaleY = static_cast(cy) / m_nInitialHeight; // 遍历对话框中的所有控件 AdjustControls(dScaleX, dScaleY); } void CIOMonitoringDlg::OnBnClickedButtonPrevPage() { // TODO: 在此添加控件通知处理程序代码 if (m_nCurrentPage > 1) { --m_nCurrentPage; DisplayCurrentPage(); } else { AfxMessageBox(_T("已经是第一页!")); } GetDlgItem(IDC_BUTTON_PREV_PAGE)->EnableWindow(m_nCurrentPage > 1); GetDlgItem(IDC_BUTTON_NEXT_PAGE)->EnableWindow(m_nCurrentPage < m_nTotalPages); } void CIOMonitoringDlg::OnBnClickedButtonNextPage() { // TODO: 在此添加控件通知处理程序代码 if (m_nCurrentPage < m_nTotalPages) { ++m_nCurrentPage; DisplayCurrentPage(); } else { AfxMessageBox(_T("已经是最后一页!")); } GetDlgItem(IDC_BUTTON_PREV_PAGE)->EnableWindow(m_nCurrentPage > 1); GetDlgItem(IDC_BUTTON_NEXT_PAGE)->EnableWindow(m_nCurrentPage < m_nTotalPages); } LRESULT CIOMonitoringDlg::OnIoClicked(WPARAM wParam, LPARAM lParam) { CString strAddr; GetStaticControlAddrText((UINT)wParam, strAddr); BOOL bOn = (BOOL)lParam; int nAddress; MC::SOFT_COMPONENT component; if (ParsePLCAddress(strAddr, component, nAddress) && m_pPLC) { TRACE("地址解析成功: %s %d\n", strAddr, GetCurrentThreadId()); int n = m_pPLC->writeBit(component, nAddress, bOn, [](IMcChannel* pChannel, int addr, DWORD value, int flag) { if (flag == 0) { TRACE("写入成功: 地址: %d, 值: %lu\n", addr, value); } else { TRACE("写入失败: 地址: %d, 错误码: %d\n", addr, flag); } }); TRACE("地址解析成功2: %d\n", n); } return 0; } void CIOMonitoringDlg::OnTimer(UINT_PTR nIDEvent) { // TODO: 在此添加消息处理程序代码和/或调用默认值 if (TIMER_READ_PLC_DATA == nIDEvent) { ASSERT(m_pPLC); ReadPLCStates(); } else if (TIMER_READ_UPDATE == nIDEvent) { ASSERT(m_pPLC); UpdatePLCStatesToUI(); } CDialogEx::OnTimer(nIDEvent); } void CIOMonitoringDlg::OnClose() { // TODO: 在此添加消息处理程序代码和/或调用默认值 KillTimer(TIMER_READ_PLC_DATA); KillTimer(TIMER_READ_UPDATE); CDialogEx::OnClose(); }