// CPageRecipe.cpp: 实现文件 // #include "stdafx.h" #include "Servo.h" #include "afxdialogex.h" #include "PageRecipe.h" #include "MsgDlg.h" #include "InputDialog.h" #include "RecipeDeviceBindDlg.h" // CPageRecipe 对话框 IMPLEMENT_DYNAMIC(CPageRecipe, CDialogEx) CPageRecipe::CPageRecipe(CWnd* pParent /*=nullptr*/) : CDialogEx(IDD_PAGE_RECIPE, pParent) { } CPageRecipe::~CPageRecipe() { } void CPageRecipe::InitListCtrlHeaderForMaster() { m_listPPID.DeleteAllItems(); while (m_listPPID.DeleteColumn(0)); CString strIniFile, strItem; strIniFile.Format(_T("%s\\configuration.ini"), (LPTSTR)(LPCTSTR)theApp.m_strAppDir); int width[12] = { 0, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 180 }; for (int i = 0; i < 12; i++) { strItem.Format(_T("Col_%d_Width"), i); width[i] = GetPrivateProfileInt("PageRecipeListCtrl", strItem, width[i], strIniFile); } m_listPPID.InsertColumn(0, _T(""), LVCFMT_RIGHT, 0); // 隐藏列 m_listPPID.InsertColumn(1, _T("No."), LVCFMT_CENTER, width[1]); m_listPPID.InsertColumn(2, _T("PPID"), LVCFMT_LEFT, width[2]); m_listPPID.InsertColumn(3, _T("真空烘烤"), LVCFMT_LEFT, width[6]); m_listPPID.InsertColumn(4, _T("Bonder1"), LVCFMT_LEFT, width[4]); m_listPPID.InsertColumn(5, _T("Bonder2"), LVCFMT_LEFT, width[5]); m_listPPID.InsertColumn(6, _T("后烘冷却"), LVCFMT_LEFT, width[7]); m_listPPID.InsertColumn(7, _T("精度检查"), LVCFMT_LEFT, width[8]); m_listPPID.InsertColumn(8, _T("EFEM"), LVCFMT_LEFT, width[3]); m_listPPID.InsertColumn(9, _T("创建时间"), LVCFMT_LEFT, width[9]); m_listPPID.InsertColumn(10, _T("描述"), LVCFMT_LEFT, width[10]); } void CPageRecipe::InitListCtrlHeaderForDevice() { m_listPPID.DeleteAllItems(); while (m_listPPID.DeleteColumn(0)); CString strIniFile, strItem; strIniFile.Format(_T("%s\\configuration.ini"), (LPCTSTR)theApp.m_strAppDir); int width[] = { 0, 60, 100, 100, 150 }; for (int i = 0; i < 5; i++) { strItem.Format(_T("Col_Device_%d_Width"), i); width[i] = GetPrivateProfileInt(_T("PageRecipeListCtrl"), strItem, width[i], strIniFile); } m_listPPID.InsertColumn(0, _T(""), LVCFMT_RIGHT, width[0]); m_listPPID.InsertColumn(1, _T("No."), LVCFMT_CENTER, width[1]); m_listPPID.InsertColumn(2, _T("Recipe ID"), LVCFMT_LEFT, width[2]); m_listPPID.InsertColumn(3, _T("Recipe 名称"), LVCFMT_LEFT, width[3]); m_listPPID.InsertColumn(4, _T("Recipe 参数"), LVCFMT_LEFT, width[4]); } void CPageRecipe::UpdateRecipeByPPID(const CString& strPPID) { if (strPPID.IsEmpty()) { AfxMessageBox(_T("请选择一个配方!")); return; } auto& mgr = RecipeManager::getInstance(); // 查询选中配方的详细数据 std::string oldPPID = CT2A(strPPID); RecipeInfo oldRecipe = mgr.getRecipeByPPID(oldPPID); if (oldRecipe.strPPID.empty()) { AfxMessageBox(_T("获取配方数据失败!")); return; } // 弹出编辑对话框,并初始化为当前内容 CRecipeDeviceBindDlg dlg(this); dlg.SetRecipeInfo(oldRecipe); if (dlg.DoModal() == IDOK) { const RecipeInfo& newRecipe = dlg.GetRecipeInfo(); bool success = false; // 判断PPID是否有改动 if (oldRecipe.strPPID != newRecipe.strPPID) { // 先更新PPID,再整体更新内容 if (mgr.updatePPID(oldRecipe.strPPID, newRecipe.strPPID)) { success = mgr.updateRecipe(newRecipe); if (!success) { AfxMessageBox(_T("已更改PPID,但更新配方内容失败,请检查日志")); } } else { AfxMessageBox(_T("更新PPID失败,请检查日志")); return; } } else { // 只更新内容 success = mgr.updateRecipe(newRecipe); if (!success) { AfxMessageBox(_T("更新配方失败,请检查日志")); } } if (success) { auto vecData = mgr.getAllRecipes(); FillDataToListCtrl(vecData); } } } void CPageRecipe::FillDataToListCtrl(const std::vector& vecRecipe) { CListCtrl* pListCtrl = (CListCtrl*)GetDlgItem(IDC_LIST_PPID); if (pListCtrl == nullptr || !::IsWindow(pListCtrl->m_hWnd)) { return; } // 清空当前CListCtrl中的所有项 pListCtrl->DeleteAllItems(); // 遍历数据并插入到CListCtrl中 for (int i = 0; i < static_cast(vecRecipe.size()); ++i) { const RecipeInfo& recipe = vecRecipe[i]; if (recipe.vecDeviceList.empty() || recipe.vecDeviceList.size() > 6){ continue; } m_listPPID.InsertItem(i, _T("")); // 第0列空白 CString strNo; strNo.Format(_T("%d"), i + 1); m_listPPID.SetItemText(i, 1, strNo); m_listPPID.SetItemText(i, 2, CA2T(recipe.strPPID.c_str())); for (int j = 0; j < recipe.vecDeviceList.size(); j++){ int nRecipeID = recipe.vecDeviceList.at(j).nRecipeID; std::string strDeviceName = recipe.vecDeviceList.at(j).strDeviceName; std::string strRecipeName = RecipeManager::getInstance().getDeviceRecipeName(strDeviceName, nRecipeID); CString str; if (strRecipeName.empty()) { str.Format(_T("%d"), recipe.vecDeviceList.at(j).nRecipeID); } else { str.Format(_T("%s"), strRecipeName.c_str()); } m_listPPID.SetItemText(i, j + 3, str); } m_listPPID.SetItemText(i, 9, CA2T(recipe.strCreateTime.c_str())); m_listPPID.SetItemText(i, 10, CA2T(recipe.strDescription.c_str())); } // 获取列数 int nColCount = m_listPPID.GetHeaderCtrl()->GetItemCount(); m_listPPID.SetColumnWidth(nColCount - 1, LVSCW_AUTOSIZE_USEHEADER); } void CPageRecipe::FillRecipeListToListCtrl(SERVO::CEquipment* pEq) { SERVO::CRecipeList* pRecipeList = pEq->getRecipeList(0); CListCtrl* pListCtrl = (CListCtrl*)GetDlgItem(IDC_LIST_PPID); if (pListCtrl == nullptr || !::IsWindow(pListCtrl->m_hWnd)) { return; } // 清空当前CListCtrl中的所有项 pListCtrl->DeleteAllItems(); if (pRecipeList == nullptr) { return; } // 遍历数据并插入到CListCtrl中 auto& mgr = RecipeManager::getInstance(); std::map& ids = pRecipeList->getIds(); auto rawDatas = pRecipeList->getParamsRawData(); for (auto item : ids) { int index = m_listPPID.InsertItem(m_listPPID.GetItemCount(), _T("")); m_listPPID.SetItemText(index, 1, std::to_string(item.first).c_str()); m_listPPID.SetItemText(index, 2, std::to_string(item.second).c_str()); std::string strRecipeName = mgr.getDeviceRecipeName(SanitizeName(pEq->getName()), item.second); m_listPPID.SetItemText(index, 3, strRecipeName.c_str()); std::string strDescription; auto iter = rawDatas.find(item.second); if (iter != rawDatas.end()) { pEq->parsingParams((const char*)iter->second.data(), iter->second.size(), strDescription); m_listPPID.SetItemText(index, 4, strDescription.c_str()); } if (strRecipeName.empty()) { strRecipeName = std::to_string(item.second); mgr.addDeviceRecipe(SanitizeName(pEq->getName()), item.second, strRecipeName, strDescription); } } // 获取列数 int nColCount = m_listPPID.GetHeaderCtrl()->GetItemCount(); m_listPPID.SetColumnWidth(nColCount - 1, LVSCW_AUTOSIZE_USEHEADER); } void CPageRecipe::DoDataExchange(CDataExchange* pDX) { CDialogEx::DoDataExchange(pDX); DDX_Control(pDX, IDC_LIST_PPID, m_listPPID); } BEGIN_MESSAGE_MAP(CPageRecipe, CDialogEx) ON_WM_SIZE() ON_WM_DESTROY() ON_WM_SHOWWINDOW() ON_BN_CLICKED(IDC_BUTTON_NEW, &CPageRecipe::OnBnClickedButtonNew) ON_BN_CLICKED(IDC_BUTTON_SEARCH, &CPageRecipe::OnBnClickedButtonSearch) ON_BN_CLICKED(IDC_BUTTON_MODIFY, &CPageRecipe::OnBnClickedButtonModify) ON_BN_CLICKED(IDC_BUTTON_DELETE, &CPageRecipe::OnBnClickedButtonDelete) ON_BN_CLICKED(IDC_BUTTON_DELETE_ALL, &CPageRecipe::OnBnClickedButtonDeleteAll) ON_BN_CLICKED(IDC_BUTTON_REFRESH, &CPageRecipe::OnBnClickedButtonRefresh) ON_NOTIFY(NM_CLICK, IDC_LIST_PPID, &CPageRecipe::OnClickListPPID) ON_NOTIFY(NM_DBLCLK, IDC_LIST_PPID, &CPageRecipe::OnDblclkListPPID) ON_CBN_SELCHANGE(IDC_COMBO_EQUIPMENT, &CPageRecipe::OnCbnSelchangeComboEquipment) END_MESSAGE_MAP() // CPageRecipe 消息处理程序 BOOL CPageRecipe::OnInitDialog() { CDialogEx::OnInitDialog(); // TODO: 在此添加额外的初始化 CListCtrl* pListCtrl = (CListCtrl*)GetDlgItem(IDC_LIST_PPID); DWORD dwStyle = pListCtrl->GetExtendedStyle(); dwStyle |= LVS_EX_FULLROWSELECT; dwStyle |= LVS_EX_GRIDLINES; pListCtrl->SetExtendedStyle(dwStyle); HIMAGELIST imageList = ImageList_Create(24, 24, ILC_COLOR24, 1, 1); ListView_SetImageList(pListCtrl->GetSafeHwnd(), imageList, LVSIL_SMALL); InitListCtrlHeaderForMaster(); // 获取所有数据 auto vecData = RecipeManager::getInstance().getAllRecipes(); FillDataToListCtrl(vecData); return TRUE; // return TRUE unless you set the focus to a control // 异常: OCX 属性页应返回 FALSE } void CPageRecipe::OnSize(UINT nType, int cx, int cy) { CDialogEx::OnSize(nType, cx, cy); if (!m_listPPID.GetSafeHwnd()) return; // 左侧列表宽高自适应 int margin = 12; int buttonWidth = 80; int buttonHeight = 30; int buttonSpacing = 10; CWnd* pItem; CRect rect, rcItem; GetClientRect(&rect); pItem = GetDlgItem(IDC_EDIT_KEYWORD); ASSERT(pItem); pItem->GetWindowRect(rcItem); ScreenToClient(&rcItem); int y = rcItem.bottom; y += 12; int listWidth = rect.Width() - buttonWidth - 3 * margin; m_listPPID.MoveWindow(margin, y, listWidth, rect.bottom - 12 - y); // 按钮竖直排列在右侧 CWnd* buttons[] = { GetDlgItem(IDC_BUTTON_REFRESH), GetDlgItem(IDC_BUTTON_NEW), GetDlgItem(IDC_BUTTON_MODIFY), GetDlgItem(IDC_BUTTON_DELETE), GetDlgItem(IDC_BUTTON_DELETE_ALL) }; for (auto pBtn : buttons) { if (pBtn && pBtn->GetSafeHwnd()) { pBtn->MoveWindow(rect.right - buttonWidth - margin, y, buttonWidth, buttonHeight); y += buttonHeight + buttonSpacing; } } } void CPageRecipe::OnDestroy() { CComboBox* pComboBox = (CComboBox*)GetDlgItem(IDC_COMBO_EQUIPMENT); int nSel = pComboBox->GetCurSel(); SERVO::CEquipment* pEq = (SERVO::CEquipment*)pComboBox->GetItemDataPtr(nSel); // 保存列宽 CString strIniFile, strItem, strTemp; strIniFile.Format(_T("%s\\configuration.ini"), (LPCTSTR)theApp.m_strAppDir); CHeaderCtrl* pHeader = m_listPPID.GetHeaderCtrl(); if (!pHeader || pHeader->GetItemCount() == 0) { return; } for (int i = 0; i < pHeader->GetItemCount(); i++) { RECT rect; if (!pHeader->GetItemRect(i, &rect)) { continue; } if (pEq == nullptr) { strItem.Format(_T("Col_%d_Width"), i); } else { strItem.Format(_T("Col_Device_%d_Width"), i); } strTemp.Format(_T("%d"), rect.right - rect.left); WritePrivateProfileString(_T("PageRecipeListCtrl"), strItem, strTemp, strIniFile); } CDialogEx::OnDestroy(); } void CPageRecipe::OnShowWindow(BOOL bShow, UINT nStatus) { CDialogEx::OnShowWindow(bShow, nStatus); if (bShow) { CComboBox* pComboBox = (CComboBox*)GetDlgItem(IDC_COMBO_EQUIPMENT); if (pComboBox->GetCount() == 0) { SERVO::CMaster& master = theApp.m_model.getMaster(); SERVO::CEquipment* pEq[] = { nullptr, master.getEquipment(EQ_ID_EFEM), master.getEquipment(EQ_ID_Bonder1), master.getEquipment(EQ_ID_Bonder2), master.getEquipment(EQ_ID_BAKE_COOLING), master.getEquipment(EQ_ID_VACUUMBAKE), master.getEquipment(EQ_ID_MEASUREMENT), }; CComboBox* pComboBox = (CComboBox*)GetDlgItem(IDC_COMBO_EQUIPMENT); for (int i = 0; i < sizeof(pEq) / sizeof(pEq[0]); i++) { pComboBox->InsertString(i, pEq[i] == nullptr ? _T("Master") : pEq[i]->getName().c_str()); pComboBox->SetItemDataPtr(i, pEq[i]); // 读取回来 char szBuffer[_MAX_PATH]; if (pEq[i]) { sprintf_s(szBuffer, _MAX_PATH, "%s\\Recipe\\EQ%d_Unit0.recipelist", (LPTSTR)(LPCTSTR)theApp.m_strAppDir, pEq[i]->getID()); std::string strFilepath(szBuffer); pEq[i]->readRecipeList(0, strFilepath); } } pComboBox->SetCurSel(0); } } } void CPageRecipe::OnBnClickedButtonNew() { // TODO: 在此添加控件通知处理程序代码 //CComboBox* pComboBox = (CComboBox*)GetDlgItem(IDC_COMBO_EQUIPMENT); //int nSel = pComboBox->GetCurSel(); //SERVO::CEquipment* pEq = (SERVO::CEquipment*)pComboBox->GetItemDataPtr(nSel); //if (pEq == nullptr) { // return; //} CRecipeDeviceBindDlg dlg(this); if (dlg.DoModal() == IDOK) { const RecipeInfo& newRecipe = dlg.GetRecipeInfo(); auto& mgr = RecipeManager::getInstance(); if (mgr.ppidExists(newRecipe.strPPID)) { // 已存在,询问是否覆盖 int ret = AfxMessageBox(_T("该 PPID 已存在,是否覆盖原配方?"), MB_YESNO | MB_ICONQUESTION); if (ret == IDYES) { if (mgr.updateRecipe(newRecipe)) { auto vecData = mgr.getAllRecipes(); FillDataToListCtrl(vecData); } else { AfxMessageBox(_T("更新配方失败,请检查日志")); } } } else { // 不存在,直接新增 if (mgr.addRecipe(newRecipe)) { auto vecData = mgr.getAllRecipes(); FillDataToListCtrl(vecData); } else { AfxMessageBox(_T("添加配方失败,请检查日志")); } } } } void CPageRecipe::OnBnClickedButtonSearch() { CString strKeyword; GetDlgItemText(IDC_EDIT_KEYWORD, strKeyword); strKeyword.Trim(); std::vector vecData; if (strKeyword.IsEmpty()) { // 关键词为空,显示全部配方 vecData = RecipeManager::getInstance().getAllRecipes(); } else { // 根据关键词搜索配方 vecData = RecipeManager::getInstance().getRecipesByKeyword(std::string(CT2A(strKeyword))); } // 如果没有数据,弹出提示 if (vecData.empty()) { AfxMessageBox(_T("未找到匹配的配方!")); return; } FillDataToListCtrl(vecData); } void CPageRecipe::OnBnClickedButtonModify() { // TODO: 在此添加控件通知处理程序代码 CComboBox* pComboBox = (CComboBox*)GetDlgItem(IDC_COMBO_EQUIPMENT); if (pComboBox == nullptr || !::IsWindow(pComboBox->m_hWnd)) { return; } POSITION pos = m_listPPID.GetFirstSelectedItemPosition(); if (!pos) { AfxMessageBox(_T("请先选择一条配方记录进行修改!")); return; } int nLine = m_listPPID.GetNextSelectedItem(pos); CString strID = m_listPPID.GetItemText(nLine, 2); int nSel = pComboBox->GetCurSel(); SERVO::CEquipment* pEq = (SERVO::CEquipment*)pComboBox->GetItemDataPtr(nSel); if (pEq == nullptr) { UpdateRecipeByPPID(strID); } else { CInputDialog dlg(_T("修改配方名称"), _T("请输入配方名称:")); if (dlg.DoModal() != IDOK) { return; } CString strText = dlg.GetInputText(); if (strText.IsEmpty()) { AfxMessageBox(_T("配方名称不能为空!")); return; } if (RecipeManager::getInstance().updateDeviceRecipeName(SanitizeName(pEq->getName()), _ttoi(strID), std::string(CT2A(strText)))) { m_listPPID.SetItemText(nLine, 3, strText); } } } void CPageRecipe::OnBnClickedButtonDelete() { // TODO: 在此添加控件通知处理程序代码 POSITION pos = m_listPPID.GetFirstSelectedItemPosition(); if (!pos) { return; } int nSel = m_listPPID.GetNextSelectedItem(pos); CString strPPID = m_listPPID.GetItemText(nSel, 2); std::string ppid = CT2A(strPPID); if (!ppid.empty()) { CString msg; msg.Format(_T("确定要删除配方 [%s] 吗?"), strPPID); if (IDYES == AfxMessageBox(msg, MB_YESNO | MB_ICONQUESTION)) { if (RecipeManager::getInstance().deleteRecipeByPPID(ppid)) { m_listPPID.DeleteItem(nSel); } else { AfxMessageBox(_T("删除失败")); } } } } void CPageRecipe::OnBnClickedButtonDeleteAll() { // TODO: 在此添加控件通知处理程序代码 if (IDYES != AfxMessageBox(_T("确定要删除全部配方记录吗?"), MB_YESNO | MB_ICONWARNING)) { return; } // 获取所有 PPID int nCount = m_listPPID.GetItemCount(); for (int i = 0; i < nCount; ++i) { CString strPPID = m_listPPID.GetItemText(i, 2); std::string ppid = CT2A(strPPID); if (!ppid.empty()) { RecipeManager::getInstance().deleteRecipeByPPID(ppid); } } // 清空列表显示 m_listPPID.DeleteAllItems(); } void CPageRecipe::OnBnClickedButtonRefresh() { CComboBox* pComboBox = (CComboBox*)GetDlgItem(IDC_COMBO_EQUIPMENT); int nSel = pComboBox->GetCurSel(); SERVO::CEquipment* pEq = (SERVO::CEquipment*)pComboBox->GetItemDataPtr(nSel); if (pEq == nullptr) { // 获取master配方(本地) auto vecData = RecipeManager::getInstance().getAllRecipes(); FillDataToListCtrl(vecData); } else { // 获取配方列表 CMsgDlg msgDlg("请等待", "正在获取配方列表..."); msgDlg.SetData((DWORD_PTR)this); msgDlg.SetDataEx((DWORD_PTR)pEq); msgDlg.BeginThread(SyncThreadFunction); msgDlg.DoModal(); } } void CPageRecipe::OnClickListPPID(NMHDR* pNMHDR, LRESULT* pResult) { LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast(pNMHDR); // TODO: 在此添加控件通知处理程序代码 *pResult = 0; CComboBox* pComboBox = (CComboBox*)GetDlgItem(IDC_COMBO_EQUIPMENT); if (pComboBox == nullptr) { return; } int nItem = pNMItemActivate->iItem; int nEqSel = pComboBox->GetCurSel(); GetDlgItem(IDC_BUTTON_NEW)->EnableWindow(nEqSel == 0); GetDlgItem(IDC_BUTTON_MODIFY)->EnableWindow(nItem != -1); GetDlgItem(IDC_BUTTON_DELETE)->EnableWindow(nEqSel == 0 && nItem != -1); GetDlgItem(IDC_BUTTON_DELETE_ALL)->EnableWindow(nEqSel == 0 && nItem != -1); } void CPageRecipe::OnDblclkListPPID(NMHDR* pNMHDR, LRESULT* pResult) { LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast(pNMHDR); // TODO: 在此添加控件通知处理程序代码 *pResult = 0; int nItem = pNMItemActivate->iItem; if (nItem < 0) { return; } CString strText = m_listPPID.GetItemText(nItem, 2); CComboBox* pComboBox = (CComboBox*)GetDlgItem(IDC_COMBO_EQUIPMENT); int nEqSel = pComboBox->GetCurSel(); if (nEqSel == CB_ERR) { return; } SERVO::CEquipment* pEq = (SERVO::CEquipment*)pComboBox->GetItemDataPtr(nEqSel); if (pEq == nullptr) { return; } } void CPageRecipe::OnCbnSelchangeComboEquipment() { CComboBox* pComboBox = (CComboBox*)GetDlgItem(IDC_COMBO_EQUIPMENT); int nEqSel = pComboBox->GetCurSel(); int nItem = ListView_GetSelectedCount(m_listPPID.GetSafeHwnd()); GetDlgItem(IDC_BUTTON_NEW)->EnableWindow(nEqSel == 0); GetDlgItem(IDC_BUTTON_MODIFY)->EnableWindow(nEqSel == 0 && nItem != -1); GetDlgItem(IDC_BUTTON_DELETE)->EnableWindow(nEqSel == 0 && nItem != -1); GetDlgItem(IDC_BUTTON_DELETE_ALL)->EnableWindow(nEqSel == 0 && nItem != -1); GetDlgItem(IDC_EDIT_KEYWORD)->EnableWindow(nEqSel == 0); GetDlgItem(IDC_BUTTON_SEARCH)->EnableWindow(nEqSel == 0); SERVO::CEquipment* pEq = (SERVO::CEquipment*)pComboBox->GetItemDataPtr(nEqSel); if (pEq == nullptr) { InitListCtrlHeaderForMaster(); auto vecData = RecipeManager::getInstance().getAllRecipes(); FillDataToListCtrl(vecData); } else { InitListCtrlHeaderForDevice(); FillRecipeListToListCtrl(pEq); } } UINT CPageRecipe::SyncThreadFunction(LPVOID lpvData) { CMsgDlg* pMsgDlg = (CMsgDlg*)lpvData; CPageRecipe* pPageRecipe = (CPageRecipe*)pMsgDlg->GetData(); return pPageRecipe->SyncThreadFunctionInner(pMsgDlg); } UINT CPageRecipe::SyncThreadFunctionInner(CMsgDlg* pMsgDlg) { SERVO::CEquipment* pEq = (SERVO::CEquipment*)pMsgDlg->GetDataEx(); HANDLE hEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL); int nStep = 0; // 准备配方路径 char szBuffer[_MAX_PATH]; sprintf_s(szBuffer, _MAX_PATH, "%s\\Recipe\\EQ%d_Unit0.recipelist", (LPTSTR)(LPCTSTR)theApp.m_strAppDir, pEq->getID()); std::string strFilepath(szBuffer); pEq->masterRecipeListRequest(0, [&, pEq, pMsgDlg, hEvent](int status) -> void { Sleep(300); if (status == SS_FAILED || status == SS_TIMEOUT) { CString strMsg; strMsg.Format(status == SS_FAILED ? _T("获取配方列表失败!") : _T("获取配方列表超时!")); pMsgDlg->SetIcon(MSG_BOX_ERROR); pMsgDlg->SetTitle(_T("操作失败")); pMsgDlg->SetMessage((LPTSTR)(LPCTSTR)strMsg); SetEvent(hEvent); } else if (status == SS_LIST_COMPLETE) { CString strMsg; strMsg.Format(_T("获取配方列表完成!")); pMsgDlg->SetTitle(_T("操作成功")); pMsgDlg->SetMessage((LPTSTR)(LPCTSTR)strMsg); SERVO::CRecipeList* pRecipeList = pEq->getRecipeList(0); if (pRecipeList != nullptr && !pRecipeList->getIds().empty()) { nStep = 1; } SetEvent(hEvent); } }); ::WaitForSingleObject(hEvent, INFINITE); if (nStep != 1) { pEq->saveRecipeList(0, strFilepath); pMsgDlg->SetIcon(MSG_BOX_SUCCEED); pMsgDlg->SetMarquee(FALSE, 0); pMsgDlg->SetCompleteCode(-1); pMsgDlg->DelayClose(3000); } ResetEvent(hEvent); // 参数列表 if (nStep == 1) { SERVO::CRecipeList* pRecipeList = pEq->getRecipeList(0); ASSERT(pRecipeList); auto& ids = pRecipeList->getIds(); pMsgDlg->SetTitle(_T("正在获取参数")); for (auto item : ids) { int recipeId = item.second; CString strMsg; strMsg.Format(_T("正在获取配方 %d 参数..."), item.second); pMsgDlg->SetMessage((LPTSTR)(LPCTSTR)strMsg); pEq->recipeParameterRequest(0, recipeId, 0, [&, pEq, pMsgDlg, recipeId, hEvent](int status) -> void { Sleep(500); if (status == SS_FAILED || status == SS_TIMEOUT) { CString strMsg; strMsg.Format(status == SS_FAILED ? _T("获取配方 %d 参数失败!") : _T("获取配方 %d 参数超时!"), recipeId); pMsgDlg->SetMessage((LPTSTR)(LPCTSTR)strMsg); Sleep(30); SetEvent(hEvent); } else if (status == SS_PARAMS_COMPLETE) { CString strMsg; strMsg.Format(_T("获取配方 %d 参数完成!"), item.second); pMsgDlg->SetMessage((LPTSTR)(LPCTSTR)strMsg); Sleep(30); SetEvent(hEvent); } }); ::WaitForSingleObject(hEvent, INFINITE); ResetEvent(hEvent); } pEq->saveRecipeList(0, strFilepath); pMsgDlg->SetIcon(MSG_BOX_SUCCEED); pMsgDlg->SetTitle(_T("操作完成")); pMsgDlg->SetCompleteCode(0); pMsgDlg->SetMarquee(FALSE, 0); pMsgDlg->DelayClose(3000); }; FillRecipeListToListCtrl(pEq); CloseHandle(hEvent); // 在此打印配方参数以便核对数据 SERVO::CRecipeList* pRecipeList = pEq->getRecipeList(0); ASSERT(pRecipeList); auto rawDatas = pRecipeList->getParamsRawData(); for (auto item : rawDatas) { TRACE("================= 配方 %d\n", item.first); std::vector params; pEq->parsingParams((const char*)item.second.data(), item.second.size(), params); for (auto p : params) { if (p.getValueType() == PVT_INT) { TRACE("%s: %d\n", p.getName().c_str(), p.getIntValue()); } else if (p.getValueType() == PVT_DOUBLE) { TRACE("%s: %f\n", p.getName().c_str(), p.getDoubleValue()); } } } return 0; } std::string CPageRecipe::SanitizeName(const std::string& name) { std::string result; result.reserve(name.size()); for (char c : name) { if (c == '(' || c == '(') { break; } unsigned char uc = static_cast(c); if (std::isalnum(uc) || c == '_') { result.push_back(c); } else if (std::isspace(uc)) { continue; } else { result.push_back('_'); } } return result; }