LAPTOP-SNT8I5JK\Boounion
2024-12-12 016703bb359382dc1de4ac204da47b6f29c55c81
Merge branch 'liuyang' into clh

# Conflicts:
# SourceCode/Bond/BondEq/BondEq.rc
# SourceCode/Bond/BondEq/Resource.h
已添加4个文件
已修改9个文件
已删除2个文件
2286 ■■■■■ 文件已修改
SourceCode/Bond/BLControlsSDK/include/BLLabel.h 91 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BondEq/AxisSettingsDlg.cpp 1116 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BondEq/AxisSettingsDlg.h 130 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BondEq/BondEq.rc 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BondEq/BondEq.vcxproj 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BondEq/FileManager/RecipeManager.cpp 23 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BondEq/FileManager/RecipeManager.h 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BondEq/RegexEdit.cpp 143 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BondEq/RegexEdit.h 74 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BondEq/Resource.h 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BondEq/View/AxisDetailSettingsDlg.cpp 419 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BondEq/View/AxisDetailSettingsDlg.h 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BondEq/View/AxisSettingsDlg.cpp 200 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BondEq/View/AxisSettingsDlg.h 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BondEq/View/IOMonitoringDlg.cpp 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BLControlsSDK/include/BLLabel.h
@@ -24,50 +24,77 @@
    void SetClickCallback(std::function<void()> callback); // è®¾ç½®ç‚¹å‡»äº‹ä»¶çš„回调函数
    // å±žæ€§è®¾ç½®æŽ¥å£
    CBLLabel& SetBkColor(COLORREF crBkgnd);             // è®¾ç½®èƒŒæ™¯é¢œè‰²
    CBLLabel& SetTextColor(COLORREF crText);            // è®¾ç½®æ–‡æœ¬é¢œè‰²
    CBLLabel& SetText(const CString& strText);          // è®¾ç½®æ–‡æœ¬å†…容
    CBLLabel& SetFontBold(BOOL bBold);                  // è®¾ç½®å­—体加粗
    CBLLabel& SetFontName(const CString& strFont);      // è®¾ç½®å­—体名称
    CBLLabel& SetFontUnderline(BOOL bSet);              // è®¾ç½®ä¸‹åˆ’线
    CBLLabel& SetFontItalic(BOOL bSet);                 // è®¾ç½®æ–œä½“
    CBLLabel& SetFontSize(int nSize);                   // è®¾ç½®å­—体大小
    CBLLabel& SetAlignment(TextAlign alignment);        // è®¾ç½®æ–‡æœ¬å¯¹é½æ–¹å¼
    CBLLabel& SetDynamicFont(BOOL bDynamic);            // è®¾ç½®æ˜¯å¦åŠ¨æ€è°ƒæ•´å­—ä½“
    CBLLabel& FlashText(BOOL bActivate);                // é—ªçƒæ–‡æœ¬
    CBLLabel& FlashBackground(BOOL bActivate);          // é—ªçƒèƒŒæ™¯
    CBLLabel& SetLink(BOOL bLink);                      // è®¾ç½®æ˜¯å¦å¯ç”¨è¶…链接
    CBLLabel& SetLinkCursor(HCURSOR hCursor);           // è®¾ç½®è¶…链接光标
    CBLLabel& SetBkColor(COLORREF crBkgnd);                 // è®¾ç½®èƒŒæ™¯é¢œè‰²
    CBLLabel& SetTextColor(COLORREF crText);                // è®¾ç½®æ–‡æœ¬é¢œè‰²
    CBLLabel& SetText(const CString& strText);              // è®¾ç½®æ–‡æœ¬å†…容
    CBLLabel& SetFontBold(BOOL bBold);                      // è®¾ç½®å­—体加粗
    CBLLabel& SetFontName(const CString& strFont);          // è®¾ç½®å­—体名称
    CBLLabel& SetFontUnderline(BOOL bSet);                  // è®¾ç½®ä¸‹åˆ’线
    CBLLabel& SetFontItalic(BOOL bSet);                     // è®¾ç½®æ–œä½“
    CBLLabel& SetFontSize(int nSize);                       // è®¾ç½®å­—体大小
    CBLLabel& SetAlignment(TextAlign alignment);            // è®¾ç½®æ–‡æœ¬å¯¹é½æ–¹å¼
    CBLLabel& SetDynamicFont(BOOL bDynamic);                // è®¾ç½®æ˜¯å¦åŠ¨æ€è°ƒæ•´å­—ä½“
    CBLLabel& FlashText(BOOL bActivate);                    // é—ªçƒæ–‡æœ¬
    CBLLabel& FlashBackground(BOOL bActivate);              // é—ªçƒèƒŒæ™¯
    CBLLabel& SetLink(BOOL bLink);                          // è®¾ç½®æ˜¯å¦å¯ç”¨è¶…链接
    CBLLabel& SetLinkCursor(HCURSOR hCursor);               // è®¾ç½®è¶…链接光标
    CBLLabel& DisableBorder();                                // ç¦ç”¨è¾¹æ¡†
    CBLLabel& SetBorderColor(COLORREF crBorder);            // è®¾ç½®è¾¹æ¡†é¢œè‰²
    CBLLabel& SetBorderWidth(int nWidth);                   // è®¾ç½®è¾¹æ¡†å®½åº¦
    CBLLabel& SetBorderStyle(int nStyle);                   // è®¾ç½®è¾¹æ¡†æ ·å¼
    CBLLabel& SetDefaultCursor(HCURSOR hCursor);            // è®¾ç½®é»˜è®¤å…‰æ ‡
    CBLLabel& SetHandCursor(HCURSOR hCursor);                // è®¾ç½®æ‰‹åž‹å…‰æ ‡
    CBLLabel& SetRoundedCorners(BOOL bEnable, int nRadius); // è®¾ç½®åœ†è§’及半径
    CBLLabel& SetCornerRadius(int nTopLeft, int nTopRight, int nBottomRight, int nBottomLeft); // è®¾ç½®å„角圆角半径
protected:
    // å·¥å…·å‡½æ•°
    void ReconstructFont();       // é‡æ–°æž„造字体
    void UpdateFontSize();        // åŠ¨æ€è°ƒæ•´å­—ä½“å¤§å°
    virtual void OnPaint();       // è‡ªå®šä¹‰ç»˜åˆ¶æ–‡æœ¬
    void ReconstructFont();                                 // é‡æ–°æž„造字体
    void UpdateFontSize();                                  // åŠ¨æ€è°ƒæ•´å­—ä½“å¤§å°
    void CreateRoundedRegion(CRgn& rgn, const CRect& rect); // åˆ›å»ºåœ†è§’区域
    virtual void OnPaint();                                 // è‡ªå®šä¹‰ç»˜åˆ¶æ–‡æœ¬
    // å±žæ€§
    COLORREF m_crText;            // æ–‡æœ¬é¢œè‰²
    COLORREF m_crBkColor;         // èƒŒæ™¯é¢œè‰²
    HBRUSH   m_hBrush;            // èƒŒæ™¯ç”»åˆ·
    LOGFONT  m_lf;                // å­—体信息
    CFont    m_font;              // å­—体对象
    CString  m_strText;           // æ–‡æœ¬å†…容
    BOOL     m_bState;            // çŠ¶æ€ï¼Œç”¨äºŽé—ªçƒ
    BOOL     m_bTimer;            // å®šæ—¶å™¨çŠ¶æ€
    BOOL     m_bLink;             // æ˜¯å¦ä¸ºè¶…链接
    BOOL     m_bDynamicFont;      // æ˜¯å¦åŠ¨æ€è°ƒæ•´å­—ä½“å¤§å°
    COLORREF  m_crText;           // æ–‡æœ¬é¢œè‰²
    COLORREF  m_crBkColor;        // èƒŒæ™¯é¢œè‰²
    HBRUSH    m_hBrush;           // èƒŒæ™¯ç”»åˆ·
    LOGFONT   m_lf;               // å­—体信息
    CFont     m_font;             // å­—体对象
    CString   m_strText;          // æ–‡æœ¬å†…容
    BOOL      m_bState;           // çŠ¶æ€ï¼Œç”¨äºŽé—ªçƒ
    BOOL      m_bTimer;           // å®šæ—¶å™¨çŠ¶æ€
    BOOL      m_bLink;            // æ˜¯å¦ä¸ºè¶…链接
    BOOL      m_bDynamicFont;     // æ˜¯å¦åŠ¨æ€è°ƒæ•´å­—ä½“å¤§å°
    TextAlign m_alignment;        // æ–‡æœ¬å¯¹é½æ–¹å¼
    FlashType m_Type;             // é—ªçƒç±»åž‹
    HCURSOR  m_hCursor;           // è¶…链接光标
    HCURSOR   m_hCursor;          // è¶…链接光标
    // è¾¹æ¡†å±žæ€§
    COLORREF m_crBorderColor;     // è¾¹æ¡†é¢œè‰²
    int m_nBorderWidth;           // è¾¹æ¡†å®½åº¦
    int m_nBorderStyle;           // è¾¹æ¡†æ ·å¼ï¼ˆä½¿ç”¨ GDI æ ·å¼ï¼šPS_SOLID, PS_DASH ç­‰ï¼‰
    // åœ†è§’相关属性
    BOOL m_bRoundedCorners;       // æ˜¯å¦å¯ç”¨åœ†è§’
    int  m_nTopLeftRadius;        // å·¦ä¸Šè§’圆角半径
    int  m_nTopRightRadius;       // å³ä¸Šè§’圆角半径
    int  m_nBottomRightRadius;    // å³ä¸‹è§’圆角半径
    int  m_nBottomLeftRadius;     // å·¦ä¸‹è§’圆角半径
    // é¼ æ ‡äº‹ä»¶ç›¸å…³å±žæ€§
    BOOL    m_bMouseIn;           // é¼ æ ‡æ˜¯å¦åœ¨æŽ§ä»¶ä¸Š
    HCURSOR m_hHandCursor;        // æ‰‹åž‹å…‰æ ‡
    HCURSOR m_hDefaultCursor;     // é»˜è®¤å…‰æ ‡
    std::function<void()> m_clickCallback; // ç‚¹å‡»äº‹ä»¶çš„回调函数
