LAPTOP-T815PCOQ\25526
2024-12-16 e2aba4b899f691b68a5d95f27981d25581142cb1
1. 创建配方和删除配方 2. 配方数据分模块,比如轴的数据就是一个模块
已添加2个文件
已修改9个文件
已删除2个文件
553 ■■■■ 文件已修改
SourceCode/Bond/BondEq/BondEq.vcxproj 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BondEq/BondEqDlg.cpp 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BondEq/FileManager/RecipeManager.cpp 96 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BondEq/FileManager/RecipeManager.h 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BondEq/Resource.h 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BondEq/ToolUnits.cpp 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BondEq/ToolUnits.h 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BondEq/View/AxisSettingsDlg.cpp 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BondEq/View/RecipeLiseDlg.cpp 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BondEq/View/RecipeLiseDlg.h 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BondEq/View/RecipeListDlg.cpp 300 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BondEq/View/RecipeListDlg.h 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BondEq/stdafx.h 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BondEq/BondEq.vcxproj
@@ -263,7 +263,7 @@
    <ClInclude Include="View\ChangePasswordDlg.h" />
    <ClInclude Include="View\IOMonitoringDlg.h" />
    <ClInclude Include="View\LoginDlg.h" />
    <ClInclude Include="View\RecipeLiseDlg.h" />
    <ClInclude Include="View\RecipeListDlg.h" />
    <ClInclude Include="View\SystemLogManagerDlg.h" />
    <ClInclude Include="View\UserManagerDlg.h" />
  </ItemGroup>
@@ -344,7 +344,7 @@
    <ClCompile Include="View\ChangePasswordDlg.cpp" />
    <ClCompile Include="View\IOMonitoringDlg.cpp" />
    <ClCompile Include="View\LoginDlg.cpp" />
    <ClCompile Include="View\RecipeLiseDlg.cpp" />
    <ClCompile Include="View\RecipeListDlg.cpp" />
    <ClCompile Include="View\SystemLogManagerDlg.cpp" />
    <ClCompile Include="View\UserManagerDlg.cpp" />
  </ItemGroup>
SourceCode/Bond/BondEq/BondEqDlg.cpp
@@ -17,7 +17,7 @@
#include "SystemLogManagerDlg.h"
// æµ‹è¯•
#include "RecipeLiseDlg.h"
#include "RecipeListDlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
@@ -253,7 +253,7 @@
    // è®¾ç½®é…æ–¹æ–‡ä»¶å¤¹è·¯å¾„
    RecipeManager& recipeManager = RecipeManager::getInstance();
    std::string strRecipePath =  CToolUnits::getCurrentExePath() + _T("\\Recipe");
    std::string strRecipePath =  CToolUnits::getRecipePath();
    CToolUnits::createDir(strRecipePath.c_str());
    recipeManager.setRecipeFolder(strRecipePath);
