// CEquipmentPage1.cpp: 实现文件
|
//
|
|
#include "stdafx.h"
|
#include "Servo.h"
|
#include "CEquipmentPage1.h"
|
#include "afxdialogex.h"
|
|
|
// 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()
|
{
|
}
|
|
void CEquipmentPage1::DoDataExchange(CDataExchange* pDX)
|
{
|
CHMPropertyPage::DoDataExchange(pDX);
|
}
|
|
|
BEGIN_MESSAGE_MAP(CEquipmentPage1, CHMPropertyPage)
|
ON_WM_CTLCOLOR()
|
ON_WM_DESTROY()
|
ON_WM_SIZE()
|
ON_WM_TIMER()
|
END_MESSAGE_MAP()
|
|
|
// CEquipmentPage1 消息处理程序
|
void CEquipmentPage1::OnApply()
|
{
|
__super::OnApply();
|
}
|
|
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()
|
{
|
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
|
}
|
|
HBRUSH CEquipmentPage1::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
|
{
|
HBRUSH hbr = CHMPropertyPage::OnCtlColor(pDC, pWnd, nCtlColor);
|
|
// TODO: 在此更改 DC 的任何特性
|
|
// TODO: 如果默认的不是所需画笔,则返回另一个画笔
|
return hbr;
|
}
|
|
void CEquipmentPage1::OnDestroy()
|
{
|
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)
|
{
|
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);
|
}
|