// RecipeLiseDlg.cpp: 实现文件 // #include "stdafx.h" #include "BondEq.h" #include "afxdialogex.h" #include "RecipeListDlg.h" #include "InputDialog.h" #include "ToolUnits.h" #include #include #include // CRecipeListDlg 对话框 IMPLEMENT_DYNAMIC(CRecipeListDlg, CBaseDlg) CRecipeListDlg::CRecipeListDlg(CWnd* pParent /*=nullptr*/) : CBaseDlg(IDD_DIALOG_RECIPE_LIST, pParent) { m_staticCurrRecipe = new CBLLabel(); } CRecipeListDlg::~CRecipeListDlg() { if (m_staticCurrRecipe != nullptr) { delete m_staticCurrRecipe; m_staticCurrRecipe = nullptr; } } void CRecipeListDlg::AdjustLabelFont(CBLLabel& label) { if (label.m_hWnd == nullptr) { return; } // 获取控件的矩形区域 CRect rect; label.GetClientRect(&rect); // 动态计算字体大小,基于控件的高度 int fontSize = rect.Height() / 2; // 控件高度的一半作为字体大小 if (fontSize < 8) fontSize = 8; // 最小字体大小 if (fontSize > 30) fontSize = 30; // 最大字体大小 // 设置字体大小 label.SetFontSize(fontSize); // 刷新控件显示 label.Invalidate(); label.UpdateWindow(); } void CRecipeListDlg::InitRecipeLise() { if (m_grid.GetSafeHwnd() == NULL) return; int nRows = 1; int nCols = 4; int nFixRows = 1; int nFixCols = 0; int nRowIdx = 0; int nColIdx = 0; m_grid.DeleteAllItems(); m_grid.SetVirtualMode(FALSE); m_grid.GetDefaultCell(TRUE, FALSE)->SetBackClr(g_nGridFixCellColor); // 设置固定行背景色 m_grid.GetDefaultCell(FALSE, TRUE)->SetBackClr(g_nGridFixCellColor); // 设置固定列背景色 m_grid.GetDefaultCell(FALSE, FALSE)->SetBackClr(g_nGridCellColor); // 设置单元格背景色 m_grid.SetFixedTextColor(g_nGridFixFontColor); // 设置固定行列字体颜色 m_grid.SetRowCount(nRows); m_grid.SetColumnCount(nCols); m_grid.SetFixedRowCount(nFixRows); m_grid.SetFixedColumnCount(nFixCols); // Col m_grid.SetColumnWidth(nColIdx, 10); m_grid.SetItemText(nRowIdx, nColIdx++, _T("No.")); m_grid.SetColumnWidth(nColIdx, 10); m_grid.SetItemText(nRowIdx, nColIdx++, _T("名称")); m_grid.SetColumnWidth(nColIdx, 120); m_grid.SetItemText(nRowIdx, nColIdx++, _T("描述")); m_grid.SetColumnWidth(nColIdx, 30); m_grid.SetItemText(nRowIdx, nColIdx++, _T("创建时间")); m_grid.SetFixedRowSelection(FALSE); // 设置固定行不可选中 m_grid.SetFixedColumnSelection(FALSE); // 设置固定列不可选中 m_grid.SetEditable(FALSE); // 设置单元格可编辑 m_grid.SetRowResize(FALSE); // 设置行不可调整大小 m_grid.SetColumnResize(TRUE); // 设置列可调整大小 m_grid.ExpandColumnsToFit(TRUE); // 自动调整列宽 m_grid.SetListMode(TRUE); // 启用列表模式 m_grid.EnableSelection(TRUE); // 启用选择 m_grid.SetSingleRowSelection(TRUE); // 自动整行高亮(限制为单行选择) m_grid.ExpandLastColumn(); // 最后一列填充网格 FillRecipeLise(); } void CRecipeListDlg::FillRecipeLise() { // 清除数据行,保留表头 for (int i = m_grid.GetRowCount() - 1; i > 0; --i) { m_grid.DeleteRow(i); } // 1. 遍历文件夹下所有XML文件 std::string strRecipePath = CToolUnits::getRecipePath(); std::vector vecFile = CToolUnits::GetFileNamesInDirectory(strRecipePath.c_str(), _T(".xml")); // 2. 读取 RecipeList.txt 文件 std::map> recipeData; // {配方名, {描述, 创建时间}} std::ifstream inFile(strRecipePath + "\\RecipeList.txt"); if (inFile.is_open()) { std::string line; while (std::getline(inFile, line)) { if (line.empty()) continue; // 跳过空行 std::istringstream ss(line); std::string name, description, createTime; // CSV格式解析(逗号分隔) if (std::getline(ss, name, ',') && std::getline(ss, description, ',') && std::getline(ss, createTime)) { recipeData[CString(name.c_str())] = std::make_pair(CString(description.c_str()), CString(createTime.c_str())); } } inFile.close(); } // 3. 更新表格数据 int rowIdx = 1; m_grid.SetRowCount(static_cast(vecFile.size()) + 1); for (const auto& fileName : vecFile) { // 从 RecipeList.txt 数据中查找对应的描述和创建时间 CString description = _T(""); CString createTime = _T(""); auto it = recipeData.find(fileName); if (it != recipeData.end()) { description = it->second.first; // 配方描述 createTime = it->second.second; // 创建时间 } // 填充表格数据 m_grid.SetItemText(rowIdx, 0, CString(std::to_string(rowIdx).c_str())); // No. m_grid.SetItemText(rowIdx, 1, fileName); // 配方名称 m_grid.SetItemText(rowIdx, 2, description); // 配方描述 m_grid.SetItemText(rowIdx, 3, createTime); // 创建时间 ++rowIdx; } m_grid.ExpandColumnsToFit(FALSE); // 自动调整列宽 m_grid.ExpandLastColumn(); // 最后一列填充网格 // 刷新网格控件 m_grid.Invalidate(); m_grid.UpdateWindow(); } void CRecipeListDlg::UpdateDataFile(const CString& strRecipeName, const CString& strNewDescription) { CStdioFile file; CFileException fe; // 打开文件以读取和写入 CString strFilePath; strFilePath.Format(_T("%s\\RecipeList.txt"), CToolUnits::getRecipePath().c_str()); if (file.Open(strFilePath, CFile::modeReadWrite | CFile::shareDenyNone, &fe)) { CString strLine; CStringArray arrLines; BOOL bFound = FALSE; // 读取文件内容到内存 while (file.ReadString(strLine)) { // 将这一行按逗号分割 CStringArray arrColumns; int nPos = 0; while ((nPos = strLine.Find(_T(','))) != -1) { arrColumns.Add(strLine.Left(nPos)); strLine = strLine.Mid(nPos + 1); } arrColumns.Add(strLine); // 最后一列 // 如果第一列(配方名称)匹配,修改第二列(配方描述) if (arrColumns.GetSize() > 0 && arrColumns[0] == strRecipeName) { arrColumns[1] = strNewDescription; // 修改配方描述列 bFound = TRUE; } // 将修改后的行保存回内存 CString strUpdatedLine; for (int i = 0; i < arrColumns.GetSize(); ++i) { if (i > 0) strUpdatedLine += _T(","); strUpdatedLine += arrColumns[i]; } arrLines.Add(strUpdatedLine); } if (bFound) { // 如果找到了配方名称,保存修改后的内容回文件 file.SeekToBegin(); file.SetLength(0); // 清空文件内容 for (int i = 0; i < arrLines.GetSize(); ++i) { file.WriteString(arrLines[i] + _T("\n")); } } else { // 如果没有找到配方名称,则追加新配方 CString strNewLine; strNewLine.Format(_T("%s,%s,%s"), strRecipeName, strNewDescription, CToolUnits::getCurrentTimeString().c_str()); file.SeekToEnd(); file.WriteString(strNewLine + _T("\n")); } file.Close(); } else { AfxMessageBox(_T("无法打开文件")); } } void CRecipeListDlg::DoDataExchange(CDataExchange* pDX) { CBaseDlg::DoDataExchange(pDX); DDX_Control(pDX, IDC_CUSTOM_RECIPE_LIST, m_grid); } BEGIN_MESSAGE_MAP(CRecipeListDlg, CBaseDlg) ON_BN_CLICKED(IDC_BUTTON_CREATE_RECIPE, &CRecipeListDlg::OnBnClickedButtonCreateRecipe) ON_BN_CLICKED(IDC_BUTTON_DELETE_RECIPE, &CRecipeListDlg::OnBnClickedButtonDeleteRecipe) ON_BN_CLICKED(IDC_BUTTON_SELECT_RECIPE, &CRecipeListDlg::OnBnClickedButtonSelectRecipe) ON_NOTIFY(NM_DBLCLK, IDC_CUSTOM_RECIPE_LIST, &CRecipeListDlg::OnGridCellEditFinished) ON_WM_SIZE() END_MESSAGE_MAP() // CRecipeListDlg 消息处理程序 BOOL CRecipeListDlg::OnInitDialog() { CBaseDlg::OnInitDialog(); // TODO: 在此添加额外的初始化 m_staticCurrRecipe->SubclassDlgItem(IDC_STATIC_CURR_RECIPE, this); m_staticCurrRecipe->SetBkColor(RGB(0, 110, 110)); m_staticCurrRecipe->ModifyStyle(0, SS_NOTIFY); m_staticCurrRecipe->SetTextColor(RGB(255, 255, 255)); m_staticCurrRecipe->SetAlignment(AlignCenter); m_staticCurrRecipe->SetDynamicFont(TRUE); m_staticCurrRecipe->SetWindowText(RecipeManager::getInstance().getCurrentRecipeName().c_str()); AdjustLabelFont(*m_staticCurrRecipe); InitRecipeLise(); return TRUE; // return TRUE unless you set the focus to a control // 异常: OCX 属性页应返回 FALSE } void CRecipeListDlg::OnSize(UINT nType, int cx, int cy) { CBaseDlg::OnSize(nType, cx, cy); // TODO: 在此处添加消息处理程序代码 AdjustLabelFont(*m_staticCurrRecipe); } void CRecipeListDlg::OnBnClickedButtonCreateRecipe() { // TODO: 在此添加控件通知处理程序代码 CInputDialog inputDialog(_T("配方名称"), _T("请输入配方名称:")); if (inputDialog.DoModal() != IDOK) { return; } CString newRecipeName = inputDialog.GetInputText(); // 验证名称不重复 std::string recipePath = CToolUnits::getRecipePath(); std::string recipeListPath = recipePath + "\\RecipeList.txt"; std::vector existingFiles = CToolUnits::GetFileNamesInDirectory(recipePath.c_str(), ".xml"); for (const auto& fileName : existingFiles) { if (newRecipeName.Compare(fileName) == 0) { AfxMessageBox(_T("配方名称已存在,请输入其他名称!")); return; } } // 检查是否要复制选中配方 CString strCopyRecipe = _T(""); for (int i = 1; i < m_grid.GetRowCount(); i++) { if (m_grid.IsCellSelected(i, 1)) { strCopyRecipe = m_grid.GetItemText(i, 1); CString strMessage; strMessage.Format(_T("Copy [%s] -> [%s]?"), strCopyRecipe, newRecipeName); if (AfxMessageBox(strMessage, MB_YESNO | MB_ICONQUESTION) != IDYES) { strCopyRecipe = _T(""); } break; } } // 创建新的XML文件 CString newRecipeFile = CString(recipePath.c_str()) + "\\" + newRecipeName + ".xml"; if (!strCopyRecipe.IsEmpty()) { CString sourceFile = CString(recipePath.c_str()) + "\\" + strCopyRecipe + ".xml"; CopyFile(sourceFile, newRecipeFile, FALSE); } else { // 生成默认XML文件 RecipeManager& recipeManager = RecipeManager::getInstance(); recipeManager.generateDefaultRecipe(); if (!recipeManager.saveRecipe(std::string(CT2A(newRecipeName)))) { AfxMessageBox(_T("创建配方失败!")); return; } } // 更新 RecipeList.txt std::ofstream outFile(recipeListPath, std::ios::app); // 追加模式 if (outFile.is_open()) { SYSTEMTIME sysTime; GetLocalTime(&sysTime); char buffer[64]; sprintf_s(buffer, "%04d-%02d-%02d %02d:%02d:%02d", sysTime.wYear, sysTime.wMonth, sysTime.wDay, sysTime.wHour, sysTime.wMinute, sysTime.wSecond); outFile << CT2A(newRecipeName) << ",默认描述," << buffer << std::endl; outFile.close(); } // 刷新网格控件 FillRecipeLise(); } void CRecipeListDlg::OnBnClickedButtonDeleteRecipe() { // TODO: 在此添加控件通知处理程序代码 int nSelect = -1; for (int i = 1; i < m_grid.GetRowCount(); i++) { if (m_grid.IsCellSelected(i, 1)) { nSelect = i; break; } } if (nSelect < 0) { AfxMessageBox(_T("请选择要删除的配方!")); return; } CString selectedRecipe = m_grid.GetItemText(nSelect, 1); if (selectedRecipe.IsEmpty()) { AfxMessageBox(_T("配方名称无效!")); return; } CString message = _T("确定要删除配方 \"") + selectedRecipe + _T("\" 吗?"); if (AfxMessageBox(message, MB_YESNO | MB_ICONQUESTION) != IDYES) { return; } // 删除XML文件 std::string recipePath = CToolUnits::getRecipePath(); CString xmlFilePath = CString(recipePath.c_str()) + "\\" + selectedRecipe + ".xml"; if (!DeleteFile(xmlFilePath)) { AfxMessageBox(_T("删除XML文件失败!")); return; } // 更新RecipeList.txt文件 std::string recipeListPath = recipePath + "\\RecipeList.txt"; std::ifstream inFile(recipeListPath); std::ofstream outFile(recipeListPath + ".tmp"); // 创建临时文件 if (inFile.is_open() && outFile.is_open()) { std::string line; while (std::getline(inFile, line)) { std::istringstream ss(line); std::string name; if (std::getline(ss, name, ',')) { if (selectedRecipe != CString(name.c_str())) { outFile << line << std::endl; // 保留不匹配的行 } } } inFile.close(); outFile.close(); // 替换文件 DeleteFile(CString(recipeListPath.c_str())); MoveFile(CString((recipeListPath + ".tmp").c_str()), CString(recipeListPath.c_str())); } // 刷新网格控件 FillRecipeLise(); } void CRecipeListDlg::OnBnClickedButtonSelectRecipe() { // TODO: 在此添加控件通知处理程序代码 int nSelect = -1; for (int i = 1; i < m_grid.GetRowCount(); i++) { if (m_grid.IsCellSelected(i, 1)) { nSelect = i; break; } } if (nSelect < 0) { AfxMessageBox(_T("请选择配方!")); return; } CString strSelectedRecipe = m_grid.GetItemText(nSelect, 1); if (RecipeManager::getInstance().loadRecipe(std::string(CT2A(strSelectedRecipe)))) { m_staticCurrRecipe->SetWindowText(strSelectedRecipe); m_staticCurrRecipe->SetBkColor(RGB(0, 110, 110)); } else { AfxMessageBox(_T("加载配方失败!")); } } void CRecipeListDlg::OnGridCellEditFinished(NMHDR* pNotifyStruct, LRESULT* pResult) { // 获取修改的行列信息 NM_GRIDVIEW* pItem = (NM_GRIDVIEW*)pNotifyStruct; int nRow = pItem->iRow; int nCol = pItem->iColumn; // 只处理“配方描述”列的修改 if (nCol == 2) { CString strRecipeName = m_grid.GetItemText(nRow, 1); CInputDialog inputDialog(_T("配方描述"), _T("请输入配方描述:")); if (inputDialog.DoModal() != IDOK) { *pResult = 0; return; } CString strText = inputDialog.GetInputText(); m_grid.SetItemText(nRow, nCol, strText); UpdateDataFile(strRecipeName, strText); m_grid.ExpandColumnsToFit(FALSE); // 自动调整列宽 m_grid.ExpandLastColumn(); // 最后一列填充网格 // 刷新网格控件 m_grid.Invalidate(); m_grid.UpdateWindow(); } *pResult = 0; }