protected:
    // MFC æ¶ˆæ¯æ˜ å°„
    virtual HBRUSH CtlColor(CDC* pDC, UINT nCtlColor);  // èƒŒæ™¯å’Œæ–‡æœ¬é¢œè‰²è®¾ç½®
    afx_msg void OnTimer(UINT_PTR nIDEvent);            // å®šæ—¶å™¨äº‹ä»¶
    afx_msg void OnLButtonDown(UINT nFlags, CPoint point); // é¼ æ ‡ç‚¹å‡»äº‹ä»¶
    virtual HBRUSH CtlColor(CDC* pDC, UINT nCtlColor);      // èƒŒæ™¯å’Œæ–‡æœ¬é¢œè‰²è®¾ç½®
    afx_msg void OnTimer(UINT_PTR nIDEvent);                // å®šæ—¶å™¨äº‹ä»¶
    afx_msg void OnLButtonDown(UINT nFlags, CPoint point);  // é¼ æ ‡ç‚¹å‡»äº‹ä»¶
    afx_msg void OnMouseMove(UINT nFlags, CPoint point);    // é¼ æ ‡ç§»åŠ¨äº‹ä»¶
    afx_msg void OnMouseLeave();                            // é¼ æ ‡ç¦»å¼€äº‹ä»¶
    afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message); // è®¾ç½®å…‰æ ‡äº‹ä»¶
    DECLARE_MESSAGE_MAP()
};
SourceCode/Bond/BondEq/AxisSettingsDlg.cpp
ÎļþÒÑɾ³ý
SourceCode/Bond/BondEq/AxisSettingsDlg.h
ÎļþÒÑɾ³ý
SourceCode/Bond/BondEq/BondEq.rc
Binary files differ
SourceCode/Bond/BondEq/BondEq.vcxproj
@@ -245,6 +245,7 @@
    <ClInclude Include="Model.h" />
    <ClInclude Include="CPageAlarm.h" />
    <ClInclude Include="Recipe.h" />
    <ClInclude Include="RegexEdit.h" />
    <ClInclude Include="Resource.h" />
    <ClInclude Include="SetPage1.h" />
    <ClInclude Include="SetPage2.h" />
@@ -256,6 +257,7 @@
    <ClInclude Include="ToolUnits.h" />
    <ClInclude Include="TopToolbar.h" />
    <ClInclude Include="VerticalLine.h" />
    <ClInclude Include="View\AxisDetailSettingsDlg.h" />
    <ClInclude Include="View\AxisSettingsDlg.h" />
    <ClInclude Include="View\ChangePasswordDlg.h" />
    <ClInclude Include="View\IOMonitoringDlg.h" />
@@ -318,6 +320,7 @@
    <ClCompile Include="Model.cpp" />
    <ClCompile Include="CPageAlarm.cpp" />
    <ClCompile Include="Recipe.cpp" />
    <ClCompile Include="RegexEdit.cpp" />
    <ClCompile Include="SetPage1.cpp" />
    <ClCompile Include="SetPage2.cpp" />
    <ClCompile Include="SettingsDlg.cpp" />
@@ -333,6 +336,7 @@
    <ClCompile Include="ToolUnits.cpp" />
    <ClCompile Include="TopToolbar.cpp" />
    <ClCompile Include="VerticalLine.cpp" />
    <ClCompile Include="View\AxisDetailSettingsDlg.cpp" />
    <ClCompile Include="View\AxisSettingsDlg.cpp" />
    <ClCompile Include="View\ChangePasswordDlg.cpp" />
    <ClCompile Include="View\IOMonitoringDlg.cpp" />
SourceCode/Bond/BondEq/FileManager/RecipeManager.cpp
@@ -37,6 +37,8 @@
        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(
@@ -66,7 +68,9 @@
        );
        // åŠ è½½ PositionRange å€¼
        axisInfo.positioningPointCount = axisNode.child("Positions").attribute("positioningPointCount").as_int();
        for (auto positionNode : axisNode.child("Positions").children("Position")) {
            bool isEnable = positionNode.attribute("isEnable").as_bool();
            std::string description = positionNode.attribute("description").value();
            ValueRange positionRange(
                positionNode.attribute("min").as_double(),
@@ -74,7 +78,7 @@
                positionNode.attribute("current").as_double()
            );
            axisInfo.positions.emplace_back(PositionRange(description, positionRange));
            axisInfo.positions.emplace_back(PositionRange(isEnable, description, positionRange));
        }
        m_axes[axisInfo.id] = axisInfo;
@@ -111,6 +115,8 @@
        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");
