| | |
| | | |
| | | // 绑定界面需要显示的设备 |
| | | static const std::vector<DeviceMetaInfo> g_vecBindDevices = { |
| | | { EQ_ID_VACUUMBAKE, EQ_NAME_VACUUMBAKE }, |
| | | { EQ_ID_Bonder1, EQ_NAME_BONDER1 }, |
| | | { EQ_ID_Bonder2, EQ_NAME_BONDER2 }, |
| | | { EQ_ID_BAKE_COOLING, EQ_NAME_BAKE_COOLING }, |
| | | { EQ_ID_MEASUREMENT, EQ_NAME_MEASUREMENT }, |
| | | { EQ_ID_EFEM, EQ_NAME_EFEM } |
| | | { EQ_ID_VACUUMBAKE, EQ_NAME_VACUUMBAKE }, |
| | | { EQ_ID_Bonder1, EQ_NAME_BONDER1 }, |
| | | { EQ_ID_Bonder2, EQ_NAME_BONDER2 }, |
| | | { EQ_ID_BAKE_COOLING, EQ_NAME_BAKE_COOLING }, |
| | | { EQ_ID_MEASUREMENT, EQ_NAME_MEASUREMENT }, |
| | | { EQ_ID_EFEM, EQ_NAME_EFEM } |
| | | }; |
| | | |
| | | // CRecipeDeviceBindDlg 对话框 |
| | |
| | | |
| | | CRecipeDeviceBindDlg::CRecipeDeviceBindDlg(CWnd* pParent /*=nullptr*/) |
| | | : CDialogEx(IDD_DIALOG_RECIPE_DEVICE_BIND, pParent) |
| | | , m_strPPID(_T("")) |
| | | , m_strDesc(_T("")) |
| | | { |
| | | |
| | | } |
| | |
| | | { |
| | | } |
| | | |
| | | const RecipeInfo& CRecipeDeviceBindDlg::GetRecipeInfo() const { |
| | | return m_recipe; |
| | | } |
| | | |
| | | void CRecipeDeviceBindDlg::SetRecipeInfo(const RecipeInfo& info) |
| | | { |
| | | m_recipe = info; |
| | | } |
| | | |
| | | void CRecipeDeviceBindDlg::ReleaseDeviceControls() |
| | | { |
| | | for (auto& ctrl : m_vecDevices) { |
| | | delete ctrl.editDeviceID; ctrl.editDeviceID = nullptr; |
| | | delete ctrl.editDeviceName; ctrl.editDeviceName = nullptr; |
| | | delete ctrl.comboRecipeID; ctrl.comboRecipeID = nullptr; |
| | | } |
| | | m_vecDevices.clear(); |
| | | } |
| | | |
| | | void CRecipeDeviceBindDlg::CreateDeviceControls(int nXStart, int nYStart, int nTotalControlWidth, int nRowHeight) |
| | | { |
| | | for (size_t i = 0; i < g_vecBindDevices.size(); ++i) { |
| | | int y = nYStart + static_cast<int>(i) * nRowHeight; |
| | | auto* pEditID = new CEdit; |
| | | pEditID->Create(WS_CHILD | WS_VISIBLE | WS_BORDER | ES_CENTER, CRect(nXStart, y, nXStart + 100, y + 25), this, (UINT)(IDC_EDIT_DEVICEID_BASE + i)); |
| | | pEditID->SetFont(&m_font); |
| | | |
| | | auto* pEditName = new CEdit; |
| | | pEditName->Create(WS_CHILD | WS_VISIBLE | WS_BORDER | ES_CENTER, CRect(nXStart + 110, y, nXStart + 210, y + 25), this, (UINT)(IDC_EDIT_DEVICENAME_BASE + i)); |
| | | pEditName->SetFont(&m_font); |
| | | |
| | | auto* pCombo = new CComboBox; |
| | | pCombo->Create(WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST, CRect(nXStart + 220, y, nXStart + nTotalControlWidth, y + 25), this, (UINT)(IDC_COMBO_RECIPEID_BASE + i)); |
| | | pCombo->SetFont(&m_font); |
| | | |
| | | m_vecDevices.push_back({ pEditID, pEditName, pCombo }); |
| | | } |
| | | } |
| | | |
| | | bool CRecipeDeviceBindDlg::FillComboRecipeList(CComboBox* pCombo, int nDeviceID, int nSelectedRecipeID) |
| | | { |
| | | auto& master = theApp.m_model.getMaster(); |
| | | auto* pEq = master.getEquipment(nDeviceID); |
| | | if (!pEq) { |
| | | return false; |
| | | } |
| | | |
| | | auto* pRecipeList = pEq->getRecipeList(0); |
| | | if (!pRecipeList) { |
| | | return false; |
| | | } |
| | | |
| | | auto& mapRecipeIds = pRecipeList->getIds(); |
| | | bool bFound = false; |
| | | pCombo->ResetContent(); |
| | | for (const auto& pair : mapRecipeIds) { |
| | | int nRecipeID = pair.second; |
| | | |
| | | std::string strDeviceName; |
| | | for (const auto& dev : g_vecBindDevices) { |
| | | if (dev.nDeviceID == pEq->getID()) { |
| | | strDeviceName = dev.strDeviceName; |
| | | } |
| | | } |
| | | |
| | | std::string strRecipeName = RecipeManager::getInstance().getDeviceRecipeName(strDeviceName, nRecipeID); |
| | | if (strRecipeName.empty()) { |
| | | strRecipeName = std::to_string(nRecipeID); |
| | | } |
| | | |
| | | CString str; |
| | | str.Format(_T("%s"), strRecipeName.c_str()); |
| | | int idx = pCombo->AddString(str); |
| | | pCombo->SetItemData(idx, nRecipeID); |
| | | if (nSelectedRecipeID == nRecipeID) { |
| | | pCombo->SetCurSel(idx); |
| | | bFound = true; |
| | | } |
| | | } |
| | | |
| | | if (nSelectedRecipeID != -1 && !bFound) { |
| | | pCombo->SetCurSel(CB_ERR); |
| | | } |
| | | else if (pCombo->GetCount() > 0 && nSelectedRecipeID == -1) { |
| | | pCombo->SetCurSel(0); |
| | | } |
| | | |
| | | return true; |
| | | } |
| | | |
| | | bool CRecipeDeviceBindDlg::FillDeviceInfo(int idx, int nDeviceID, const CString& strDeviceName, int nSelectedRecipeID) |
| | | { |
| | | if (idx < 0 || idx >= (int)m_vecDevices.size()) { |
| | | return false; |
| | | } |
| | | |
| | | auto& ctrl = m_vecDevices[idx]; |
| | | CString strID; |
| | | strID.Format(_T("%d"), nDeviceID); |
| | | ctrl.editDeviceID->SetWindowText(strID); |
| | | ctrl.editDeviceID->SetReadOnly(TRUE); |
| | | ctrl.editDeviceName->SetWindowText(strDeviceName); |
| | | ctrl.editDeviceName->SetReadOnly(TRUE); |
| | | |
| | | if (!FillComboRecipeList(ctrl.comboRecipeID, nDeviceID, nSelectedRecipeID)) { |
| | | CString str; |
| | | str.Format(_T("设备 [%s] 或其配方列表未找到,请检查设备配置"), strDeviceName.GetString()); |
| | | AfxMessageBox(str); |
| | | return false; |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | void CRecipeDeviceBindDlg::DoDataExchange(CDataExchange* pDX) |
| | | { |
| | | CDialogEx::DoDataExchange(pDX); |
| | | DDX_Text(pDX, IDC_EDIT_PPID, m_strPPID); |
| | | DDX_Text(pDX, IDC_EDIT_DESC, m_strDesc); |
| | | } |
| | | |
| | | |
| | | BEGIN_MESSAGE_MAP(CRecipeDeviceBindDlg, CDialogEx) |
| | | ON_WM_CLOSE() |
| | | ON_WM_SIZE() |
| | | ON_WM_CLOSE() |
| | | ON_WM_SIZE() |
| | | ON_BN_CLICKED(IDOK, &CRecipeDeviceBindDlg::OnBnClickedOk) |
| | | END_MESSAGE_MAP() |
| | | |
| | | |
| | |
| | | { |
| | | CDialogEx::OnInitDialog(); |
| | | |
| | | // TODO: 在此添加额外的初始化 |
| | | // 设置固定大小(例如 600x400) |
| | | SetWindowPos(nullptr, 0, 0, 600, 400, SWP_NOMOVE | SWP_NOZORDER); |
| | | // 设置对话框标题 |
| | | SetWindowText(m_recipe.vecDeviceList.empty() ? _T("新建配方") : _T("编辑配方")); |
| | | |
| | | // 创建控件 |
| | | const int totalControlWidth = 340; |
| | | CRect clientRect; |
| | | GetClientRect(&clientRect); |
| | | int xStart = (clientRect.Width() - totalControlWidth) / 2; |
| | | // 创建动态控件字体 |
| | | if (!m_font.m_hObject) { |
| | | CFont* pDlgFont = GetFont(); |
| | | LOGFONT lf; |
| | | if (pDlgFont && pDlgFont->GetLogFont(&lf)) { |
| | | lf.lfHeight = -16; |
| | | m_font.CreateFontIndirect(&lf); |
| | | } |
| | | } |
| | | |
| | | const int nRowHeight = 30; |
| | | const int yStart = 30; // 顶部起始高度 |
| | | // 计算坐标 |
| | | CRect rDesc; |
| | | int nXStart = 30, nYStart = 30, nTotalControlWidth = 340; |
| | | if (auto* pWndDesc = GetDlgItem(IDC_STATIC_DESC)) { |
| | | pWndDesc->GetWindowRect(&rDesc); ScreenToClient(&rDesc); |
| | | nXStart = rDesc.left; |
| | | } |
| | | if (auto* pWndEdit = GetDlgItem(IDC_EDIT_DESC)) { |
| | | pWndEdit->GetWindowRect(&rDesc); ScreenToClient(&rDesc); |
| | | nYStart = rDesc.bottom + 20; |
| | | } |
| | | CRect rClient; GetClientRect(&rClient); |
| | | nTotalControlWidth = rClient.Width() - nXStart * 2; |
| | | const int nRowHeight = 30; |
| | | |
| | | const int nRowCount = static_cast<int>(g_vecBindDevices.size()); |
| | | for (int i = 0; i < nRowCount; ++i) { |
| | | int y = yStart + i * nRowHeight; |
| | | const auto& meta = g_vecBindDevices[i]; |
| | | // 清空旧控件 |
| | | ReleaseDeviceControls(); |
| | | |
| | | CEdit* pEditID = new CEdit(); |
| | | pEditID->Create(WS_CHILD | WS_VISIBLE | WS_BORDER, CRect(xStart, y, xStart + 100, y + 25), this, IDC_EDIT_DEVICEID_BASE + i); |
| | | // 创建新控件 |
| | | CreateDeviceControls(nXStart, nYStart, nTotalControlWidth, nRowHeight); |
| | | |
| | | CString strID; |
| | | strID.Format(_T("%d"), meta.nDeviceID); |
| | | pEditID->SetWindowText(strID); |
| | | pEditID->SetReadOnly(TRUE); // 设备ID只读 |
| | | auto& master = theApp.m_model.getMaster(); |
| | | |
| | | CEdit* pEditName = new CEdit(); |
| | | pEditName->Create(WS_CHILD | WS_VISIBLE | WS_BORDER, CRect(xStart + 110, y, xStart + 210, y + 25), this, IDC_EDIT_DEVICENAME_BASE + i); |
| | | pEditName->SetWindowText(CA2T(meta.strDeviceName)); |
| | | pEditName->SetReadOnly(TRUE); // 设备名称只读 |
| | | // 填充内容 |
| | | if (m_recipe.vecDeviceList.empty()) { |
| | | // 新建 |
| | | for (size_t i = 0; i < g_vecBindDevices.size(); ++i) { |
| | | const auto& meta = g_vecBindDevices[i]; |
| | | FillDeviceInfo((int)i, meta.nDeviceID, meta.strDeviceName); |
| | | } |
| | | } |
| | | else { |
| | | // 编辑 |
| | | m_strPPID = CA2T(m_recipe.strPPID.c_str()); |
| | | m_strDesc = CA2T(m_recipe.strDescription.c_str()); |
| | | UpdateData(FALSE); |
| | | |
| | | CComboBox* pCombo = new CComboBox(); |
| | | pCombo->Create(WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST, CRect(xStart + 220, y, xStart + 340, y + 300), this, IDC_COMBO_RECIPEID_BASE + i); |
| | | for (size_t i = 0; i < m_recipe.vecDeviceList.size() && i < m_vecDevices.size(); ++i) { |
| | | const auto& d = m_recipe.vecDeviceList[i]; |
| | | FillDeviceInfo((int)i, d.nDeviceID, d.strDeviceName.c_str(), d.nRecipeID); |
| | | } |
| | | } |
| | | |
| | | // 添加选项到 ComboBox |
| | | m_vecDevices.push_back({ pEditID, pEditName, pCombo }); |
| | | } |
| | | CenterWindow(); |
| | | |
| | | return TRUE; // return TRUE unless you set the focus to a control |
| | | // 异常: OCX 属性页应返回 FALSE |
| | |
| | | |
| | | void CRecipeDeviceBindDlg::OnClose() |
| | | { |
| | | // TODO: 在此添加消息处理程序代码和/或调用默认值 |
| | | CDialogEx::OnClose(); |
| | | // TODO: 在此添加消息处理程序代码和/或调用默认值 |
| | | CDialogEx::OnClose(); |
| | | |
| | | // 清理控件 |
| | | for (auto& device : m_vecDevices) { |
| | | if (device.editDeviceID) { |
| | | device.editDeviceID->DestroyWindow(); |
| | | delete device.editDeviceID; |
| | | } |
| | | if (device.editDeviceName) { |
| | | device.editDeviceName->DestroyWindow(); |
| | | delete device.editDeviceName; |
| | | } |
| | | if (device.comboRecipeID) { |
| | | device.comboRecipeID->DestroyWindow(); |
| | | delete device.comboRecipeID; |
| | | } |
| | | } |
| | | m_vecDevices.clear(); |
| | | // 清理控件 |
| | | ReleaseDeviceControls(); |
| | | } |
| | | |
| | | void CRecipeDeviceBindDlg::OnSize(UINT nType, int cx, int cy) |
| | | { |
| | | CDialogEx::OnSize(nType, cx, cy); |
| | | CDialogEx::OnSize(nType, cx, cy); |
| | | |
| | | // TODO: 在此处添加消息处理程序代码 |
| | | } |
| | | // TODO: 在此处添加消息处理程序代码 |
| | | } |
| | | |
| | | void CRecipeDeviceBindDlg::OnBnClickedOk() |
| | | { |
| | | // TODO: 在此添加控件通知处理程序代码 |
| | | UpdateData(TRUE); |
| | | |
| | | // 收集所有设备映射 |
| | | m_recipe.vecDeviceList.clear(); |
| | | for (const auto& dev : m_vecDevices) { |
| | | DeviceRecipe info; |
| | | CString strID, strName; |
| | | dev.editDeviceID->GetWindowText(strID); |
| | | dev.editDeviceName->GetWindowText(strName); |
| | | |
| | | int sel = dev.comboRecipeID->GetCurSel(); |
| | | info.nRecipeID = -1; |
| | | if (sel != CB_ERR) { |
| | | info.nRecipeID = (int)dev.comboRecipeID->GetItemData(sel); |
| | | } |
| | | info.nDeviceID = _ttoi(strID); |
| | | info.strDeviceName = CT2A(strName); |
| | | |
| | | m_recipe.vecDeviceList.push_back(info); |
| | | } |
| | | |
| | | // 检查 PPID 是否为空 |
| | | if (m_strPPID.IsEmpty()) { |
| | | AfxMessageBox(_T("配方 PPID 不能为空")); |
| | | return; |
| | | } |
| | | |
| | | // PPID和描述 |
| | | m_recipe.strPPID = CT2A(m_strPPID); |
| | | m_recipe.strDescription = CT2A(m_strDesc); |
| | | |
| | | CDialogEx::OnOK(); |
| | | } |