LAPTOP-SNT8I5JK\Boounion
2024-12-02 df0863b2c29fa227d186e6b8aeb4a856dcae12f3
SourceCode/Bond/BondEq/View/IOMonitoringDlg.cpp
@@ -5,7 +5,10 @@
#include "BondEq.h"
#include "afxdialogex.h"
#include "IOMonitoringDlg.h"
#include "ToolUnits.h"
#define TIMER_INIT            1
#define TIMER_READ_PLC_DATA      2
// CIOMonitoringDlg 对话框
@@ -53,6 +56,12 @@
   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);
@@ -88,8 +97,7 @@
   CWnd* pWnd = GetWindow(GW_CHILD);
   while (pWnd) {
      int nCtrlID = pWnd->GetDlgCtrlID();
      if (nCtrlID != -1 && m_mapCtrlLayouts.find(nCtrlID) != m_mapCtrlLayouts.end())
      {
      if (nCtrlID != -1 && m_mapCtrlLayouts.find(nCtrlID) != m_mapCtrlLayouts.end()) {
         CRect originalRect = m_mapCtrlLayouts[nCtrlID];
         CRect newRect(
            static_cast<int>(originalRect.left * dScaleX),
@@ -112,6 +120,7 @@
   // 根据控件高度动态调整字体大小
   int fontSize = nHeight / 2;
   if (fontSize < 8) fontSize = 8;
   if (fontSize < 24) fontSize = 24;
   // 获取或创建字体
   CFont* pFont = GetOrCreateFont(fontSize);
@@ -161,50 +170,88 @@
   int colWidthLarge = availableWidth * 4 / 14;      // 大宽度列比例
   int groupWidth = colWidthSmall * 2 + colWidthLarge; // 每组总宽度
   for (int i = 0; i < m_nRowsPerPage; ++i)
   {
   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);
      CreateStaticControl(x, y, colWidthSmall, rowHeight, _T("OFF"), true, AlignCenter);
      x += colWidthSmall;
      CreateStaticControl(x, y, colWidthSmall, rowHeight, _T("X1000"));
      CreateStaticControl(x, y, colWidthSmall, rowHeight, _T("X1000"), false, AlignCenter);
      x += colWidthSmall;
      CreateStaticControl(x, y, colWidthLarge, rowHeight, _T("描述文本"), false, true);
      CreateStaticControl(x, y, colWidthLarge, rowHeight, _T("描述文本"), false);
      // 第 2 组起始位置,加上组间距
      x += colWidthLarge + groupSpacing;
      // 创建第 2 组 (3, 4, 5)
      CreateStaticControl(x, y, colWidthSmall, rowHeight, _T("OFF"), true);
      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"));
      CreateStaticControl(x, y, colWidthSmall, rowHeight, _T("Y1010"), false, AlignCenter);
      x += colWidthSmall;
      CreateStaticControl(x, y, colWidthLarge, rowHeight, _T("描述文本"), false, true);
      CreateStaticControl(x, y, colWidthLarge, rowHeight, _T("描述文本"), false);
   }
}
void CIOMonitoringDlg::CreateStaticControl(int x, int y, int width, int height, const CString& text, bool hasBorder, bool alignLeft)
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;      // 添加边框
      style |= WS_BORDER; // 添加边框
   }
   if (alignLeft) {
      style |= SS_LEFT;      // 左对齐文本
   }
   else {
      style |= SS_CENTER;      // 居中文本
   }
   CStatic* pStatic = new CStatic();
   pStatic->Create(text, style, CRect(x, y, x + width, y + height), this);
   // 动态设置字体大小
   CFont* pFont = GetOrCreateFont(height / 3);
   // 设置文本对齐方式
   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);
@@ -215,27 +262,55 @@
   int startIndex = (m_nCurrentPage - 1) * m_nRowsPerPage;
   int endIndex = min(startIndex + m_nRowsPerPage, static_cast<int>(m_displayData.size()));
   for (int i = startIndex; i < endIndex; ++i)
   {
      const auto& data = m_displayData[i];
      int row = i - startIndex;
   m_inputPLCAddresses.clear();
   m_outputPLCAddresses.clear();
      m_staticControls[row * m_nCols + 0]->SetWindowText(_T("OFF"));
      m_staticControls[row * m_nCols + 1]->SetWindowText(CString(data.inputAddress.c_str()));
      m_staticControls[row * m_nCols + 2]->SetWindowText(CString(data.inputDescription.c_str()));
      m_staticControls[row * m_nCols + 3]->SetWindowText(_T("OFF"));
      m_staticControls[row * m_nCols + 4]->SetWindowText(CString(data.outputAddress.c_str()));
      m_staticControls[row * m_nCols + 5]->SetWindowText(CString(data.outputDescription.c_str()));
   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)
      {
   for (auto* pStatic : m_staticControls) {
      if (pStatic) {
         pStatic->DestroyWindow();
         delete pStatic;
      }
@@ -243,10 +318,127 @@
   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()
@@ -311,6 +503,8 @@
   CreateDynamicControls();
   DisplayCurrentPage();
   SetTimer(TIMER_READ_PLC_DATA, 500, nullptr);
   return TRUE;  // return TRUE unless you set the focus to a control
   // 异常: OCX 属性页应返回 FALSE
}
@@ -354,3 +548,21 @@
      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();
}