@@ -140,8 +146,10 @@
        // ä¿å­˜ PositionRange å€¼
        auto positionsNode = axisNode.append_child("Positions");
        positionsNode.append_attribute("positioningPointCount") = axisInfo.positioningPointCount;
        for (const auto& position : axisInfo.positions) {
            auto positionNode = positionsNode.append_child("Position");
            positionNode.append_attribute("isEnable") = position.isEnable;
            positionNode.append_attribute("description") = position.description.c_str();
            positionNode.append_attribute("min") = position.range.minValue;
            positionNode.append_attribute("max") = position.range.maxValue;
@@ -160,6 +168,9 @@
    for (int axisId = 1; axisId <= 12; ++axisId) {
        AxisInfo axisInfo;
        axisInfo.id = axisId;
        axisInfo.positioningPointCount = 25;
        //axisInfo.maxPositioningSpeed = 100.0;
        //axisInfo.maxManualSpeed = 100.0;
        axisInfo.number = "M100-M" + std::to_string(axisId);
        axisInfo.description = "Default_Axis" + std::to_string(axisId);
        axisInfo.startAddress = "ZR" + std::to_string(10000 + (axisId - 1) * 300);
@@ -172,10 +183,10 @@
        axisInfo.decelerationTime = ValueRange(1.0, 10.0, 1.0);
        // æ·»åŠ å®šä½ç‚¹å¹¶è®¾ç½®é»˜è®¤çš„æœ€å°å€¼å’Œæœ€å¤§å€¼
        for (int posId = 1; posId <= 25; ++posId) {
            double minPos = posId * 5.0;
            double maxPos = posId * 20.0;
            axisInfo.positions.emplace_back(PositionRange("Position " + std::to_string(posId), ValueRange(minPos, maxPos, posId * 10.0)));
        for (int posId = 0; posId < axisInfo.positioningPointCount; ++posId) {
            double minPos = (posId + 1) * 5.0;
            double maxPos = (posId + 1) * 20.0;
            axisInfo.positions.emplace_back(PositionRange(TRUE, "Position " + std::to_string(posId + 1), ValueRange(minPos, maxPos, (posId + 1) * 10.0)));
        }
        m_axes[axisId] = axisInfo;
@@ -195,7 +206,7 @@
    }
    // å¦‚果没有找到该轴,返回一个默认的无效 AxisInfo
    return AxisInfo{ -1, "", "", "", ValueRange(), ValueRange(), ValueRange(), ValueRange(), ValueRange(), {} };
    return AxisInfo{ -1, 0, /*0.0, 0.0,*/ "", "", "", ValueRange(), ValueRange(), ValueRange(), ValueRange(), ValueRange(), {} };
}
// æ›´æ–°è½´ä¿¡æ¯
SourceCode/Bond/BondEq/FileManager/RecipeManager.h
@@ -17,17 +17,21 @@
};
struct PositionRange {
    BOOL isEnable;            // æ˜¯å¦å¯ç”¨
    std::string description;  // å®šä½ç‚¹æè¿°
    ValueRange range;         // ä½ç½®çš„æœ€å°å€¼ã€æœ€å¤§å€¼å’Œå½“前值
    // æž„造函数初始化
    PositionRange(const std::string& desc = "", const ValueRange& r = ValueRange())
        : description(desc), range(r) {}
    PositionRange(BOOL b = TRUE, const std::string& desc = "", const ValueRange& r = ValueRange())
        :isEnable(b), description(desc), range(r) {}
};
// è½´ä¿¡æ¯ç»“构体
struct AxisInfo {
    int id;                                    // è½´ID
    int positioningPointCount;                 // å®šä½ç‚¹æ•°
    //double maxPositioningSpeed;                // å®šä½é€Ÿåº¦ä¸Šé™
    //double maxManualSpeed;                     // æ‰‹åŠ¨é€Ÿåº¦ä¸Šé™
    std::string number;                        // è½´ç¼–号
    std::string description;                   // è½´æè¿°
    std::string startAddress;                  // èµ·å§‹åœ°å€
SourceCode/Bond/BondEq/RegexEdit.cpp
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,143 @@
#include "stdafx.h"
#include "RegexEdit.h"
#include <stdexcept>
IMPLEMENT_DYNAMIC(CRegexEdit, CEdit)
CRegexEdit::CRegexEdit()
{
    m_enRegexType = RegexType::Alphanumeric;
    m_dMinValue = LDBL_MIN;
    m_dMaxValue = LDBL_MAX;
}
CRegexEdit::~CRegexEdit()
{
}
void CRegexEdit::SetRegexType(RegexType enType)
{
    m_enRegexType = enType;
}
void CRegexEdit::SetCustomRegex(const std::string& strCustomRegex)
{
    m_strCustomRegex = strCustomRegex;
}
void CRegexEdit::SetValueRange(long double dMinValue, long double dMaxValue)
{
    m_dMinValue = dMinValue;
    m_dMaxValue = dMaxValue;
}
void CRegexEdit::SetCustomComparator(std::function<bool(const std::string&)> comparator)
{
    m_customComparator = comparator;
}
void CRegexEdit::SetInvalidInputCallback(std::function<void()> callback)
{
    m_invalidInputCallback = callback;
}
bool CRegexEdit::FindMatch(const std::string& pattern, std::string& foundText)
{
    CString currentText;
    GetWindowText(currentText);
    std::string text(CT2A(currentText.GetString()));
    std::regex regexPattern(pattern);
    std::smatch match;
    if (std::regex_search(text, match, regexPattern)) {
        foundText = match.str();
        return true;
    }
    return false;
}
void CRegexEdit::ReplaceMatch(const std::string& pattern, const std::string& replacement)
{
    CString currentText;
    GetWindowText(currentText);
    std::string text(CT2A(currentText.GetString()));
    std::regex regexPattern(pattern);
    std::string result = std::regex_replace(text, regexPattern, replacement);
    SetWindowText(CString(result.c_str()));
}
std::regex CRegexEdit::GetCurrentRegex() const
{
    switch (m_enRegexType)
    {
    case RegexType::Alphanumeric:
        return std::regex("^[a-zA-Z0-9]*$");        // å­—母和数字
    case RegexType::Letters:
        return std::regex("^[a-zA-Z]*$");           // åªå…è®¸å­—母
    case RegexType::Digits:
        return std::regex("^\\d*$");                // åªå…è®¸æ•°å­—
    case RegexType::Decimal:
        return std::regex("^[-+]?\\d+(\\.\\d+)?$"); // å…è®¸å°æ•°å’Œæ•´æ•°
    case RegexType::Custom:
        return std::regex(m_strCustomRegex);        // è‡ªå®šä¹‰æ­£åˆ™
    default:
        return std::regex(".*");                    // é»˜è®¤å…è®¸è¾“入任何内容
    }
}
bool CRegexEdit::IsValueInRange(const std::string& strText)
{
    try {
        if (m_enRegexType == RegexType::Digits || m_enRegexType == RegexType::Decimal) {
            if (strText.find('.') == std::string::npos) {
                int nValue = std::stoi(strText);
                return nValue >= static_cast<int>(m_dMinValue) && nValue <= static_cast<int>(m_dMaxValue);
            }
            else {
                double dValue = std::stod(strText);
                return dValue >= m_dMinValue && dValue <= m_dMaxValue;
            }
        }
    }
    catch (const std::invalid_argument&) {
        return false;
    }
    return true;
}
BEGIN_MESSAGE_MAP(CRegexEdit, CEdit)
    ON_WM_CHAR()
END_MESSAGE_MAP()
void CRegexEdit::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
    // å¤„理删除键和退格键
    if (nChar == VK_BACK || nChar == VK_DELETE) {
        CEdit::OnChar(nChar, nRepCnt, nFlags);
        return;
    }
    CString strCurrent;
    GetWindowText(strCurrent);
    // èŽ·å–å…‰æ ‡å½“å‰ä½ç½®
    int nStartChar, nEndChar;
    GetSel(nStartChar, nEndChar); // èŽ·å–å½“å‰é€‰åŒºçš„èµ·å§‹å’Œç»“æŸä½ç½®
    std::string strText(CT2A(strCurrent.GetBuffer()));
    strText.insert(strText.begin() + nStartChar, (char)nChar);
    bool bValid = m_customComparator ? m_customComparator(strText) : IsValueInRange(strText);
    if (std::regex_match(strText, GetCurrentRegex()) && bValid) {
        CEdit::OnChar(nChar, nRepCnt, nFlags);
    }
    else {
        if (m_invalidInputCallback) {
            m_invalidInputCallback();
        }
    }
}
SourceCode/Bond/BondEq/RegexEdit.h
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,74 @@
#if !defined(AFX_REGEXEDIT_H__A4EABEC5_2E8C_11D1_B79F_00805F9ECE10__INCLUDED_)
#define AFX_REGEXEDIT_H__A4EABEC5_2E8C_11D1_B79F_00805F9ECE10__INCLUDED_
#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000
#include <afxwin.h>
#include <regex>
#include <functional>
#include <limits>
// æžšä¸¾ç±»åž‹ï¼šæ­£åˆ™è¡¨è¾¾å¼ç±»åž‹
enum class RegexType
{
    Alphanumeric,   // å…è®¸å­—母和数字
    Letters,        // åªå…è®¸å­—母
    Digits,         // åªå…è®¸æ•°å­—
    Decimal,        // å…è®¸å°æ•°å’Œæ•´æ•°
    Custom          // è‡ªå®šä¹‰æ­£åˆ™
};
class CRegexEdit : public CEdit
{
    DECLARE_DYNAMIC(CRegexEdit)
public:
    // æž„造与析构
    CRegexEdit();
    virtual ~CRegexEdit();
    // è®¾ç½®æ­£åˆ™ç±»åž‹
    void SetRegexType(RegexType enType);
    // è®¾ç½®è‡ªå®šä¹‰æ­£åˆ™è¡¨è¾¾å¼
    void SetCustomRegex(const std::string& strCustomRegex);
    // è®¾ç½®æ•°å€¼èŒƒå›´ï¼ˆæ•´æ•°æˆ–浮点)
    void SetValueRange(long double dMinValue, long double dMaxValue);
    // è®¾ç½®è‡ªå®šä¹‰æ¯”较函数
    void SetCustomComparator(std::function<bool(const std::string&)> comparator);
    // è®¾ç½®è¾“入不合法函数
    void SetInvalidInputCallback(std::function<void()> callback);
    // æŸ¥æ‰¾åŒ¹é…å†…容
    bool FindMatch(const std::string& pattern, std::string& foundText);
    // æ›¿æ¢åŒ¹é…å†…容
    void ReplaceMatch(const std::string& pattern, const std::string& replacement);
protected:
    // æ ¹æ®æžšä¸¾å€¼è¿”回对应的正则表达式
    std::regex GetCurrentRegex() const;
    // æ ¡éªŒè¾“入是否在指定范围内
    bool IsValueInRange(const std::string& strText);
protected:
    RegexType m_enRegexType;        // å½“前选中的正则类型
    std::string m_strCustomRegex;   // è‡ªå®šä¹‰æ­£åˆ™è¡¨è¾¾å¼
    long double m_dMinValue;        // æœ€å°å€¼
    long double m_dMaxValue;        // æœ€å¤§å€¼
    std::function<bool(const std::string&)> m_customComparator; // è‡ªå®šä¹‰æ¯”较函数
    std::function<void()> m_invalidInputCallback;               // ä¸åˆæ³•输入的回调函数
protected:
    void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags);
    DECLARE_MESSAGE_MAP()
};
#endif // !defined(AFX_REGEXEDIT_H__A4EABEC5_2E8C_11D1_B79F_00805F9ECE10__INCLUDED_)
SourceCode/Bond/BondEq/Resource.h
Binary files differ
SourceCode/Bond/BondEq/View/AxisDetailSettingsDlg.cpp
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,419 @@
// AxisDetailSettingsDlg.cpp: å®žçŽ°æ–‡ä»¶
//
#include "stdafx.h"
#include "BondEq.h"
#include "afxdialogex.h"
#include "AxisDetailSettingsDlg.h"
#include "NewCellTypes/GridCellCheck.h"
#include "NewCellTypes/GridCellNumeric.h"
// CAxisDetailSettingsDlg å¯¹è¯æ¡†
IMPLEMENT_DYNAMIC(CAxisDetailSettingsDlg, CDialogEx)
CAxisDetailSettingsDlg::CAxisDetailSettingsDlg(const CString& strRecipeName, int nAxisNO, CWnd* pParent /*=nullptr*/)
    : CDialogEx(IDD_DIALOG_AXIS_DETAIL_SETTINGS, pParent)
{
    m_strRecipeName = strRecipeName;
    m_nAxisNO = nAxisNO;
    m_pPLC = nullptr;
    m_nInitialWidth = 0;
    m_nInitialHeight = 0;
}
CAxisDetailSettingsDlg::~CAxisDetailSettingsDlg()
{
}
void CAxisDetailSettingsDlg::SetPLC(CPLC* pPLC)
{
    ASSERT(pPLC);
    m_pPLC = pPLC;
}
void CAxisDetailSettingsDlg::InitAnchorPontManager()
{
    if (m_grid.GetSafeHwnd() == NULL)
        return;
    int nRows = 1;
    int nCols = 6;
    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, 50);
    m_grid.SetItemText(nRowIdx, nColIdx++, _T("当前值"));
    m_grid.SetColumnWidth(nColIdx, 50);
    m_grid.SetItemText(nRowIdx, nColIdx++, _T("最大值"));
    m_grid.SetColumnWidth(nColIdx, 120);
    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();                // æœ€åŽä¸€åˆ—填充网格
    FillAnchorPontManager();
}
void CAxisDetailSettingsDlg::FillAnchorPontManager()
{
    RecipeManager& g_recipeManager = RecipeManager::getInstance();
    auto axisDetails = g_recipeManager.getAxis(m_nAxisNO);
    int nRowIndex = 1;
    int nPositionsSize = (int)axisDetails.positions.size();
    // æ¸…除数据行,保留表头
    for (int i = 1; i < m_grid.GetRowCount(); i++) {
        m_grid.DeleteRow(i);
    }
    // è®¾ç½®è¡¨æ ¼è¡Œæ•°
    m_grid.SetRowCount(axisDetails.positioningPointCount + 1);
    auto SetCellText = [this](int nRow, int nCol, const CString& strText, UINT nState = GVIS_READONLY) {
        m_grid.SetItemText(nRow, nCol, strText);
        m_grid.SetItemState(nRow, nCol, nState);
    };
    auto FormatFloatToString = [](double dValue) -> CString {
        CString strText;
        strText.Format(_T("%.3f"), dValue);
        return strText;
    };
    for (int nIndex = 0; nIndex < axisDetails.positioningPointCount; nIndex++) {
        m_grid.SetItemState(nIndex, 0, GVIS_READONLY); // åºå·åˆ—设置只读
        SetCellText(nRowIndex, 0, CString(std::to_string(nRowIndex).c_str()));
        if (nIndex >= nPositionsSize) {
            // æ·»åŠ æ–°è¡Œçš„é»˜è®¤å€¼
            if (m_grid.SetCellType(nRowIndex, 1, RUNTIME_CLASS(CGridCellCheck))) {
                auto* pCell = static_cast<CGridCellCheck*>(m_grid.GetCell(nRowIndex, 1));
                pCell->SetCheck(TRUE);
            }
            SetCellText(nRowIndex, 2, FormatFloatToString(0.0), GVIS_MODIFIED);
            SetCellText(nRowIndex, 3, FormatFloatToString(1.0), GVIS_MODIFIED);
            SetCellText(nRowIndex, 4, FormatFloatToString(10.0), GVIS_MODIFIED);
            SetCellText(nRowIndex, 5, CString(_T("Position ")) + CString(std::to_string(nIndex + 1).c_str()), GVIS_MODIFIED);
        }
        else {
            const auto& enPosition = axisDetails.positions[nIndex];
            if (m_grid.SetCellType(nRowIndex, 1, RUNTIME_CLASS(CGridCellCheck))) {
                auto* pCell = static_cast<CGridCellCheck*>(m_grid.GetCell(nRowIndex, 1));
                pCell->SetCheck(enPosition.isEnable);
            }
            UINT nCellState = enPosition.isEnable ? GVIS_MODIFIED : GVIS_READONLY;
            SetCellText(nRowIndex, 2, FormatFloatToString(enPosition.range.minValue), nCellState);
            SetCellText(nRowIndex, 3, FormatFloatToString(enPosition.range.currentValue), nCellState);
            SetCellText(nRowIndex, 4, FormatFloatToString(enPosition.range.maxValue), nCellState);
            SetCellText(nRowIndex, 5, CString(enPosition.description.c_str()), nCellState);
        }
        nRowIndex++;
    }
    m_grid.ExpandColumnsToFit(FALSE);
    m_grid.ExpandLastColumn();
    m_grid.Invalidate();
    m_grid.UpdateWindow();
}
void CAxisDetailSettingsDlg::UpdateAxisDetailSettings()
{
    // èŽ·å–è½´æ•°æ®
    RecipeManager& recipeManager = RecipeManager::getInstance();
    auto axisDetails = recipeManager.getAxis(m_nAxisNO);
    auto formatDouble = [](double value) -> CString {
        CString str;
        str.Format(_T("%.3f"), value);
        return str;
    };
    auto formatInt = [](int value) -> CString {
        CString str;
        str.Format(_T("%d"), value);
        return str;
    };
    m_staticAxisNO.SetWindowText(CString(axisDetails.number.c_str()));                                // è½´ç¼–号
    m_staticAxisDescription.SetWindowText(CString(axisDetails.description.c_str()));                // è½´æè¿°
    m_staticStartAddress.SetWindowText(CString(axisDetails.startAddress.c_str()));                    // èµ·å§‹åœ°å€
    //GetDlgItem(IDC_EDIT_AXIS_POSITIONING_SPEED_LIMIT)->SetWindowText(formatDouble(axisDetails.maxPositioningSpeed));    // å®šä½é€Ÿåº¦ä¸Šé™
    //GetDlgItem(IDC_EDIT_AXIS_JOG_SPEED_LIMIT)->SetWindowText(formatDouble(axisDetails.maxManualSpeed));                    // æ‰‹åŠ¨é€Ÿåº¦ä¸Šé™
    GetDlgItem(IDC_EDIT_AXIS_POSITIONING_POINTS)->SetWindowText(formatInt(axisDetails.positioningPointCount));            // å®šä½ç‚¹æ•°
    // å¾®åŠ¨é‡
    GetDlgItem(IDC_EDIT_AXIS_MODITFY_MICROMENTUM_MIN)->SetWindowText(formatDouble(axisDetails.jogDistance.minValue));
    GetDlgItem(IDC_EDIT_AXIS_MODITFY_MICROMENTUM)->SetWindowText(formatDouble(axisDetails.jogDistance.currentValue));
    GetDlgItem(IDC_EDIT_AXIS_MODITFY_MICROMENTUM_MAX)->SetWindowText(formatDouble(axisDetails.jogDistance.maxValue));
    // æ‰‹åŠ¨é€Ÿåº¦
    GetDlgItem(IDC_EDIT_AXIS_MODITFY_POS_MIN)->SetWindowText(formatDouble(axisDetails.manualSpeed.minValue));
    GetDlgItem(IDC_EDIT_AXIS_MODITFY_POS)->SetWindowText(formatDouble(axisDetails.manualSpeed.currentValue));
    GetDlgItem(IDC_EDIT_AXIS_MODITFY_POS_MAX)->SetWindowText(formatDouble(axisDetails.manualSpeed.maxValue));
    // è‡ªåŠ¨é€Ÿåº¦
    GetDlgItem(IDC_EDIT_AXIS_MODITFY_AUTO_SPEED_MIN)->SetWindowText(formatDouble(axisDetails.autoSpeed.minValue));
    GetDlgItem(IDC_EDIT_AXIS_MODITFY_AUTO_SPEED)->SetWindowText(formatDouble(axisDetails.autoSpeed.currentValue));
    GetDlgItem(IDC_EDIT_AXIS_MODITFY_AUTO_SPEED_MAX)->SetWindowText(formatDouble(axisDetails.autoSpeed.maxValue));
    // åŠ é€Ÿæ—¶é—´
    GetDlgItem(IDC_EDIT_AXIS_MODITFY_ACCE_TIME_MIN)->SetWindowText(formatDouble(axisDetails.accelerationTime.minValue));
    GetDlgItem(IDC_EDIT_AXIS_MODITFY_ACCE_TIME)->SetWindowText(formatDouble(axisDetails.accelerationTime.currentValue));
    GetDlgItem(IDC_EDIT_AXIS_MODITFY_ACCE_TIME_MAX)->SetWindowText(formatDouble(axisDetails.accelerationTime.maxValue));
    // å‡é€Ÿæ—¶é—´
    GetDlgItem(IDC_EDIT_AXIS_MODITFY_DECE_TIME_MIN)->SetWindowText(formatDouble(axisDetails.decelerationTime.minValue));
    GetDlgItem(IDC_EDIT_AXIS_MODITFY_DECE_TIME)->SetWindowText(formatDouble(axisDetails.decelerationTime.currentValue));
    GetDlgItem(IDC_EDIT_AXIS_MODITFY_DECE_TIME_MAX)->SetWindowText(formatDouble(axisDetails.decelerationTime.maxValue));
}
void CAxisDetailSettingsDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
    DDX_Control(pDX, IDC_STATIC_AXIS_NUMBER, m_staticAxisNO);
    DDX_Control(pDX, IDC_STATIC_AXIS_DESCRIP, m_staticAxisDescription);
    DDX_Control(pDX, IDC_STATIC_START_ADDRESS, m_staticStartAddress);
    DDX_Control(pDX, IDC_CUSTOM_AXIS_ANCHOR_POINT, m_grid);
}
BEGIN_MESSAGE_MAP(CAxisDetailSettingsDlg, CDialogEx)
    ON_NOTIFY(NM_CLICK, IDC_CUSTOM_AXIS_ANCHOR_POINT, &CAxisDetailSettingsDlg::OnGridItemChanged)
    ON_BN_CLICKED(IDC_BUTTON_AXIS_DETAIL_SETTINGS_SAVE, &CAxisDetailSettingsDlg::OnBnClickedButtonAxisDetailSettingsSave)
    ON_BN_CLICKED(IDC_BUTTON_SET_AXIS_POSITIONING_POINTS, &CAxisDetailSettingsDlg::OnBnClickedButtonSetAxisPositioningPoints)
