| SourceCode/Bond/Servo/CEquipmentPage1.cpp | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| SourceCode/Bond/Servo/CEquipmentPage1.h | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| SourceCode/Bond/Servo/JobSlotGrid.cpp | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| SourceCode/Bond/Servo/Servo.vcxproj | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| SourceCode/Bond/Servo/Servo.vcxproj.filters | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| SourceCode/Bond/Servo/ServoMemDC.cpp | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| SourceCode/Bond/Servo/ServoMemDC.h | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
SourceCode/Bond/Servo/CEquipmentPage1.cpp
@@ -9,12 +9,20 @@ // CEquipmentPage1 å¯¹è¯æ¡ #define SIGNAL_GRID_ROWS 8 #define SIGNAL_GRID_COLS 8 #define SIGNAL_GRID_SIZE (SIGNAL_GRID_ROWS * SIGNAL_GRID_COLS) #define TIMER_ID_SIGNAL_UPDATE 1001 #define TIMER_INTERVAL_MS 1000 // æ¯ 1 ç§æ´æ°ä¸æ¬¡ IMPLEMENT_DYNAMIC(CEquipmentPage1, CHMPropertyPage) CEquipmentPage1::CEquipmentPage1(CWnd* pParent /*=nullptr*/) : CHMPropertyPage(IDD_PAGE_EQUIPMENT1, pParent) { m_pEquipment = nullptr; m_nCurrentDeviceID = 0; } CEquipmentPage1::~CEquipmentPage1() @@ -31,6 +39,7 @@ ON_WM_CTLCOLOR() ON_WM_DESTROY() ON_WM_SIZE() ON_WM_TIMER() END_MESSAGE_MAP() @@ -43,6 +52,149 @@ void CEquipmentPage1::setEquipment(SERVO::CEquipment* pEquipment) { m_pEquipment = pEquipment; if (m_pEquipment != nullptr) { InitSignalListForDevice(pEquipment->getID()); } else { ResetSignalPanel(); } } void CEquipmentPage1::LoadSignalListFromCSV(const CString& strFilePath) { m_mapSignalListByID.clear(); CStdioFile file; if (!file.Open(strFilePath, CFile::modeRead | CFile::typeText)) { AfxMessageBox(_T("æ æ³æå¼ä¿¡å·å®ä¹æä»¶: ") + strFilePath); return; } CString strLine; int nLineNum = 0; while (file.ReadString(strLine)) { ++nLineNum; strLine.Trim(); if (strLine.IsEmpty() || strLine.Left(1) == _T("#") || strLine.Left(2) == _T("//")) { continue; // è·³è¿æ³¨éè¡æç©ºè¡ } // åå²ä¸º tokens std::vector<CString> tokens; int curPos = 0; CString token = strLine.Tokenize(_T(","), curPos); while (!token.IsEmpty()) { token.Trim(); // å»é¤æ¯ä¸ªå段çç©ºæ ¼ tokens.push_back(token); token = strLine.Tokenize(_T(","), curPos); } // æ ¼å¼æ£æ¥ if (tokens.size() < 3) { TRACE(_T("CSV æ ¼å¼é误 [è¡ %d]ï¼å段æ°ä¸è¶³ã\n"), nLineNum); continue; } // è§£æå段 int nDeviceID = _ttoi(tokens[0]); CString strSignalName = tokens[1]; bool bClickable = _ttoi(tokens[2]) ? TRUE : FALSE; if (nDeviceID <= 0 || nDeviceID > 999 || strSignalName.IsEmpty()) { TRACE(_T("CSV è¡ %dï¼æ æè®¾å¤ID=%d æä¿¡å·å为空\n"), nLineNum, nDeviceID); continue; } SignalInfo info = { strSignalName, false, bClickable }; m_mapSignalListByID[nDeviceID].push_back(info); } file.Close(); TRACE(_T("ä¿¡å·å®ä¹å è½½å®æï¼å ± %d 个设å¤ã\n"), (int)m_mapSignalListByID.size()); } void CEquipmentPage1::InitSignalListForDevice(int nDeviceID) { m_nCurrentDeviceID = nDeviceID; m_vSignalList.clear(); auto it = m_mapSignalListByID.find(nDeviceID); if (it != m_mapSignalListByID.end()) { m_vSignalList = it->second; } else { TRACE(_T("Warning: No signals found for DeviceID=%d\n"), nDeviceID); } // è¡¥é½å° 64 项 while (m_vSignalList.size() < SIGNAL_GRID_SIZE) { m_vSignalList.push_back({ _T(""), false, false }); } InitSignalSlotTextAndClickable(); UpdateAllSignalStatesFromDevice(); } void CEquipmentPage1::UpdateSignalState(int nRow, int nCol, bool bNewState) { if (!::IsWindow(m_ctrlSignalPanel.GetSafeHwnd())) { return; } int nIndex = nRow * SIGNAL_GRID_COLS + nCol; if (nIndex < 0 || nIndex >= static_cast<int>(m_vSignalList.size())) { return; } if (m_vSignalList[nIndex].bCurrentState != bNewState) { m_vSignalList[nIndex].bCurrentState = bNewState; m_ctrlSignalPanel.SetSlotStatus(nRow, nCol, bNewState); TRACE(_T("[Device %d] UpdateSignalState: [%d, %d] = %d\n"), m_nCurrentDeviceID, nRow, nCol, bNewState); } } void CEquipmentPage1::InitSignalSlotTextAndClickable() { if (!::IsWindow(m_ctrlSignalPanel.GetSafeHwnd())) { return; } for (int i = 0; i < SIGNAL_GRID_SIZE; ++i) { int nRow = i / SIGNAL_GRID_COLS; int nCol = i % SIGNAL_GRID_COLS; const auto& signal = m_vSignalList[i]; m_ctrlSignalPanel.SetSlotText(nRow, nCol, signal.strName); m_ctrlSignalPanel.SetSlotClickable(nRow, nCol, signal.bClickable); } } void CEquipmentPage1::UpdateAllSignalStatesFromDevice() { if (!m_pEquipment) { return; } for (int nRow = 0; nRow < SIGNAL_GRID_ROWS; ++nRow) { for (int nCol = 0; nCol < SIGNAL_GRID_COLS; ++nCol) { BOOL bCurrentState = m_pEquipment->isLinkSignalOn(nRow, nCol); UpdateSignalState(nRow, nCol, bCurrentState); } } } void CEquipmentPage1::ResetSignalPanel() { if (!::IsWindow(m_ctrlSignalPanel.GetSafeHwnd())) { return; } m_ctrlSignalPanel.ClearAll(); m_vSignalList.clear(); m_nCurrentDeviceID = 0; } BOOL CEquipmentPage1::OnInitDialog() @@ -50,6 +202,34 @@ CHMPropertyPage::OnInitDialog(); // TODO: 卿¤æ·»å é¢å¤çåå§å m_ctrlSignalPanel.Create(AfxRegisterWndClass(0), _T("SignalGrid"), WS_CHILD | WS_VISIBLE, CRect(0, 0, 100, 100), this, 1002); m_ctrlSignalPanel.SetColors(RGB(0, 200, 0), RGB(220, 220, 220)); m_ctrlSignalPanel.SetGridSize(SIGNAL_GRID_ROWS, SIGNAL_GRID_COLS); m_ctrlSignalPanel.SetTextFont(_T("Microsoft YaHei"), 10); m_ctrlSignalPanel.SetSlotClickCallback([this](int nRow, int nCol) { int index = nRow * SIGNAL_GRID_COLS + nCol; if (index >= 0 && index < (int)m_vSignalList.size() && m_vSignalList[index].bClickable && m_pEquipment != nullptr) { // 读åå½åç¶æå¹¶åæ¢ const BOOL bCurrentState = m_pEquipment->isLinkSignalOn(nRow, nCol); m_pEquipment->setLinkSignal(nRow, nCol, !bCurrentState); } }); { TCHAR szPath[MAX_PATH] = {}; GetModuleFileName(nullptr, szPath, MAX_PATH); PathRemoveFileSpec(szPath); CString strCSVFile = CString(szPath) + _T("\\Config\\signals.csv"); LoadSignalListFromCSV(strCSVFile); } // å¦æè®¾å¤å·²è®¾ç½®ï¼ååå§åä¿¡å·å表 if (m_pEquipment != nullptr) { InitSignalListForDevice(m_pEquipment->getID()); } KillTimer(TIMER_ID_SIGNAL_UPDATE); SetTimer(TIMER_ID_SIGNAL_UPDATE, TIMER_INTERVAL_MS, nullptr); return TRUE; // return TRUE unless you set the focus to a control // å¼å¸¸: OCX 屿§é¡µåºè¿å FALSE @@ -70,6 +250,10 @@ CHMPropertyPage::OnDestroy(); // TODO: 卿¤å¤æ·»å æ¶æ¯å¤çç¨åºä»£ç KillTimer(TIMER_ID_SIGNAL_UPDATE); if (::IsWindow(m_ctrlSignalPanel.GetSafeHwnd())) { m_ctrlSignalPanel.DestroyWindow(); } } void CEquipmentPage1::OnSize(UINT nType, int cx, int cy) @@ -77,4 +261,21 @@ CHMPropertyPage::OnSize(nType, cx, cy); // TODO: 卿¤å¤æ·»å æ¶æ¯å¤çç¨åºä»£ç if (::IsWindow(m_ctrlSignalPanel.GetSafeHwnd())) { CRect rc; GetClientRect(&rc); rc.DeflateRect(10, 10); m_ctrlSignalPanel.MoveWindow(rc); } } void CEquipmentPage1::OnTimer(UINT_PTR nIDEvent) { if (nIDEvent == TIMER_ID_SIGNAL_UPDATE) { if (m_pEquipment && !m_vSignalList.empty()) { UpdateAllSignalStatesFromDevice(); } } CHMPropertyPage::OnTimer(nIDEvent); } SourceCode/Bond/Servo/CEquipmentPage1.h
@@ -1,9 +1,17 @@ #pragma once #include "CHMPropertyPage.h" #include "CEquipment.h" #include "JobSlotGrid.h" // CEquipmentPage1 å¯¹è¯æ¡ struct SignalInfo { CString strName; // ä¿¡å·åç§° bool bCurrentState; // å½åç¶æï¼ON/OFFï¼ bool bClickable; // æ¯å¦å 许ç¹å» }; class CEquipmentPage1 : public CHMPropertyPage { @@ -16,7 +24,18 @@ void setEquipment(SERVO::CEquipment* pEquipment); private: int m_nCurrentDeviceID; SERVO::CEquipment* m_pEquipment; std::vector<SignalInfo> m_vSignalList; CJobSlotGrid m_ctrlSignalPanel; std::map<int, std::vector<SignalInfo>> m_mapSignalListByID; void LoadSignalListFromCSV(const CString& strFilePath); void InitSignalListForDevice(int nDeviceID); void UpdateSignalState(int nRow, int nCol, bool bNewState); void InitSignalSlotTextAndClickable(); void UpdateAllSignalStatesFromDevice(); void ResetSignalPanel(); // å¯¹è¯æ¡æ°æ® @@ -33,4 +52,5 @@ afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); afx_msg void OnDestroy(); afx_msg void OnSize(UINT nType, int cx, int cy); afx_msg void OnTimer(UINT_PTR nIDEvent); }; SourceCode/Bond/Servo/JobSlotGrid.cpp
@@ -1,5 +1,6 @@ #include "stdafx.h" #include "JobSlotGrid.h" #include "ServoMemDC.h" #ifdef _DEBUG #define new DEBUG_NEW @@ -221,17 +222,32 @@ void CJobSlotGrid::OnPaint() { CPaintDC dc(this); DrawGrid(&dc); CServoMemDC memDC(&dc); DrawGrid(&memDC); } void CJobSlotGrid::DrawGrid(CDC* pDC) { CRect rect; GetClientRect(&rect); pDC->FillSolidRect(&rect, ::GetSysColor(COLOR_3DFACE)); // å®å ¨èæ¯è²ï¼ä» å åç»å¶ if (m_nCols == 0 || m_nRows == 0) { return; } // è®¡ç®æ ¼å尺寸 int nCellWidth = rect.Width() / m_nCols; int nCellHeight = rect.Height() / m_nRows; // åä½è®¾ç½® CFont* pOldFont = pDC->SelectObject(&m_fontText); pDC->SetBkMode(TRANSPARENT); pDC->SetTextColor(RGB(0, 0, 0)); // å®ä¹é¢è²å¸¸é constexpr COLORREF COLOR_HOVER = RGB(200, 230, 255); constexpr COLORREF COLOR_CLICK = RGB(0, 120, 215); for (int i = 0; i < m_nRows; ++i) { for (int j = 0; j < m_nCols; ++j) { @@ -241,29 +257,61 @@ bool bIsHover = (m_ptHover.x == j && m_ptHover.y == i); bool bIsClicking = bIsHover && m_bLButtonDown; // éæ©é¢è² COLORREF fillColor; if (bIsClicking) { fillColor = RGB(0, 120, 215); // é¼ æ æä¸è² } else if (bIsHover) { fillColor = RGB(200, 230, 255); // æ¬åé«äº® } else { fillColor = m_vSlotStatus[i][j] ? m_colorHasJob : m_colorNoJob; // 鿩填å é¢è² COLORREF fillColor = m_vSlotStatus[i][j] ? m_colorHasJob : m_colorNoJob; if (IsSlotClickable(i, j)) { if (bIsClicking) { fillColor = COLOR_CLICK; } else if (bIsHover) { fillColor = COLOR_HOVER; } } // ç»èæ¯ CBrush brush(fillColor); pDC->FillRect(&cellRect, &brush); // ç»å¶èæ¯ï¼é«ææ¿ä»£ CBrushï¼ pDC->FillSolidRect(&cellRect, fillColor); // è¾¹æ¡ // ç»å¶è¾¹æ¡ pDC->DrawEdge(&cellRect, EDGE_SUNKEN, BF_RECT); // ææ¬ pDC->SetBkMode(TRANSPARENT); pDC->SetTextColor(RGB(0, 0, 0)); pDC->DrawText(m_vSlotText[i][j], &cellRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE); // 妿æ¯å¯ç¹å»æ ¼åï¼å¨å·¦ä¸è§ç»ä¸ä¸ªå°åç¹ if (IsSlotClickable(i, j)) { constexpr int DOT_RADIUS = 3; int cx = cellRect.left + 5; int cy = cellRect.top + 5; // ä¿åæ§ç¬åå·å CBrush brushDot(RGB(0, 120, 215)); CBrush* pOldBrush = pDC->SelectObject(&brushDot); CPen penDot(PS_SOLID, 1, RGB(0, 120, 215)); CPen* pOldPen = pDC->SelectObject(&penDot); // ç»å¶åç¹ pDC->Ellipse(cx - DOT_RADIUS, cy - DOT_RADIUS, cx + DOT_RADIUS, cy + DOT_RADIUS); // æ¢å¤ pDC->SelectObject(pOldBrush); pDC->SelectObject(pOldPen); } // è·åæåï¼å®å ¨ï¼ CString strText; if (i < m_vSlotText.size() && j < m_vSlotText[i].size()) { strText = m_vSlotText[i][j]; } if (!strText.IsEmpty()) { // å è®¡ç®æåé«åº¦ï¼æ¯ææ¢è¡ï¼ CRect calcRect = cellRect; pDC->DrawText(strText, &calcRect, DT_CENTER | DT_WORDBREAK | DT_NOPREFIX | DT_CALCRECT); // éæ°è®¾å®å± ä¸ç»å¶åºå CRect textRect = cellRect; textRect.top += (cellRect.Height() - calcRect.Height()) / 2; // å®é ç»å¶æå pDC->DrawText(strText, &textRect, DT_CENTER | DT_WORDBREAK | DT_NOPREFIX); } } } SourceCode/Bond/Servo/Servo.vcxproj
@@ -319,6 +319,7 @@ <ClInclude Include="ServoCommo.h" /> <ClInclude Include="ServoDlg.h" /> <ClInclude Include="ServoGraph.h" /> <ClInclude Include="ServoMemDC.h" /> <ClInclude Include="stdafx.h" /> <ClInclude Include="targetver.h" /> <ClInclude Include="TerminalDisplayDlg.h" /> @@ -444,6 +445,7 @@ <ClCompile Include="Servo.cpp" /> <ClCompile Include="ServoDlg.cpp" /> <ClCompile Include="ServoGraph.cpp" /> <ClCompile Include="ServoMemDC.cpp" /> <ClCompile Include="stdafx.cpp"> <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader> <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader> SourceCode/Bond/Servo/Servo.vcxproj.filters
@@ -157,6 +157,7 @@ <ClCompile Include="CSlot.cpp" /> <ClCompile Include="CRobotTaskDlg.cpp" /> <ClCompile Include="PageTransferLog.cpp" /> <ClCompile Include="ServoMemDC.cpp" /> </ItemGroup> <ItemGroup> <ClInclude Include="AlarmManager.h" /> @@ -319,6 +320,7 @@ <ClInclude Include="CSlot.h" /> <ClInclude Include="CRobotTaskDlg.h" /> <ClInclude Include="PageTransferLog.h" /> <ClInclude Include="ServoMemDC.h" /> </ItemGroup> <ItemGroup> <ResourceCompile Include="Servo.rc" /> SourceCode/Bond/Servo/ServoMemDC.cpp
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,40 @@ #include "stdafx.h" #include "ServoMemDC.h" CServoMemDC::CServoMemDC(CDC* pDC, const CRect* pRect) : CDC(), m_pOldBitmap(nullptr), m_pDC(pDC), m_bMemDC(FALSE) { ASSERT(pDC != nullptr); if (pRect == nullptr) pDC->GetClipBox(&m_rect); else m_rect = *pRect; if (CreateCompatibleDC(pDC)) { m_bMemDC = TRUE; m_bitmap.CreateCompatibleBitmap(pDC, m_rect.Width(), m_rect.Height()); m_pOldBitmap = SelectObject(&m_bitmap); SetWindowOrg(m_rect.left, m_rect.top); } } CServoMemDC::~CServoMemDC() { if (m_bMemDC) { // å°å å DC æ·è´ååå§çªå£ DC m_pDC->BitBlt(m_rect.left, m_rect.top, m_rect.Width(), m_rect.Height(), this, m_rect.left, m_rect.top, SRCCOPY); SelectObject(m_pOldBitmap); } } CServoMemDC* CServoMemDC::operator->() { return this; } CServoMemDC::operator CDC* () { return this; } SourceCode/Bond/Servo/ServoMemDC.h
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,20 @@ #pragma once #include <afxwin.h> // MFC æ ¸å¿å¤´æä»¶ // CServoMemDCï¼åç¼å²ç»å¾å°è£ ç±»ï¼æ¶é¤éªçï¼ class CServoMemDC : public CDC { public: CServoMemDC(CDC* pDC, const CRect* pRect = nullptr); // æé ï¼ä¼ å ¥ç®æ DC ååºå ~CServoMemDC(); // ææï¼èªå¨æ·è´å°ç®æ DC CServoMemDC* operator->(); operator CDC* (); private: CBitmap m_bitmap; // ç¨äºå å DC çä½å¾ CBitmap* m_pOldBitmap; // æ§ä½å¾ CDC* m_pDC; // åå§ç»å¾ DCï¼çªå£ï¼ CRect m_rect; // ç»å¾åºå BOOL m_bMemDC; // æ¯å¦å¯ç¨äºå å DCï¼CreateCompatibleDC æåï¼ };