@@ -540,8 +540,7 @@
void CBondEqDlg::OnMenuFileSettings()
{
    CRecipeLiseDlg dlg;
    CRecipeListDlg dlg;
    dlg.DoModal();
    //CSettingsDlg dlg;
SourceCode/Bond/BondEq/FileManager/RecipeManager.cpp
@@ -12,33 +12,15 @@
// æž„造函数
RecipeManager::RecipeManager() : m_recipeFolder("Recipe") {}
// è®¾ç½®é…æ–¹æ–‡ä»¶å¤¹
void RecipeManager::setRecipeFolder(const std::string& folderPath) {
    m_recipeFolder = folderPath;
}
// åŠ è½½é…æ–¹ï¼ˆå¦‚æžœæ–‡ä»¶ä¸å­˜åœ¨ï¼ŒåŠ è½½é»˜è®¤æ•°æ®ï¼‰
bool RecipeManager::loadRecipe(const std::string& recipeName) {
    std::string filePath = m_recipeFolder + "/" + recipeName + ".xml";
    pugi::xml_document doc;
    if (!doc.load_file(filePath.c_str())) {
        std::cerr << "Recipe file not found: " << filePath << ". Loading default recipe." << std::endl;
        generateDefaultRecipe();
        return false; // æ–‡ä»¶ä¸å­˜åœ¨ï¼Œä½†åŠ è½½äº†é»˜è®¤æ•°æ®
    }
// åŠ è½½è½´ä¿¡æ¯
bool RecipeManager::loadAxes(pugi::xml_node axesNode) {
    m_axes.clear();
    auto recipe = doc.child("Recipe");
    for (auto axisNode : recipe.child("Axes").children("Axis")) {
    for (auto axisNode : axesNode.children("Axis")) {
        AxisInfo axisInfo;
        axisInfo.id = axisNode.attribute("id").as_int();
        axisInfo.number = axisNode.attribute("number").value();
        axisInfo.description = axisNode.attribute("description").value();
        axisInfo.startAddress = axisNode.attribute("start_address").value();
        //axisInfo.maxPositioningSpeed = axisNode.attribute("maxPositioningSpeed").as_double();
        //axisInfo.maxManualSpeed = axisNode.attribute("maxManualSpeed").as_double();
        // åŠ è½½ ValueRange å€¼
        axisInfo.jogDistance = ValueRange(
@@ -68,9 +50,9 @@
        );
        // åŠ è½½ PositionRange å€¼
        axisInfo.positioningPointCount = axisNode.child("Positions").attribute("positioningPointCount").as_int();
        axisInfo.positioningPointCount = axisNode.child("Positions").attribute("positioningPointCount").as_int();
        for (auto positionNode : axisNode.child("Positions").children("Position")) {
            bool isEnable = positionNode.attribute("isEnable").as_bool();
            bool isEnable = positionNode.attribute("isEnable").as_bool();
            std::string description = positionNode.attribute("description").value();
            ValueRange positionRange(
                positionNode.attribute("min").as_double(),
@@ -87,26 +69,8 @@
    return true;
}
// ä¿å­˜é…æ–¹
bool RecipeManager::saveRecipe(const std::string& recipeName) {
    // ç”Ÿæˆæ–‡ä»¶è·¯å¾„
    std::string filePath = m_recipeFolder + "/" + recipeName + ".xml";
    // åˆ›å»º XML æ–‡æ¡£å¯¹è±¡
    pugi::xml_document doc;
    // å¦‚果轴数据为空,生成默认配方
    if (m_axes.empty()) {
        generateDefaultRecipe();
    }
    // æ·»åŠ é…æ–¹æ ¹èŠ‚ç‚¹
    auto recipe = doc.append_child("Recipe");
    // æ·»åŠ è½´åˆ—è¡¨èŠ‚ç‚¹
    auto axesNode = recipe.append_child("Axes");
    // éåŽ†æ‰€æœ‰è½´æ•°æ®å¹¶å†™å…¥ XML
// ä¿å­˜è½´ä¿¡æ¯
void RecipeManager::saveAxes(pugi::xml_node& axesNode) {
    for (const auto& axisEntry : m_axes) {
        const AxisInfo& axisInfo = axisEntry.second;
@@ -115,8 +79,6 @@
        axisNode.append_attribute("number") = axisInfo.number.c_str();
        axisNode.append_attribute("description") = axisInfo.description.c_str();
        axisNode.append_attribute("start_address") = axisInfo.startAddress.c_str();
        //axisNode.append_attribute("maxPositioningSpeed") = axisInfo.maxPositioningSpeed;
        //axisNode.append_attribute("maxManualSpeed") = axisInfo.maxManualSpeed;
        // ä¿å­˜ ValueRange å€¼
        auto jog_distance = axisNode.append_child("jog_distance");
@@ -156,6 +118,50 @@
            positionNode.append_attribute("current") = position.range.currentValue;
        }
    }
}
// è®¾ç½®é…æ–¹æ–‡ä»¶å¤¹
void RecipeManager::setRecipeFolder(const std::string& folderPath) {
    m_recipeFolder = folderPath;
}
// åŠ è½½é…æ–¹ï¼ˆå¦‚æžœæ–‡ä»¶ä¸å­˜åœ¨ï¼ŒåŠ è½½é»˜è®¤æ•°æ®ï¼‰
bool RecipeManager::loadRecipe(const std::string& recipeName) {
    std::string filePath = m_recipeFolder + "/" + recipeName + ".xml";
    pugi::xml_document doc;
    if (!doc.load_file(filePath.c_str())) {
        std::cerr << "Recipe file not found: " << filePath << ". Loading default recipe." << std::endl;
        generateDefaultRecipe();
        return false; // æ–‡ä»¶ä¸å­˜åœ¨ï¼Œä½†åŠ è½½äº†é»˜è®¤æ•°æ®
    }
    auto recipeNode = doc.child("Recipe");
    auto axesNode = recipeNode.child("Axes");
    loadAxes(axesNode);  // åŠ è½½è½´ä¿¡æ¯
    return true;
}
// ä¿å­˜é…æ–¹
bool RecipeManager::saveRecipe(const std::string& recipeName) {
    // ç”Ÿæˆæ–‡ä»¶è·¯å¾„
    std::string filePath = m_recipeFolder + "/" + recipeName + ".xml";
    // åˆ›å»º XML æ–‡æ¡£å¯¹è±¡
    pugi::xml_document doc;
    // å¦‚果轴数据为空,生成默认配方
    if (m_axes.empty()) {
        generateDefaultRecipe();
    }
    // æ·»åŠ é…æ–¹æ ¹èŠ‚ç‚¹
    auto recipeNode = doc.append_child("Recipe");
    // æ·»åŠ è½´ä¿¡æ¯
    auto axesNode = recipeNode.append_child("Axes");
    saveAxes(axesNode);
    // ä¿å­˜ XML æ–‡ä»¶
    return doc.save_file(filePath.c_str());
SourceCode/Bond/BondEq/FileManager/RecipeManager.h
@@ -88,6 +88,10 @@
private:
    RecipeManager();
    // è½´åŠ è½½å’Œä¿å­˜å‡½æ•°
    bool loadAxes(pugi::xml_node axesNode);
    void saveAxes(pugi::xml_node& axesNode);
private:
    std::string m_recipeFolder;      // é…æ–¹æ–‡ä»¶å¤¹è·¯å¾„
    std::map<int, AxisInfo> m_axes;  // è½´ä¿¡æ¯ç¼“å­˜
SourceCode/Bond/BondEq/Resource.h
Binary files differ
SourceCode/Bond/BondEq/ToolUnits.cpp
@@ -247,3 +247,43 @@
    strText.Format(_T("%.03f"), value);
    pWnd->SetDlgItemText(nCtrlId, strText);
}
std::vector<CString> CToolUnits::GetFileNamesInDirectory(const CString& strFolderPath, const CString& strExtension)
{
    std::vector<CString> fileNames;
    // ç¡®ä¿ç›®å½•路径最后有反斜杠
    CString strSearchPath = strFolderPath;
    if (strSearchPath[strSearchPath.GetLength() - 1] != '\\') {
        strSearchPath += '\\';
    }
    CString finalExtension = strExtension;
    if (finalExtension.Find('.') == -1) {
        finalExtension = '.' + finalExtension;
    }
    strSearchPath += "*" + finalExtension;
    std::unique_ptr<CFileFind> finder = std::make_unique<CFileFind>();
    BOOL bWorking = finder->FindFile(strSearchPath);
    // éåŽ†æ–‡ä»¶å¤¹
    while (bWorking) {
        bWorking = finder->FindNextFile();
        if (!finder->IsDirectory()) {
            CString fileName = finder->GetFileName();
            int dotPos = fileName.ReverseFind('.');
            if (dotPos != -1) {
                fileName = fileName.Left(dotPos);
            }
            fileNames.push_back(fileName);
        }
    }
    return fileNames;
}
std::string CToolUnits::getRecipePath()
{
    return getCurrentExePath() + "\\Recipe";
}
SourceCode/Bond/BondEq/ToolUnits.h
@@ -25,5 +25,7 @@
    static BOOL getBit(const char c, int index);
    static void setBit(char* p, int index);
    static void setDlgItemDouble(CWnd* pWnd, int nCtrlId, double value);
    static std::vector<CString> GetFileNamesInDirectory(const CString& strFolderPath, const CString& strExtension);
    static std::string getRecipePath();
};
SourceCode/Bond/BondEq/View/AxisSettingsDlg.cpp
@@ -299,7 +299,6 @@
    RecipeManager& recipeManager = RecipeManager::getInstance();
    if (m_strRecipeName.IsEmpty() || !recipeManager.loadRecipe(std::string(CT2A(m_strRecipeName)))) {
        AfxMessageBox(_T("加载配方失败!"));
        recipeManager.saveRecipe(std::string(CT2A(m_strRecipeName)));
        return;
    }
SourceCode/Bond/BondEq/View/RecipeLiseDlg.cpp
ÎļþÒÑɾ³ý
SourceCode/Bond/BondEq/View/RecipeLiseDlg.h
ÎļþÒÑɾ³ý
SourceCode/Bond/BondEq/View/RecipeListDlg.cpp
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,300 @@
// RecipeLiseDlg.cpp: å®žçŽ°æ–‡ä»¶
//
#include "stdafx.h"
#include "BondEq.h"
#include "afxdialogex.h"
#include "RecipeListDlg.h"
#include "InputDialog.h"
#include "ToolUnits.h"
#include <fstream>
#include <sstream>
#include <map>
// CRecipeListDlg å¯¹è¯æ¡†
IMPLEMENT_DYNAMIC(CRecipeListDlg, CDialogEx)
CRecipeListDlg::CRecipeListDlg(CWnd* pParent /*=nullptr*/)
    : CDialogEx(IDD_DIALOG_RECIPE_LIST, pParent)
{
}
CRecipeListDlg::~CRecipeListDlg()
{
}
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, 50);
    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(TRUE);
    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 = 1; i < m_grid.GetRowCount(); i++) {
        m_grid.DeleteRow(i);
    }
    // 1. éåŽ†æ–‡ä»¶å¤¹ä¸‹æ‰€æœ‰XML文件
    std::string strRecipePath = CToolUnits::getRecipePath();
    std::vector<CString> vecFile = CToolUnits::GetFileNamesInDirectory(strRecipePath.c_str(), _T(".xml"));
    // 2. è¯»å– RecipeList.txt æ–‡ä»¶
    std::map<CString, std::pair<CString, CString>> 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<int>(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);                                // åˆ›å»ºæ—¶é—´
        m_grid.SetItemState(rowIdx, 0, GVIS_READONLY);
        m_grid.SetItemState(rowIdx, 1, GVIS_READONLY);
        m_grid.SetItemState(rowIdx, 3, GVIS_READONLY);
        ++rowIdx;
    }
    m_grid.ExpandColumnsToFit(FALSE);
    m_grid.ExpandLastColumn();
    m_grid.Invalidate();
    m_grid.UpdateWindow();
}
void CRecipeListDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
    DDX_Control(pDX, IDC_CUSTOM_RECIPE_LIST, m_grid);
}
BEGIN_MESSAGE_MAP(CRecipeListDlg, CDialogEx)
    ON_BN_CLICKED(IDC_BUTTON_CREATE_RECIPE, &CRecipeListDlg::OnBnClickedButtonCreateRecipe)
    ON_BN_CLICKED(IDC_BUTTON_DELETE_RECIPE, &CRecipeListDlg::OnBnClickedButtonDeleteRecipe)