END_MESSAGE_MAP()
// CAxisDetailSettingsDlg æ¶ˆæ¯å¤„理程序
BOOL CAxisDetailSettingsDlg::OnInitDialog()
{
    CDialogEx::OnInitDialog();
    // TODO:  åœ¨æ­¤æ·»åŠ é¢å¤–çš„åˆå§‹åŒ–
    CString strTitle;
    strTitle.Format(_T("Axis细部设定(配方: %s)"), m_strRecipeName);
    SetWindowText(strTitle);
    // èŽ·å–è½´æ•°æ®
    RecipeManager& recipeManager = RecipeManager::getInstance();
    auto axisDetails = recipeManager.getAxis(m_nAxisNO);
    if (axisDetails.id == -1) {
        CString strMsg;
        strMsg.Format(_T("è½´ [%d] ä¸å­˜åœ¨ï¼"), m_nAxisNO);
        AfxMessageBox(strMsg);
        return FALSE;
    }
    UpdateAxisDetailSettings();
    InitAnchorPontManager();
    return TRUE;  // return TRUE unless you set the focus to a control
    // å¼‚常: OCX å±žæ€§é¡µåº”返回 FALSE
}
void CAxisDetailSettingsDlg::OnGridItemChanged(NMHDR* pNotifyStruct, LRESULT* pResult)
{
    NM_GRIDVIEW* pItem = (NM_GRIDVIEW*)pNotifyStruct;
    int nRow = pItem->iRow;
    int nCol = pItem->iColumn;
    // å¤„理复选框状态变化
    if (nCol == 1) {
        // èŽ·å–å¤é€‰æ¡†çš„å½“å‰çŠ¶æ€
        CGridCellCheck* pCell = static_cast<CGridCellCheck*>(m_grid.GetCell(nRow, nCol));
        BOOL bChecked = pCell->GetCheck();
        // å¤„理复选框状态变化
        m_grid.SetItemState(nRow, 2, bChecked ? GVIS_MODIFIED : GVIS_READONLY);
        m_grid.SetItemState(nRow, 3, bChecked ? GVIS_MODIFIED : GVIS_READONLY);
        m_grid.SetItemState(nRow, 4, bChecked ? GVIS_MODIFIED : GVIS_READONLY);
        m_grid.SetItemState(nRow, 5, bChecked ? GVIS_MODIFIED : GVIS_READONLY);
    }
    *pResult = 0;
}
void CAxisDetailSettingsDlg::OnBnClickedButtonAxisDetailSettingsSave()
{
    // TODO: åœ¨æ­¤æ·»åŠ æŽ§ä»¶é€šçŸ¥å¤„ç†ç¨‹åºä»£ç 
    // èŽ·å–è½´æ•°æ®
    RecipeManager& recipeManager = RecipeManager::getInstance();
    auto& axisDetails = recipeManager.getAxis(m_nAxisNO);
    // ä»Žç•Œé¢æŽ§ä»¶èŽ·å–ç”¨æˆ·è¾“å…¥çš„æ•°æ®å¹¶æ›´æ–°åˆ° axisDetails
    // è½´ç¼–号、描述和起始地址
    CString strAxisNo, strAxisDesc, strStartAddr;
    m_staticAxisNO.GetWindowText(strAxisNo);
    m_staticAxisDescription.GetWindowText(strAxisDesc);
    m_staticStartAddress.GetWindowText(strStartAddr);
    axisDetails.number = std::string(CT2A(strAxisNo));
    axisDetails.description = std::string(CT2A(strAxisDesc));
    axisDetails.startAddress = std::string(CT2A(strStartAddr));
    // å®šä½é€Ÿåº¦ä¸Šé™
    //CString strPosSpeedLimit;
    //GetDlgItem(IDC_EDIT_AXIS_POSITIONING_SPEED_LIMIT)->GetWindowText(strPosSpeedLimit);
    //axisDetails.maxPositioningSpeed = _ttof(strPosSpeedLimit);  // è½¬æ¢ä¸º double ç±»åž‹
    // æ‰‹åŠ¨é€Ÿåº¦ä¸Šé™
    //CString strJogSpeedLimit;
    //GetDlgItem(IDC_EDIT_AXIS_JOG_SPEED_LIMIT)->GetWindowText(strJogSpeedLimit);
    //axisDetails.maxManualSpeed = _ttof(strJogSpeedLimit);
    // å®šä½ç‚¹æ•°
    CString strPosCount;
    GetDlgItem(IDC_EDIT_AXIS_POSITIONING_POINTS)->GetWindowText(strPosCount);
    axisDetails.positioningPointCount = _ttoi(strPosCount);   // è½¬æ¢ä¸º int ç±»åž‹
    // å¾®åŠ¨é‡
    CString strJogDistanceMin, strJogDistanceCur, strJogDistanceMax;
    GetDlgItem(IDC_EDIT_AXIS_MODITFY_MICROMENTUM_MIN)->GetWindowText(strJogDistanceMin);
    GetDlgItem(IDC_EDIT_AXIS_MODITFY_MICROMENTUM)->GetWindowText(strJogDistanceCur);
    GetDlgItem(IDC_EDIT_AXIS_MODITFY_MICROMENTUM_MAX)->GetWindowText(strJogDistanceMax);
    axisDetails.jogDistance.minValue = _ttof(strJogDistanceMin);
    axisDetails.jogDistance.currentValue = _ttof(strJogDistanceCur);
    axisDetails.jogDistance.maxValue = _ttof(strJogDistanceMax);
    // æ‰‹åŠ¨é€Ÿåº¦
    CString strManualSpeedMin, strManualSpeedCur, strManualSpeedMax;
    GetDlgItem(IDC_EDIT_AXIS_MODITFY_POS_MIN)->GetWindowText(strManualSpeedMin);
    GetDlgItem(IDC_EDIT_AXIS_MODITFY_POS)->GetWindowText(strManualSpeedCur);
    GetDlgItem(IDC_EDIT_AXIS_MODITFY_POS_MAX)->GetWindowText(strManualSpeedMax);
    axisDetails.manualSpeed.minValue = _ttof(strManualSpeedMin);
    axisDetails.manualSpeed.currentValue = _ttof(strManualSpeedCur);
    axisDetails.manualSpeed.maxValue = _ttof(strManualSpeedMax);
    // è‡ªåŠ¨é€Ÿåº¦
    CString strAutoSpeedMin, strAutoSpeedCur, strAutoSpeedMax;
    GetDlgItem(IDC_EDIT_AXIS_MODITFY_AUTO_SPEED_MIN)->GetWindowText(strAutoSpeedMin);
    GetDlgItem(IDC_EDIT_AXIS_MODITFY_AUTO_SPEED)->GetWindowText(strAutoSpeedCur);
    GetDlgItem(IDC_EDIT_AXIS_MODITFY_AUTO_SPEED_MAX)->GetWindowText(strAutoSpeedMax);
    axisDetails.autoSpeed.minValue = _ttof(strAutoSpeedMin);
    axisDetails.autoSpeed.currentValue = _ttof(strAutoSpeedCur);
    axisDetails.autoSpeed.maxValue = _ttof(strAutoSpeedMax);
    // åŠ é€Ÿæ—¶é—´
    CString strAcceTimeMin, strAcceTimeCur, strAcceTimeMax;
    GetDlgItem(IDC_EDIT_AXIS_MODITFY_ACCE_TIME_MIN)->GetWindowText(strAcceTimeMin);
    GetDlgItem(IDC_EDIT_AXIS_MODITFY_ACCE_TIME)->GetWindowText(strAcceTimeCur);
    GetDlgItem(IDC_EDIT_AXIS_MODITFY_ACCE_TIME_MAX)->GetWindowText(strAcceTimeMax);
    axisDetails.accelerationTime.minValue = _ttof(strAcceTimeMin);
    axisDetails.accelerationTime.currentValue = _ttof(strAcceTimeCur);
    axisDetails.accelerationTime.maxValue = _ttof(strAcceTimeMax);
    // å‡é€Ÿæ—¶é—´
    CString strDeceTimeMin, strDeceTimeCur, strDeceTimeMax;
    GetDlgItem(IDC_EDIT_AXIS_MODITFY_DECE_TIME_MIN)->GetWindowText(strDeceTimeMin);
    GetDlgItem(IDC_EDIT_AXIS_MODITFY_DECE_TIME)->GetWindowText(strDeceTimeCur);
    GetDlgItem(IDC_EDIT_AXIS_MODITFY_DECE_TIME_MAX)->GetWindowText(strDeceTimeMax);
    axisDetails.decelerationTime.minValue = _ttof(strDeceTimeMin);
    axisDetails.decelerationTime.currentValue = _ttof(strDeceTimeCur);
    axisDetails.decelerationTime.maxValue = _ttof(strDeceTimeMax);
    // å¦‚æžœ positioningPointCount å’Œ positions.size() ä¸åŒï¼Œåˆ™è°ƒæ•´å¤§å°
    if (axisDetails.positioningPointCount != (int)axisDetails.positions.size()) {
        axisDetails.positions.resize(axisDetails.positioningPointCount);
    }
    // æ›´æ–°è¡¨æ ¼ä¸­çš„定位点数据
    for (int i = 0; i < axisDetails.positioningPointCount; i++) {
        auto& enPosition = axisDetails.positions[i];
        // ä½¿èƒ½çŠ¶æ€
        BOOL bIsChecked = ((CGridCellCheck*)m_grid.GetCell(i + 1, 1))->GetCheck();
        enPosition.isEnable = bIsChecked;
        // æœ€å°å€¼ã€å½“前值和最大值
        CString strMin, strCur, strMax;
        strMin = m_grid.GetItemText(i + 1, 2);
        strCur = m_grid.GetItemText(i + 1, 3);
        strMax = m_grid.GetItemText(i + 1, 4);
        enPosition.range.minValue = _ttof(strMin);
        enPosition.range.currentValue = _ttof(strCur);
        enPosition.range.maxValue = _ttof(strMax);
        // æè¿°
        CString strDesc;
        strDesc = m_grid.GetItemText(i + 1, 5);
        enPosition.description = std::string(CT2A(strDesc));
    }
    // æ›´æ–° RecipeManager ä¸­çš„轴数据
    recipeManager.updateAxis(axisDetails);
    // ä¿å­˜è½´æ•°æ®åˆ°æ–‡ä»¶
    CString cstrMessage;
    if (RecipeManager::getInstance().saveRecipe(std::string(CT2A(m_strRecipeName)))) {
        cstrMessage.Format(_T("保存轴 [%d] ç»†éƒ¨å‚数成功!"), m_nAxisNO);
        SystemLogManager::getInstance().log(SystemLogManager::LogType::Operation, std::string(CT2A(cstrMessage)));
    }
    else {
        cstrMessage.Format(_T("保存轴 [%d] ç»†éƒ¨å‚数失败!"), m_nAxisNO);
        SystemLogManager::getInstance().log(SystemLogManager::LogType::Error, std::string(CT2A(cstrMessage)));
    }
    AfxMessageBox(cstrMessage);
}
void CAxisDetailSettingsDlg::OnBnClickedButtonSetAxisPositioningPoints()
{
    // TODO: åœ¨æ­¤æ·»åŠ æŽ§ä»¶é€šçŸ¥å¤„ç†ç¨‹åºä»£ç 
    CString strPosCount;
    GetDlgItem(IDC_EDIT_AXIS_POSITIONING_POINTS)->GetWindowText(strPosCount);
    if (strPosCount.IsEmpty()) {
        AfxMessageBox(_T("请输入定位点数!"));
        return;
    }
    RecipeManager& recipeManager = RecipeManager::getInstance();
    AxisInfo axisDetails = recipeManager.getAxis(m_nAxisNO);
    axisDetails.positioningPointCount = _ttoi(strPosCount);
    // æ›´æ–° RecipeManager ä¸­çš„轴数据
    recipeManager.updateAxis(axisDetails);
    FillAnchorPontManager();
}
SourceCode/Bond/BondEq/View/AxisDetailSettingsDlg.h
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,50 @@
#pragma once
#include "afxdialogex.h"
#include "GridCtrl.h"
// CAxisDetailSettingsDlg å¯¹è¯æ¡†
class CAxisDetailSettingsDlg : public CDialogEx
{
    DECLARE_DYNAMIC(CAxisDetailSettingsDlg)
public:
    CAxisDetailSettingsDlg(const CString& strRecipeName, int nAxisNO, CWnd* pParent = nullptr);   // æ ‡å‡†æž„造函数
    virtual ~CAxisDetailSettingsDlg();
public:
    void SetPLC(CPLC* pPLC);
// å¯¹è¯æ¡†æ•°æ®
#ifdef AFX_DESIGN_TIME
    enum { IDD = IDD_DIALOG_AXIS_DETAIL_SETTINGS };
#endif
private:
    void InitAnchorPontManager();
    void FillAnchorPontManager();
    void UpdateAxisDetailSettings();
private:
    CPLC* m_pPLC;
    int m_nInitialWidth;
    int m_nInitialHeight;
    // æ•°æ®
    int m_nAxisNO;
    CString m_strRecipeName;
    // æŽ§ä»¶
    CStatic m_staticAxisNO, m_staticAxisDescription, m_staticStartAddress;
    CGridCtrl m_grid;
protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV æ”¯æŒ
    virtual BOOL OnInitDialog();
    afx_msg void OnGridItemChanged(NMHDR* pNotifyStruct, LRESULT* pResult);
    afx_msg void OnBnClickedButtonAxisDetailSettingsSave();
    afx_msg void OnBnClickedButtonSetAxisPositioningPoints();
    DECLARE_MESSAGE_MAP()
};
SourceCode/Bond/BondEq/View/AxisSettingsDlg.cpp
@@ -5,6 +5,7 @@
#include "BondEq.h"
#include "afxdialogex.h"
#include "AxisSettingsDlg.h"
#include "AxisDetailSettingsDlg.h"
#include "ToolUnits.h"
#include <cctype>
#include <algorithm>
@@ -43,8 +44,13 @@
    m_bReady = FALSE;
    m_bBusy = FALSE;
    m_bErr = FALSE;
    for (int i = 0; i < BTN_MAX; i++) {
        m_pBlBtns[i] = new CBlButton();
    }
    for (int i = 0; i < EDIT_MAX; i++) {
        m_pRegexEdit[i] = new CRegexEdit();
    }
    for (int i = 0; i < LABEL_MAX; i++) {
@@ -67,6 +73,10 @@
    for (int i = 0; i < BTN_MAX; i++) {
        delete m_pBlBtns[i];
    }
    for (int i = 0; i < EDIT_MAX; i++) {
        delete m_pRegexEdit[i];
    }
    for (int i = 0; i < LABEL_MAX; i++) {
@@ -92,11 +102,6 @@
    DDX_Control(pDX, IDC_STATIC_AXIS_NUMBER, m_staticAxisNO);
    DDX_Control(pDX, IDC_STATIC_AXIS_DESCRIP, m_staticAxisDescription);
    DDX_Control(pDX, IDC_STATIC_START_ADDRESS, m_staticStartAddress);
    DDX_Control(pDX, IDC_EDIT_AXIS_MODITFY_POS, m_editManualSpeed);
    DDX_Control(pDX, IDC_EDIT_AXIS_MODITFY_AUTO_SPEED, m_editAutoSpeed);
    DDX_Control(pDX, IDC_EDIT_AXIS_MODITFY_ACCE_TIME, m_editAccelerationTime);
    DDX_Control(pDX, IDC_EDIT_AXIS_MODITFY_DECE_TIME, m_editDecelerationTime);
    DDX_Control(pDX, IDC_EDIT_AXIS_MODITFY_MICROMENTUM, m_editJogDistance);
}
UINT CAxisSettingsDlg::FindIDByName(const CString& strControlID)
@@ -237,6 +242,24 @@
    SetLabelColorBasedOnState(*m_pBlLabels[LABEL_ERR], m_bErr, COLOR_RED, COLOR_GREEN_OFF);
}
void CAxisSettingsDlg::UpdateRegexEdit(CRegexEdit* pRegexEdit, const ValueRange& range, const CString& title)
{
    auto formatDouble = [](double value) -> CString {
        CString str;
        str.Format(_T("%.3f"), value);
        return str;
    };
    pRegexEdit->SetWindowText(formatDouble(range.currentValue));
    pRegexEdit->SetRegexType(RegexType::Decimal);
    pRegexEdit->SetValueRange(range.minValue, range.maxValue);
    pRegexEdit->SetInvalidInputCallback([title, range]() {
        CString strError;
        strError.Format(_T("%s的值必须在 %.3f å’Œ %.3f ä¹‹é—´ï¼"), title, range.minValue, range.maxValue);
        AfxMessageBox(strError);
    });
}
void CAxisSettingsDlg::updatePageButtonStates()
{
    for (int i = 0; i < AXIS_PAGE_SIZE; ++i) {
@@ -276,6 +299,7 @@
    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;
    }
@@ -311,14 +335,15 @@
    };
    // æ›´æ–°æŽ§ä»¶æ˜¾ç¤º
    m_staticAxisNO.SetWindowText(CString(axisDetails.number.c_str()));                                // è½´ç¼–号
    m_staticAxisDescription.SetWindowText(CString(axisDetails.description.c_str()));                // è½´æè¿°
    m_staticStartAddress.SetWindowText(CString(axisDetails.startAddress.c_str()));                    // èµ·å§‹åœ°å€
    m_editJogDistance.SetWindowText(formatDouble(axisDetails.jogDistance.currentValue));            // å¾®åŠ¨é‡
    m_editManualSpeed.SetWindowText(formatDouble(axisDetails.manualSpeed.currentValue));            // æ‰‹åŠ¨é€Ÿåº¦
    m_editAutoSpeed.SetWindowText(formatDouble(axisDetails.autoSpeed.currentValue));                // è‡ªåŠ¨é€Ÿåº¦
    m_editAccelerationTime.SetWindowText(formatDouble(axisDetails.accelerationTime.currentValue));    // åŠ é€Ÿæ—¶é—´
    m_editDecelerationTime.SetWindowText(formatDouble(axisDetails.decelerationTime.currentValue));    // å‡é€Ÿæ—¶é—´
    m_staticAxisNO.SetWindowText(CString(axisDetails.number.c_str()));                    // è½´ç¼–号
    m_staticAxisDescription.SetWindowText(CString(axisDetails.description.c_str()));    // è½´æè¿°
    m_staticStartAddress.SetWindowText(CString(axisDetails.startAddress.c_str()));        // èµ·å§‹åœ°å€
    UpdateRegexEdit(m_pRegexEdit[EDIT_MICROMENTUM], axisDetails.jogDistance, _T("微动量"));
    UpdateRegexEdit(m_pRegexEdit[EDIT_MANUAL_SPEED], axisDetails.manualSpeed, _T("手动速度"));
    UpdateRegexEdit(m_pRegexEdit[EDIT_AUTO_SPEED], axisDetails.autoSpeed, _T("自动速度"));
    UpdateRegexEdit(m_pRegexEdit[EDIT_ACCE_TIME], axisDetails.accelerationTime, _T("加速时间"));
    UpdateRegexEdit(m_pRegexEdit[EDIT_DECE_TIME], axisDetails.decelerationTime, _T("减速时间"));
}
void CAxisSettingsDlg::refreshPositionDetails(int nAxisId, int pageNumber)
@@ -352,12 +377,28 @@
            // æ˜¾ç¤ºå®šä½ç‚¹çš„当前位置
            CString value;
            value.Format(_T("%.3f"), position.range.currentValue);
            if (pPositionCtrl) pPositionCtrl->SetWindowText(value);
            if (pPositionCtrl) {
                pPositionCtrl->SetWindowText(value);
                pPositionCtrl->EnableWindow(position.isEnable);
                if (position.isEnable) {
                    CString strError;
                    strError.Format(_T("定位点%d"), i + 1);
                    UpdateRegexEdit((CRegexEdit*)pPositionCtrl, position.range, strError);
                }
            }
        }
        else {
            // æ¸…空控件内容
            if (pDescriptionCtrl) pDescriptionCtrl->SetWindowText(_T(""));
            if (pPositionCtrl) pPositionCtrl->SetWindowText(_T(""));
            if (pDescriptionCtrl) {
                pDescriptionCtrl->SetWindowText(_T(""));
                pDescriptionCtrl->EnableWindow(FALSE);
            }
            if (pPositionCtrl) {
                pPositionCtrl->SetWindowText(_T(""));
                pPositionCtrl->EnableWindow(FALSE);
            }
        }
    }
}
@@ -433,19 +474,19 @@
    // èŽ·å–ç•Œé¢ä¸Šçš„ä¿®æ”¹å‚æ•°
    CString text;
    m_editManualSpeed.GetWindowText(text);
    m_pRegexEdit[EDIT_MANUAL_SPEED]->GetWindowText(text);
    axisData.manualSpeed.currentValue = _ttof(text);
    m_editAutoSpeed.GetWindowText(text);
    m_pRegexEdit[EDIT_AUTO_SPEED]->GetWindowText(text);
    axisData.autoSpeed.currentValue = _ttof(text);
    m_editAccelerationTime.GetWindowText(text);
    m_pRegexEdit[EDIT_ACCE_TIME]->GetWindowText(text);
    axisData.accelerationTime.currentValue = _ttof(text);
    m_editDecelerationTime.GetWindowText(text);
    m_pRegexEdit[EDIT_DECE_TIME]->GetWindowText(text);
    axisData.decelerationTime.currentValue = _ttof(text);
    m_editJogDistance.GetWindowText(text);
    m_pRegexEdit[EDIT_MICROMENTUM]->GetWindowText(text);
    axisData.jogDistance.currentValue = _ttof(text);
    // æ›´æ–°å®šä½ç‚¹æ•°æ®
