LAPTOP-SNT8I5JK\Boounion
2024-12-02 aedb3b85fed48cb2cf0abb5fafa8e7591644c9f4
SourceCode/Bond/BondEq/View/IOMonitoringDlg.cpp
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,568 @@
// 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
// CIOMonitoringDlg å¯¹è¯æ¡†
IMPLEMENT_DYNAMIC(CIOMonitoringDlg, CDialogEx)
CIOMonitoringDlg::CIOMonitoringDlg(CWnd* pParent /*=nullptr*/)
   : CDialogEx(IDD_DIALOG_IO_MONITORING, pParent)
{
   m_nCurrentPage = 1;
   m_nTotalPages = 1;
   m_nRowsPerPage = 10;
   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 = (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<int>(originalRect.left * dScaleX),
            static_cast<int>(originalRect.top * dScaleY),
            static_cast<int>(originalRect.right * dScaleX),
            static_cast<int>(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 = 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; // æ¯ç»„总宽度
   for (int i = 0; i < m_nRowsPerPage; ++i) {
      // æ¯ä¸€è¡Œçš„èµ·å§‹ Y åæ ‡
      int y = topMargin + i * (rowHeight + verticalSpacing);
      // åˆ›å»ºç¬¬ 1 ç»„ (0, 1, 2)
      int x = sideMargin; // ä»Žå·¦è¾¹è·å¼€å§‹
      CreateStaticControl(x, y, colWidthSmall, rowHeight, _T("OFF"), true, AlignCenter);
      x += colWidthSmall;
      CreateStaticControl(x, y, colWidthSmall, rowHeight, _T("X1000"), false, AlignCenter);
      x += colWidthSmall;
      CreateStaticControl(x, y, colWidthLarge, rowHeight, _T("描述文本"), false);
      // ç¬¬ 2 ç»„起始位置,加上组间距
      x += colWidthLarge + groupSpacing;
      // åˆ›å»ºç¬¬ 2 ç»„ (3, 4, 5)
      CreateStaticControl(x, y, colWidthSmall, rowHeight, _T("OFF"), true, AlignCenter, [this, i]() {
         // è‡ªå®šä¹‰ç‚¹å‡»äº‹ä»¶çš„逻辑
         auto* pControl = static_cast<CBLLabel*>(m_staticControls[i * m_nCols + 3]);
         CString currentText;
         pControl->GetWindowText(currentText);
         BOOL bOn = FALSE;
         if (currentText == _T("OFF")) {
            //pControl->SetBkColor(RGB(0, 255, 0)); // ç»¿è‰²èƒŒæ™¯
            //pControl->SetText(_T("ON"));          // æ›´æ–°æ–‡æœ¬ä¸º ON
            bOn = TRUE;
         }
         else {
            //pControl->SetBkColor(RGB(255, 0, 0)); // çº¢è‰²èƒŒæ™¯
            //pControl->SetText(_T("OFF"));         // æ›´æ–°æ–‡æœ¬ä¸º OFF
            bOn = FALSE;
         }
         pControl = static_cast<CBLLabel*>(m_staticControls[i * m_nCols + 4]);
         pControl->GetWindowText(currentText);
         int nAddress;
         MC::SOFT_COMPONENT component;
         if (ParsePLCAddress(currentText, component, nAddress) && m_pPLC) {
            TRACE("地址解析成功: %s\n", currentText);
            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);
               }
            });
         }
      });
      x += colWidthSmall;
      CreateStaticControl(x, y, colWidthSmall, rowHeight, _T("Y1010"), false, AlignCenter);
      x += colWidthSmall;
      CreateStaticControl(x, y, colWidthLarge, rowHeight, _T("描述文本"), false);
   }
}
void CIOMonitoringDlg::CreateStaticControl(int x, int y, int width, int height, const CString& text, bool hasBorder, TextAlign alignment, std::function<void()> clickCallback)
{
   // åˆ›å»ºåŠ¨æ€æŽ§ä»¶
   CBLLabel* pStatic = new CBLLabel();
   DWORD style = WS_CHILD | WS_VISIBLE | SS_CENTERIMAGE; // ç¡®ä¿åž‚直居中
   if (hasBorder) {
      style |= WS_BORDER; // æ·»åŠ è¾¹æ¡†
   }
   pStatic->Create(text, style, CRect(x, y, x + width, y + height), this);
   // è®¾ç½®æ–‡æœ¬å¯¹é½æ–¹å¼
   pStatic->SetAlignment(alignment);
   // è®¾ç½®åŠ¨æ€å­—ä½“è°ƒæ•´ï¼Œå¹¶è®¾ç½®å­—ä½“å¤§å°ï¼ˆåŠ¨æ€å­—ä½“ä¼šæ ¹æ®æŽ§ä»¶å¤§å°è°ƒæ•´ï¼‰
   int nSize = height / 3;
   CFont* pFont = GetOrCreateFont(nSize);
   pStatic->SetFont(pFont);
   pStatic->SetFontSize(nSize);
   pStatic->SetDynamicFont(TRUE);
   // è®¾ç½®å›žè°ƒ
   if (clickCallback) {
      pStatic->SetClickCallback(clickCallback);
   }
   // å­˜å‚¨æŽ§ä»¶æŒ‡é’ˆ
   m_staticControls.push_back(pStatic);
}
void CIOMonitoringDlg::DisplayCurrentPage()
{
   int startIndex = (m_nCurrentPage - 1) * m_nRowsPerPage;
   int endIndex = min(startIndex + m_nRowsPerPage, static_cast<int>(m_displayData.size()));
   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];
         // æ·»åŠ  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];
   switch (componentChar) {
   case 'D':
      component = MC::SOFT_COMPONENT::D;
      break;
   case 'M':
      component = MC::SOFT_COMPONENT::M;
      break;
   case 'X':
      component = MC::SOFT_COMPONENT::X;
      break;
   case 'Y':
      component = MC::SOFT_COMPONENT::Y;
      break;
   default:
      return false;
   }
   CString hexAddress = address.Mid(1);
   addr = _tcstoul(hexAddress, nullptr, 16);
   return true;
}
void CIOMonitoringDlg::UpdatePLCStates()
{
   // ç¤ºä¾‹ï¼šä»Ž PLC èŽ·å–å€¼ï¼Œè¿™é‡Œç”¨éšæœºå€¼æ¨¡æ‹Ÿ
   //for (size_t i = 0; i < m_inputPLCAddresses.size(); ++i) {
   //   // æ¨¡æ‹ŸèŽ·å–è¾“å…¥çŠ¶æ€
   //   bool inputState = (rand() % 2 == 0); // å¶å°”为 true/false
   //   auto* inputControl = static_cast<CBLLabel*>(m_staticControls[i * m_nCols + 0]);
   //   inputControl->SetBkColor(inputState ? RGB(0, 255, 0) : RGB(255, 0, 0));
   //   inputControl->SetText(inputState ? _T("ON") : _T("OFF"));
   //}
   //for (size_t i = 0; i < m_outputPLCAddresses.size(); ++i) {
   //   // æ¨¡æ‹ŸèŽ·å–è¾“å‡ºçŠ¶æ€
   //   bool outputState = (rand() % 2 == 0); // å¶å°”为 true/false
   //   auto* outputControl = static_cast<CBLLabel*>(m_staticControls[i * m_nCols + 3]);
   //   outputControl->SetBkColor(outputState ? RGB(0, 255, 0) : RGB(255, 0, 0));
   //   outputControl->SetText(outputState ? _T("ON") : _T("OFF"));
   //}
   // è¾“入地址的读取
   if (!m_inputPLCAddresses.empty()) {
      // èŽ·å–èµ·å§‹åœ°å€å’Œé•¿åº¦
      CString startAddressStr = m_inputPLCAddresses.front();
      CString endAddressStr = m_inputPLCAddresses.back();
      MC::SOFT_COMPONENT component;
      int startAddress, endAddress;
      // è§£æžèµ·å§‹å’Œç»“束地址
      if (ParsePLCAddress(startAddressStr, component, startAddress) &&
         ParsePLCAddress(endAddressStr, component, endAddress)) {
         int inputSize = endAddress - startAddress + 1;
         // å›žè°ƒå¤„理输入数据
         auto funOnReadInput = [this, startAddress](IMcChannel* pChannel, int addr, char* pData, unsigned int nDataSize, int flag) {
            if (nDataSize == (unsigned int)(m_inputPLCAddresses.size()) && flag == 0) {
               for (size_t i = 0; i < m_inputPLCAddresses.size(); ++i) {
                  int offset = i;
                  int value = CToolUnits::toInt16(&pData[offset]);
                  auto* inputControl = static_cast<CBLLabel*>(m_staticControls[i * m_nCols + 0]); // ç¬¬ 0 åˆ—
                  inputControl->SetBkColor(value ? RGB(0, 255, 0) : RGB(255, 0, 0)); // æ›´æ–°èƒŒæ™¯é¢œè‰²
                  inputControl->SetText(value ? _T("ON") : _T("OFF"));               // æ›´æ–°æ–‡æœ¬
               }
            }
         };
         // è¯»å–输入数据
         m_pPLC->readData(component, startAddress, inputSize, funOnReadInput);
      }
   }
   // è¾“出地址的读取
   if (!m_outputPLCAddresses.empty()) {
      // èŽ·å–èµ·å§‹åœ°å€å’Œé•¿åº¦
      CString startAddressStr = m_outputPLCAddresses.front();
      CString endAddressStr = m_outputPLCAddresses.back();
      MC::SOFT_COMPONENT component;
      int startAddress, endAddress;
      // è§£æžèµ·å§‹å’Œç»“束地址
      if (ParsePLCAddress(startAddressStr, component, startAddress) &&
         ParsePLCAddress(endAddressStr, component, endAddress)) {
         int outputSize = endAddress - startAddress + 1;
         // å›žè°ƒå¤„理输出数据
         auto funOnReadOutput = [this, startAddress](IMcChannel* pChannel, int addr, char* pData, unsigned int nDataSize, int flag) {
            if (nDataSize == (unsigned int)(m_outputPLCAddresses.size()) && flag == 0) {
               for (size_t i = 0; i < m_outputPLCAddresses.size(); ++i) {
                  int offset = i;
                  int value = CToolUnits::toInt16(&pData[offset]);
                  auto* outputControl = static_cast<CBLLabel*>(m_staticControls[i * m_nCols + 3]); // ç¬¬ 3 åˆ—
                  outputControl->SetBkColor(value ? RGB(0, 255, 0) : RGB(255, 0, 0)); // æ›´æ–°èƒŒæ™¯é¢œè‰²
                  outputControl->SetText(value ? _T("ON") : _T("OFF"));               // æ›´æ–°æ–‡æœ¬
               }
            }
         };
         // è¯»å–输出数据
         m_pPLC->readData(component, startAddress, outputSize, funOnReadOutput);
      }
   }
}
BEGIN_MESSAGE_MAP(CIOMonitoringDlg, CDialogEx)
   ON_BN_CLICKED(IDC_BUTTON_PREV_PAGE, &CIOMonitoringDlg::OnBnClickedButtonPrevPage)
   ON_BN_CLICKED(IDC_BUTTON_NEXT_PAGE, &CIOMonitoringDlg::OnBnClickedButtonNextPage)
   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() * 2;
   int dlgHeight = dlgRect.Height() * 2;
   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();
   SetTimer(TIMER_READ_PLC_DATA, 500, 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<float>(cx) / m_nInitialWidth;
   float dScaleY = static_cast<float>(cy) / m_nInitialHeight;
   // éåŽ†å¯¹è¯æ¡†ä¸­çš„æ‰€æœ‰æŽ§ä»¶
   AdjustControls(dScaleX, dScaleY);
}
void CIOMonitoringDlg::OnBnClickedButtonPrevPage()
{
   // TODO: åœ¨æ­¤æ·»åŠ æŽ§ä»¶é€šçŸ¥å¤„ç†ç¨‹åºä»£ç 
   if (m_nCurrentPage > 1) {
      --m_nCurrentPage;
      DisplayCurrentPage();
   }
   else {
      AfxMessageBox(_T("已经是第一页!"));
   }
}
void CIOMonitoringDlg::OnBnClickedButtonNextPage()
{
   // TODO: åœ¨æ­¤æ·»åŠ æŽ§ä»¶é€šçŸ¥å¤„ç†ç¨‹åºä»£ç 
   if (m_nCurrentPage < m_nTotalPages) {
      ++m_nCurrentPage;
      DisplayCurrentPage();
   }
   else {
      AfxMessageBox(_T("已经是最后一页!"));
   }
}
void CIOMonitoringDlg::OnTimer(UINT_PTR nIDEvent)
{
   // TODO: åœ¨æ­¤æ·»åŠ æ¶ˆæ¯å¤„ç†ç¨‹åºä»£ç å’Œ/或调用默认值
   if (TIMER_READ_PLC_DATA == nIDEvent) {
      ASSERT(m_pPLC);
      UpdatePLCStates();
      Sleep(100);
   }
   CDialogEx::OnTimer(nIDEvent);
}
void CIOMonitoringDlg::OnClose()
{
   // TODO: åœ¨æ­¤æ·»åŠ æ¶ˆæ¯å¤„ç†ç¨‹åºä»£ç å’Œ/或调用默认值
   KillTimer(TIMER_READ_PLC_DATA);
   CDialogEx::OnClose();
}