END_MESSAGE_MAP()
// CRecipeListDlg æ¶ˆæ¯å¤„理程序
BOOL CRecipeListDlg::OnInitDialog()
{
    CDialogEx::OnInitDialog();
    // TODO:  åœ¨æ­¤æ·»åŠ é¢å¤–çš„åˆå§‹åŒ–
    InitRecipeLise();
    return TRUE;  // return TRUE unless you set the focus to a control
    // å¼‚常: OCX å±žæ€§é¡µåº”返回 FALSE
}
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<CString> 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();
}
SourceCode/Bond/BondEq/View/RecipeListDlg.h
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,34 @@
#pragma once
#include "afxdialogex.h"
#include "GridCtrl.h"
// CRecipeListDlg å¯¹è¯æ¡†
class CRecipeListDlg : public CDialogEx
{
    DECLARE_DYNAMIC(CRecipeListDlg)
public:
    CRecipeListDlg(CWnd* pParent = nullptr);   // æ ‡å‡†æž„造函数
    virtual ~CRecipeListDlg();
// å¯¹è¯æ¡†æ•°æ®
#ifdef AFX_DESIGN_TIME
    enum { IDD = IDD_DIALOG_RECIPE_LIST };
#endif
private:
    void InitRecipeLise();
    void FillRecipeLise();
private:
    CGridCtrl m_grid;
protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV æ”¯æŒ
    virtual BOOL OnInitDialog();
    afx_msg void OnBnClickedButtonCreateRecipe();
    afx_msg void OnBnClickedButtonDeleteRecipe();
    DECLARE_MESSAGE_MAP()
};
SourceCode/Bond/BondEq/stdafx.h
@@ -56,7 +56,7 @@
// æŽ§ä»¶æ ·å¼
static UINT g_nGridFixCellColor = RGB(144, 200, 246);
static UINT g_nGridFixFontColor = RGB(0, 0, 0);
static UINT g_nGridCellColor = RGB(255, 255, 255);
static UINT g_nGridCellColor = RGB(255, 255, 224);
static UINT g_nGridCellColor_NonSelect = RGB(150, 150, 150);
static UINT g_nGridCellReadyColor = RGB(255, 255, 0);
static UINT g_nGridCellOnColor = RGB(255, 69, 0);