@@ -454,7 +495,7 @@
        if (index < axisData.positions.size()) {
            // æž„建控件名称
            CString descriptionName, positionName, minValueName, maxValueName;
            CString descriptionName, positionName;
            descriptionName.Format(_T("IDC_EDIT_AXIS_ANCHOR_POINT_DESCRIP%d"), i + 1);
            positionName.Format(_T("IDC_EDIT_AXIS_ANCHOR_POINT%d"), i + 1);
@@ -463,7 +504,7 @@
            CEdit* pPositionEdit = (CEdit*)GetDlgItem(FindIDByName(positionName));
            if (pDescriptionEdit && pPositionEdit) {
                CString description, positionValue, minValue, maxValue;
                CString description, positionValue;
                // èŽ·å–æŽ§ä»¶ä¸­çš„æ–‡æœ¬
                pDescriptionEdit->GetWindowText(description);
@@ -769,17 +810,15 @@
            m_nBtnsFlashState8 = ((BYTE)pData[b + 4] | (BYTE)pData[b + 5] << 8);
            m_nBtnsFlashState8 |= ((BYTE)pData[b + 6] << 16 | (BYTE)pData[b + 7] << 24);
            AxisInfo axisInfo = RecipeManager::getInstance().getAxis(nAxisId);
            axisInfo.autoSpeed.currentValue = m_fAutoSpeed;                                                // è‡ªåŠ¨é€Ÿåº¦
            axisInfo.manualSpeed.currentValue = m_fManualSpeed;                                            // æ‰‹åŠ¨é€Ÿåº¦
            axisInfo.jogDistance.currentValue = CToolUnits::toInt32(&pData[81 * 2]) * 0.001;            // å¾®åŠ¨é‡
            axisInfo.accelerationTime.currentValue = CToolUnits::toInt32(&pData[62 * 2]) * 0.001;        // åŠ é€Ÿæ—¶é—´
            axisInfo.decelerationTime.currentValue = CToolUnits::toInt32(&pData[64 * 2]) * 0.001;        // å‡é€Ÿæ—¶é—´
            // è¯»å–定位点数据
            AxisInfo axisInfo = RecipeManager::getInstance().getAxis(nAxisId);
            for (int i = 0; i < axisInfo.positions.size(); ++i) {
                unsigned int positionAddress = 100 + (i * 2);
                axisInfo.positions[i].range.currentValue = CToolUnits::toInt32(&pData[positionAddress * 2]) * 0.001;
                if (axisInfo.positions[i].isEnable == FALSE) {
                    unsigned int positionAddress = 100 + (i * 2);
                    //axisInfo.positions[i].range.minValue = CToolUnits::toInt32(&pData[positionAddress * 2]) * 0.001;
                    axisInfo.positions[i].range.currentValue = CToolUnits::toInt32(&pData[positionAddress * 2]) * 0.001;
                    //axisInfo.positions[i].range.maxValue = CToolUnits::toInt32(&pData[positionAddress * 2]) * 0.001;
                }
            }
            RecipeManager::getInstance().updateAxis(axisInfo);
@@ -805,15 +844,17 @@
    ON_BN_CLICKED(IDC_BUTTON_AXIS_ANCHOR_POINT5, &CAxisSettingsDlg::OnBnClickedButtonAxisAnchorPoint5)
    ON_BN_CLICKED(IDC_BUTTON_AXIS_TEST_OPR, &CAxisSettingsDlg::OnBnClickedButtonAxisTestOpr)
    ON_BN_CLICKED(IDC_BUTTON_AXIS_TEST_STOP, &CAxisSettingsDlg::OnBnClickedButtonAxisTestStop)
    ON_BN_CLICKED(IDC_BUTTON_AXIS_SEV, &CAxisSettingsDlg::OnBnClickedButtonAxisSev)
    ON_CBN_SELCHANGE(IDC_COMBO_AXIS_NAME, &CAxisSettingsDlg::OnSelchangeComboAxisName)
    ON_BN_CLICKED(IDC_BUTTON_AXIS_SAVE, &CAxisSettingsDlg::OnBnClickedButtonAxisSave)
    ON_BN_CLICKED(IDC_BUTTON_AXIS_UPDATE_UI, &CAxisSettingsDlg::OnBnClickedButtonAxisUpdateUi)
    ON_BN_CLICKED(IDC_BUTTON_AXIS_DETAIL_SETTINGS, &CAxisSettingsDlg::OnBnClickedButtonAxisDetailSettings)
    ON_MESSAGE(ID_MSG_UPDATA_DATA_TO_UI, &CAxisSettingsDlg::OnUpdateDataToUI)
    ON_WM_SIZE()
    ON_WM_CTLCOLOR()
    ON_WM_SIZING()
    ON_WM_TIMER()
    ON_WM_CLOSE()
    ON_BN_CLICKED(IDC_BUTTON_AXIS_SEV, &CAxisSettingsDlg::OnBnClickedButtonAxisSev)
END_MESSAGE_MAP()
@@ -830,20 +871,13 @@
    SetWindowText(strTitle);
    // éšè—å…‰æ ‡
    //HideEditCursor(IDC_EDIT_AXIS_CURR_POS);
    HideEditCursor(IDC_EDIT_AXIS_CURR_POS);
    HideEditCursor(IDC_EDIT_AXIS_CURR_MANUAL_SPEED);
    HideEditCursor(IDC_EDIT_AXIS_CURR_AUTO_SPEED);
    HideEditCursor(IDC_EDIT_AXIS_CURR_ROTA_SPEED);
    HideEditCursor(IDC_EDIT_AXIS_CURR_LOAD);
    HideEditCursor(IDC_EDIT_AXIS_CURR_ERROR_NUMBER);
    HideEditCursor(IDC_EDIT_AXIS_CURR_ALARM_NUMBER);
    // æµ‹è¯•
    {
        CEdit* pEdit = (CEdit*)GetDlgItem(IDC_EDIT_AXIS_CURR_POS);
        pEdit->EnableWindow(TRUE);
        pEdit->SetReadOnly(FALSE);
    }
    // è®¾ç½®æµ‹è¯•状态
    m_pBlLabels[LABEL_FLS]->SubclassDlgItem(IDC_STATIC_AXIS_TEST_FLS, this);
@@ -861,6 +895,18 @@
        pLabel->SetDynamicFont(TRUE);
    }
    
    // åˆå§‹åŒ–编辑框
    m_pRegexEdit[EDIT_MANUAL_SPEED]->SubclassDlgItem(IDC_EDIT_AXIS_MODITFY_MANUAL_SPEED, this);
    m_pRegexEdit[EDIT_AUTO_SPEED]->SubclassDlgItem(IDC_EDIT_AXIS_MODITFY_AUTO_SPEED, this);
    m_pRegexEdit[EDIT_ACCE_TIME]->SubclassDlgItem(IDC_EDIT_AXIS_MODITFY_ACCE_TIME, this);
    m_pRegexEdit[EDIT_DECE_TIME]->SubclassDlgItem(IDC_EDIT_AXIS_MODITFY_DECE_TIME, this);
    m_pRegexEdit[EDIT_MICROMENTUM]->SubclassDlgItem(IDC_EDIT_AXIS_MODITFY_MICROMENTUM, this);
    m_pRegexEdit[EDIT_ANCHOR_POINT1]->SubclassDlgItem(IDC_EDIT_AXIS_ANCHOR_POINT1, this);
    m_pRegexEdit[EDIT_ANCHOR_POINT2]->SubclassDlgItem(IDC_EDIT_AXIS_ANCHOR_POINT2, this);
    m_pRegexEdit[EDIT_ANCHOR_POINT3]->SubclassDlgItem(IDC_EDIT_AXIS_ANCHOR_POINT3, this);
    m_pRegexEdit[EDIT_ANCHOR_POINT4]->SubclassDlgItem(IDC_EDIT_AXIS_ANCHOR_POINT4, this);
    m_pRegexEdit[EDIT_ANCHOR_POINT5]->SubclassDlgItem(IDC_EDIT_AXIS_ANCHOR_POINT5, this);
    // æŒ‰é’®åˆå§‹åŒ–
    m_pBlBtns[BTN_PAGE1]->SubclassDlgItem(IDC_BUTTON_AXIS_ANCHOR_POINT_GROUP1, this);
    m_pBlBtns[BTN_PAGE2]->SubclassDlgItem(IDC_BUTTON_AXIS_ANCHOR_POINT_GROUP2, this);
@@ -975,6 +1021,11 @@
    CWnd* pWnd = CWnd::FromHandle(pMsg->hwnd);
    if (pWnd) {
        if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_RETURN) {
            // é˜»æ­¢å›žè½¦é”®é»˜è®¤å¤„理,防止对话框关闭
            return TRUE;
        }
        // åˆ¤æ–­é¼ æ ‡æ˜¯å¦è¿›å…¥æŒ‡å®šæŽ§ä»¶åŒºåŸŸ
        if (pWnd->GetSafeHwnd() == GetDlgItem(IDC_EDIT_AXIS_ANCHOR_POINT_DESCRIP1)->m_hWnd ||
            pWnd->GetSafeHwnd() == GetDlgItem(IDC_EDIT_AXIS_ANCHOR_POINT_DESCRIP2)->m_hWnd ||
@@ -1202,7 +1253,7 @@
    handleAxisOperation(AxisOperationType::POSITION_1, true);
    Sleep(200);
    handleAxisOperation(AxisOperationType::POSITION_1, false);
    m_pBlBtns[BTN_POINT1]->Flash(1000);
    m_pBlBtns[BTN_POINT1]->Flash(500);
}
void CAxisSettingsDlg::OnBnClickedButtonAxisAnchorPoint2()
@@ -1298,6 +1349,7 @@
    updateDataFromUI(axisId);
    if (RecipeManager::getInstance().saveRecipe(std::string(CT2A(m_strRecipeName)))) {
        writeAxisDataToPLC(axisId);
        cstrMessage.Format(_T("保存轴 [%d] å‚数成功!"), axisId);
        SystemLogManager::getInstance().log(SystemLogManager::LogType::Operation, std::string(CT2A(cstrMessage)));
    }
@@ -1307,6 +1359,36 @@
    }
    AfxMessageBox(cstrMessage);
}
void CAxisSettingsDlg::OnBnClickedButtonAxisUpdateUi()
{
    // TODO: åœ¨æ­¤æ·»åŠ æŽ§ä»¶é€šçŸ¥å¤„ç†ç¨‹åºä»£ç 
    int axisId = getCurrentSelectedAxisID();
    if (axisId == -1) {
        AfxMessageBox(_T("请选择一个有效的轴编号!"));
        return;
    }
    refreshAxisDetails(axisId);
    refreshPositionDetails(axisId, m_currentPage);
}
void CAxisSettingsDlg::OnBnClickedButtonAxisDetailSettings()
{
    // TODO: åœ¨æ­¤æ·»åŠ æŽ§ä»¶é€šçŸ¥å¤„ç†ç¨‹åºä»£ç 
    int nAxisId = getCurrentSelectedAxisID();
    if (nAxisId == -1) {
        AfxMessageBox(_T("请选择一个有效的轴编号!"));
        return;
    }
    CAxisDetailSettingsDlg dlg(m_strRecipeName, nAxisId, this);
    dlg.SetPLC(m_pPLC);
    dlg.DoModal();
    refreshAxisDetails(nAxisId);
    refreshPositionDetails(nAxisId, m_currentPage);
}
LRESULT CAxisSettingsDlg::OnUpdateDataToUI(WPARAM wParam, LPARAM lParam)
@@ -1321,16 +1403,32 @@
    // æ›´æ–°Labels状态
    UpdateLabels();
    // æ›´æ–°å®šä½ç‚¹
    //refreshPositionDetails(getCurrentSelectedAxisID(), m_currentPage);
    // æ›´æ–°ä¸å¯å†™çš„定位点数据
    RecipeManager& recipeManager = RecipeManager::getInstance();
    for (int i = 0; i < AXIS_PAGE_SIZE; ++i) {
        PositionRange position = recipeManager.getPositionByIndex(getCurrentSelectedAxisID(), m_currentPage, AXIS_PAGE_SIZE, 0);
        if (position.isEnable) {
            continue;
        }
        CString positionName;
        positionName.Format(_T("IDC_EDIT_AXIS_ANCHOR_POINT%d"), i + 1);
        CEdit* pPositionEdit = (CEdit*)GetDlgItem(FindIDByName(positionName));
        if (pPositionEdit) {
            CString positionValue;
            positionValue.Format(_T("%.3f"), position.range.currentValue);
            pPositionEdit->GetWindowText(positionValue);
        }
    }
    
    // OPR按钮是否要闪烁或停止闪烁
    // 06.0和08.0
    if (m_nBtnsFlashState6 & 0x01) {
        // 06.0
        if (!m_pBlBtns[BTN_JOG_OPR]->IsFlash()) {
            m_pBlBtns[BTN_JOG_OPR]->Flash(1000);
            m_pBlBtns[BTN_JOG_OPR]->Flash(500);
        }
    }
    else if (m_nBtnsFlashState8 & 0x01) {
@@ -1346,7 +1444,7 @@
    if (m_nBtnsFlashState6 & v) {
        if (!m_pBlBtns[BTN_POINT1]->IsFlash()) {
            m_pBlBtns[BTN_POINT1]->Flash(1000);
            m_pBlBtns[BTN_POINT1]->Flash(500);
        }
    }
    else if (m_nBtnsFlashState8 & v) {
@@ -1357,7 +1455,7 @@
    if (m_nBtnsFlashState6 & (v << 1)) {
        if (!m_pBlBtns[BTN_POINT2]->IsFlash()) {
            m_pBlBtns[BTN_POINT2]->Flash(1000);
            m_pBlBtns[BTN_POINT2]->Flash(500);
        }
    }
    else if (m_nBtnsFlashState8 & (v << 1)) {
@@ -1368,7 +1466,7 @@
    if (m_nBtnsFlashState6 & (v << 2)) {
        if (!m_pBlBtns[BTN_POINT3]->IsFlash()) {
            m_pBlBtns[BTN_POINT3]->Flash(1000);
            m_pBlBtns[BTN_POINT3]->Flash(500);
        }
    }
    else if (m_nBtnsFlashState8 & (v << 2)) {
@@ -1379,7 +1477,7 @@
    if (m_nBtnsFlashState6 & (v << 3)) {
        if (!m_pBlBtns[BTN_POINT4]->IsFlash()) {
            m_pBlBtns[BTN_POINT4]->Flash(1000);
            m_pBlBtns[BTN_POINT4]->Flash(500);
        }
    }
    else if (m_nBtnsFlashState8 & (v << 3)) {
@@ -1390,7 +1488,7 @@
    if (m_nBtnsFlashState6 & (v << 4)) {
        if (!m_pBlBtns[BTN_POINT5]->IsFlash()) {
            m_pBlBtns[BTN_POINT5]->Flash(1000);
            m_pBlBtns[BTN_POINT5]->Flash(500);
        }
    }
    else if (m_nBtnsFlashState8 & (v << 4)) {
SourceCode/Bond/BondEq/View/AxisSettingsDlg.h
@@ -2,12 +2,13 @@
#include "afxdialogex.h"
#include "BlButton.h"
#include "BLLabel.h"
#include "RegexEdit.h"
#include "CPLC.h"
// æ¯é¡µå®šä½ç‚¹æ˜¾ç¤ºä¸ªæ•°
#define AXIS_PAGE_SIZE    5
// LABEL控件
// Label控件
#define LABEL_MAX        6
#define LABEL_FLS        0
#define LABEL_DOG        1
@@ -15,6 +16,19 @@
#define LABEL_READY        3
#define LABEL_BUSY        4
#define LABEL_ERR        5
// RegexEdit控件
#define EDIT_MAX            10
#define EDIT_MANUAL_SPEED    0
#define EDIT_AUTO_SPEED        1
#define EDIT_ACCE_TIME        2
#define EDIT_DECE_TIME        3
#define EDIT_MICROMENTUM    4
#define EDIT_ANCHOR_POINT1    5
#define EDIT_ANCHOR_POINT2    6
#define EDIT_ANCHOR_POINT3    7
#define EDIT_ANCHOR_POINT4    8
#define EDIT_ANCHOR_POINT5    9
// BUTTON控件
#define BTN_MAX            15
@@ -76,6 +90,7 @@
    void SetLabelColor(CBLLabel& label, COLORREF color);
    void SetLabelColorBasedOnState(CBLLabel& label, BOOL bState, COLORREF colorTrue, COLORREF colorFalse);
    void UpdateLabels();
    void UpdateRegexEdit(CRegexEdit* pRegexEdit, const ValueRange& range, const CString& title);
    void updatePageButtonStates();
    void HideEditCursor(int nCtrlID);
    int getCurrentSelectedAxisID();
@@ -105,9 +120,10 @@
    // æŽ§ä»¶
    CBlButton* m_pBlBtns[BTN_MAX];
    CBLLabel* m_pBlLabels[LABEL_MAX];
    CRegexEdit* m_pRegexEdit[EDIT_MAX];
    CComboBox m_comboAxisNO;
    CStatic m_staticAxisNO, m_staticAxisDescription, m_staticStartAddress;
    CEdit m_editManualSpeed, m_editAutoSpeed, m_editAccelerationTime, m_editDecelerationTime, m_editJogDistance;
    //CEdit m_editManualSpeed, m_editAutoSpeed, m_editAccelerationTime, m_editDecelerationTime, m_editJogDistance;
    
    std::map<int, CRect> m_mapCtrlLayouts;
    std::map<int, CFont*> m_mapFonts;
@@ -154,6 +170,8 @@
    afx_msg void OnBnClickedButtonAxisSev();
    afx_msg void OnSelchangeComboAxisName();
    afx_msg void OnBnClickedButtonAxisSave();
    afx_msg void OnBnClickedButtonAxisUpdateUi();
    afx_msg void OnBnClickedButtonAxisDetailSettings();
    afx_msg LRESULT OnUpdateDataToUI(WPARAM wParam, LPARAM lParam);
    afx_msg void OnTimer(UINT_PTR nIDEvent);
    afx_msg void OnClose();
SourceCode/Bond/BondEq/View/IOMonitoringDlg.cpp
@@ -214,8 +214,8 @@
    // åˆ›å»ºåŠ¨æ€æŽ§ä»¶
    CBLLabel* pStatic = new CBLLabel();
    DWORD style = WS_CHILD | WS_VISIBLE | SS_CENTERIMAGE; // ç¡®ä¿åž‚直居中
    if (hasBorder) {
        style |= WS_BORDER; // æ·»åŠ è¾¹æ¡†
    if (!hasBorder) {
        pStatic->DisableBorder();
    }
    pStatic->Create(text, style, CRect(x, y, x + width, y + height), this, id);
@@ -234,6 +234,8 @@
    UserRole enRole = userManager.getCurrentUserRole();
    if (clickCallback && (enRole == UserRole::SuperAdmin || enRole == UserRole::Operator)) {
        pStatic->SetClickCallback(clickCallback);
        pStatic->SetRoundedCorners(TRUE, 5);
        pStatic->DisableBorder();
    }
    // å­˜å‚¨æŽ§ä»¶æŒ‡é’ˆ