#include "UiManager.h" #include "WindowRuntime.h" #include "PouManager.h" #include "GvlManager.h" #include "WindowAppUiScene.h" #include "VPControls.h" // 字符串之间的间隔,用于Tip 与 Text 之间的组装 #define STRING_INTERVAL ": " UiManager::UiManager() { m_pMainPage = nullptr; } /// /// 注册新的UIView /// /// void UiManager::registerNewUi(WindowAppUiView* pView) { QString strName = pView->m_strPageName; if (m_pAllPages.contains(strName)) { m_pAllPages[strName] = pView; return; } m_pAllPages.insert(strName, pView); } /// /// 删除指定页面(此处需要检查是否删除的是主页) /// /// bool UiManager::deleteUi(const QString& strName, bool bForce) { // 如果删除的页面是主页,则提示是否确认删除,并且需要指定新的主页 if (m_pMainPage!=nullptr && strName == m_pMainPage->m_strPageName) { // 是否不弹提示强制删除 if (!bForce) { QMessageBox::StandardButton ret = Utility::VPQuesitonMessageBox("确定要删除主页[" + strName + "吗? 你需要指定新的主页后,才可以执行发布操作."); if (ret != QMessageBox::Yes) { return false; } } m_pMainPage = nullptr; } // 数据结构中删除 m_pAllPages.remove(strName); qDebug() << "[UiManager] Delete UI " << strName << "."; return true; } /// /// 注册新的控件 /// /// /// void UiManager::regiterNewControl(VControlObject* pNewControl, WindowAppUiView* pView) { m_AllControls.insert(pNewControl->m_pWidget, pView); qDebug() << "[UiManager] UiManager::regiterNewControl - " << pNewControl << " in " << pView->m_strPageName; } /// /// 删除一个控件 /// /// void UiManager::deleteControl(QWidget* pDelControl) { m_AllControls.remove(pDelControl); // 删除本UI控件和其他的关联关系 m_UiToDllControls.remove(pDelControl); m_UiToRtControls.remove(pDelControl); m_UiControlToValues.remove(pDelControl); QHash::iterator it = m_DllToUiControls.begin(); for (; it != m_DllToUiControls.end();) { if (it.value() == pDelControl) { m_DllToUiControls.erase(it); break; } else { it++; } } QHash::iterator it2 = m_RtToUiControls.begin(); for (; it2 != m_RtToUiControls.end();) { if (it2.value() == pDelControl) { m_RtToUiControls.erase(it2); break; } else { it2++; } } QHashIterator it3(m_ValueToUiControls); while (it3.hasNext()) { QList pWidgets = m_ValueToUiControls.values(it3.next().key()); for (QWidget* pWidget : pWidgets) { if (pWidget == pDelControl) { // 2021-11-9 取消DataLink标识 it3.key()->bDataLink = false; // 减小引用计数 if (it3.key()->nRefCount > 0) { it3.key()->nRefCount--; } m_ValueToUiControls.remove(it3.key(), pDelControl); break; } } } } /// /// 获取所有的Ui名称 /// /// QStringList UiManager::getAllUiNames() { // return this->m_UiNames; QStringList listNames; QMapIterator it(m_pAllPages); while (it.hasNext()) { listNames.push_back(it.next().key()); } return listNames; } /// /// 获取指定名字的页面 /// /// /// WindowAppUiView* UiManager::getPageByName(const QString& strName) { if (m_pAllPages.contains(strName)) { return m_pAllPages[strName]; } else { return nullptr; } } /// /// 检查各个页面中携带的属性是否正确有效 /// /// bool UiManager::checkAll() { QMapIterator it(m_pAllPages); while (it.hasNext()) { // 依次检测每一个UI页面的属性设置 bool bRet = it.next().value()->uiScene()->checkAllProperties(); if (!bRet) { return false; } } return true; } /// /// 发布所有页面到Runtime执行(所有的关于主页的检查都放到这里来执行) /// bool UiManager::publishAll() { // 首先检查是否设定了主页 if (m_pMainPage == nullptr) { CRITICAL_MESSAGE("Error: 请先设置主页面"); return false; } // 检查各个页面中携带的属性是否正确有效(仅检查必填项) bool bRet = checkAll(); if (!bRet) { return false; } // 然后将主页和所有页面都传输到Runtime发布 return g_pRuntime->publishAllPages(m_pMainPage, m_pAllPages); } /// /// 设定主页 /// /// bool UiManager::setMainPage(const QString& strName) { if (m_pAllPages.contains(strName)) { m_pMainPage = m_pAllPages[strName]; qDebug() << "[UiManager] Set " << strName << " as MainPage."; return true; } else { qWarning() << "[UiManager] Set " << strName << " as MainPage failed."; return false; } } /// /// 获取主页 /// /// WindowAppUiView* UiManager::getMainPage() { return this->m_pMainPage; } /// /// 序列化所有的WindowAppUiView* /// /// /// bool UiManager::serialized(QDataStream& out) { // 首先写入UI的总数量 out << m_pAllPages.size(); // 首先写入主页 out << m_pMainPage; // 遍历所有的UIView,执行序列化 QMapIterator it(m_pAllPages); while (it.hasNext()) { it.next(); // 跳过主页 if (it.value() != m_pMainPage) { out << it.value(); } } return true; } //===================================================================== // // 同步相关代码 // //===================================================================== /// /// 接收来自其他控件和变量的同步Event /// /// /// void UiManager::customEvent(QEvent* event) { // qDebug() << "UiManager::event " << event->type(); // 如果是控件同步消息 if (event->type() == CONTROL_EVENT_TYPEID) { qDebug() << "UiManager::event - CONTROL_EVENT"; SyncControlEvent* pValueEvent = dynamic_cast (event); // 取出参数执行同步 syncFromDll( pValueEvent->m_pSrcControl, pValueEvent->m_SyncMsg ); } // 如果是数值同步消息 else if (event->type() == VALUE_EVENT_TYPEID) { vDebug() << "VALUE_EVENT"; SyncValueEvent* pValueEvent = dynamic_cast (event); // 取出参数 QList syncValues = pValueEvent->getSyncValues(); for (VARIABLE* syncVal : syncValues) { this->syncFromValue(syncVal); } } // 如果是硬件数值同步消息 else if (event->type() == HDVALUE_EVENT_TYPEID) { qDebug() << "UiManager::event - HDVALUE_EVENT"; SyncHdValueEvent* pValueEvent = dynamic_cast (event); // 如果当前组不是硬件组态,不继续执行后续代码 ,为了解决硬件工具放在 POU 中时候,主动触发了ui刷新 if (pValueEvent != nullptr && pValueEvent->groupName() != CATEGORY_TOOL_HARDWARE) { return; } // 首先需要去Pou中取出此接口 POU* pHdPou = g_pPouManager->getHdwPou(); _INTERFACE* pInf = nullptr; // 第一种方式 if (!pValueEvent->m_strInstanceName.isEmpty() && !pValueEvent->m_strInfName.isEmpty()) { QString infFullName = pValueEvent->m_strInstanceName + "." + pValueEvent->m_strInfName; pInf = pHdPou->GetInterface(infFullName); } // 第二种方式 else if(pValueEvent->m_pSrcValue!=nullptr) { pInf = pHdPou->GetInterfaceByValuePtr(pValueEvent->m_pSrcValue); } else { qDebug() << "[Error] UiManager::customEvent - but SyncHdValueEvent invalid."; } // 如果接口成功取到,则执行同步 if (pInf != nullptr) { // 执行同步 this->syncFromValue(pInf); } else { qWarning() << "UiManager::customEvent - Can't find update interface, may be not a hardward interface."; } } //return QObject::event(event); } /// /// 绑定dll中的控件与UI控件 /// /// /// void UiManager::bindDllControlWithUiControl(QWidget* pDllControl, VControlObject* pUiControl) { m_DllToUiControls.insert(pDllControl, pUiControl->m_pWidget); m_UiToDllControls.insert(pUiControl->m_pWidget, pDllControl); // 刚绑定时,从dll向UI做一次同步 this->syncFromDllFirst(pDllControl, pUiControl); } /// /// 2022-9-13,解除dll中的控件与UI控件的绑定 /// /// /// void UiManager::unbindDllControlWithUiControl(QWidget* pDllControl, VControlObject* pUiControl) { m_DllToUiControls.remove(pDllControl); m_UiToDllControls.remove(pUiControl->m_pWidget); } /// /// 绑定UI控件与Runtime控件用于同步 /// /// /// void UiManager::bindUiControlWithRtControl(QWidget* pUiControl, QWidget* pRtControl) { m_UiToRtControls.insert(pUiControl, pRtControl); m_RtToUiControls.insert(pRtControl, pUiControl); } /// /// 2022-9-13,解除UI控件与Runtime控件的绑定 /// /// /// void UiManager::unbindUiControlWithRtControl(QWidget* pUiControl, QWidget* pRtControl) { m_UiToRtControls.remove(pUiControl); m_RtToUiControls.remove(pRtControl); } /// /// 绑定数值变量与UI控件用于同步 /// /// /// void UiManager::bindValueWithUiControl(VARIABLE* val, QWidget* pUiControl) { //LINK_VALUE lv; //lv.direction = dir; //lv.value = value; m_ValueToUiControls.insertMulti(val, pUiControl); m_UiControlToValues.insert(pUiControl, val); //// For Debug //foreach(const auto & key, m_ValueToUiControls.keys()) //{ // qDebug() << "bindValueWithUiControl: " << key->strFullName << " - " << m_ValueToUiControls.value(key); //} // 刚绑定时,从Value向UI做一次同步 this->syncFromValue(val); } /// /// 2022-9-13,解绑数值变量与UI控件(在控件变更了主索引绑定变量时,需要做解绑动作) /// /// /// void UiManager::unbindValueWithUiControl(VARIABLE* val, QWidget* pUiControl) { m_UiControlToValues.remove(pUiControl); QMutableHashIterator iter(m_ValueToUiControls); while (iter.hasNext()) { if (iter.next().key() == val) { QList pWidgets = m_ValueToUiControls.values(iter.key()); for (QWidget* pWidget : pWidgets) { if (pWidget == pUiControl) { m_ValueToUiControls.remove(iter.key(), pUiControl); return; } } } } } /// /// 绑定DataLink中的信息用于后续同步(仅 UI->Dll) /// bool UiManager::bindDataLinkSyncInformation(const DataLink& dataLink, VControlObject* pVControl) { // 2022-2-9 ,解决绑定Button相关数据连接中出现的bug(也不清楚是怎么出现的,先暂时这么处理一下看起来好像没问题) if (pVControl->m_Type == VALUE_TYPE::Control_Button) { pVControl->m_Property.m_DataLink = dataLink; return true; } POU* pPou = nullptr; TOOL* pTool = nullptr; _INTERFACE* pInf = nullptr; // 解析出Tool信息 this->parsePouToolFromDataLink(dataLink, pPou, pTool, pInf); if (pInf == nullptr) { vDebug() << "[Error] Abandon bind Datalink, Reason: Parse datalink failed."; return false; } // 如果是控件类型 if (pInf->Type == INF_TYPE::INF_TYPE_CONTROL) { return this->bindSyncByControl(pTool, pInf, pVControl); } // 数值类型或者普通数据类型的接口类型 else if (pInf->Type == INF_TYPE::INF_TYPE_VALUE || pInf->Type == INF_TYPE::INF_TYPE_STANDARD ) { // 如果是普通类型控件 if (!pVControl->isComplexControl()) { this->bindSyncByValue(pTool, pInf, pVControl); } // 2021-12-7 复杂类型控件 else { // 2022-2-10 绑定dll中的信息用于后续同步(复杂类型,暂未绑定,仅引用计数 + 1) // 由于不需要执行三方同步,此处不需要绑定 this->bindSyncByComplex(pTool, pInf); } } // 未处理类型 else { qWarning() << "DialogDataLink::bindSyncFromDll - Unsupported interface category : " << (int)pInf->Type; } return true; } /// /// 2022-9-13,解绑DataLine信息(在控件变更了主索引绑定变量时,需要做解绑动作) /// /// /// bool UiManager::unbindDataLinkSyncInformation(const DataLink& dataLink, VControlObject* pVControl) { if (pVControl->m_Type == VALUE_TYPE::Control_Button) { pVControl->m_Property.m_DataLink = dataLink; return true; } POU* pPou = nullptr; TOOL* pTool = nullptr; _INTERFACE* pDllInf = nullptr; // 解析出Tool信息 this->parsePouToolFromDataLink(dataLink, pPou, pTool, pDllInf); if (pDllInf == nullptr) { return false; } // 如果是控件类型 if (pDllInf->Type == INF_TYPE::INF_TYPE_CONTROL) { return this->unbindSyncByControl(pTool, pDllInf, pVControl); } // 数值类型或者普通数据类型的接口类型 else if (pDllInf->Type == INF_TYPE::INF_TYPE_VALUE || pDllInf->Type == INF_TYPE::INF_TYPE_STANDARD ) { // 如果是普通类型控件 if (!pVControl->isComplexControl()) { this->unbindSyncByValue(pTool, pDllInf, pVControl); } // 2021-12-7 复杂类型控件 else { this->unbindSyncByComplex(pTool, pDllInf); } } // 未处理类型 else { vDebug() << "Unsupported interface category : " << (int)pDllInf->Type; } return true; } /// /// 绑定dll中的信息用于后续同步(控件类型) /// /// bool UiManager::bindSyncByControl(TOOL* pTool, _INTERFACE* pDllInf, VControlObject* pVControl) { // 因为dll->UI只能是一对一,所以此处需要判断一下引用计数 if (pDllInf->nRefCount > 0) { vDebug() << ("Error: Interface[" + pDllInf->strNameWithType + "] ref count >0 : " + pDllInf->nRefCount + "."); return false; } // 引用计数 + 1 pDllInf->nRefCount++; // TODO:回调函数方式已经废弃(只是暂时留着备用) // dll->UI同步:给dll设置UI同步回调函数 CONTROL_CALLBACK callBack = std::bind( &UiManager::syncFromDll, g_pUiManager, std::placeholders::_1, std::placeholders::_2 ); pTool->pDllPtr->setControlCallback(callBack); // 设置同步event的target(这个为目前统一使用的方式,回调函数的方式已经废弃了) pTool->pDllPtr->setSyncTarget(g_pUiManager); // UI->Dll同步:信息存储至UiManager统一处理 QWidget* pDllControl = (QWidget*)pTool->pDllPtr->Interface(pDllInf->nIndex).value.Ptr; g_pUiManager->bindDllControlWithUiControl(pDllControl, pVControl); return true; } /// /// 2022-9-13 解绑dll中的控件信息 /// /// /// /// /// bool UiManager::unbindSyncByControl(TOOL* pTool, _INTERFACE* pDllInf, VControlObject* pVControl) { if (pDllInf->nRefCount > 0) { vDebug() << ("Error: Interface[" + pDllInf->strNameWithType + "] ref count >0 : " + pDllInf->nRefCount + "."); return false; } // 引用计数 - 1 pDllInf->nRefCount--; // 解绑UI->Dll的同步信息 QWidget* pDllControl = (QWidget*)pTool->pDllPtr->Interface(pDllInf->nIndex).value.Ptr; g_pUiManager->unbindDllControlWithUiControl(pDllControl, pVControl); return true; } /// /// 绑定接口信息用于后续同步(有可能是Dll接口,有可能是数值类型,数值可对应多个UI控件) /// /// /// /// bool UiManager::bindSyncByValue(TOOL* pTool, _INTERFACE* pInf, VControlObject* pVControl) { // 输出接口 - Text控件,一对多,输入接口 - Text控件,一对一 // 如果是输入接口,要检查引用计数 if (pInf->Direction == INF_DIRECTION::INF_DIR_IN && pInf->nRefCount > 0) { vDebug() << ("Error: Interface[" + pInf->strNameWithType + "] ref count >0 : " + pInf->nRefCount + "."); return false; } // 引用计数 + 1 pInf->nRefCount++; // Value->UI同步,给Tool设置同步事件接收对象 // 如果是Tool中的Value接口,需要绑定变更的回调函数(针对dll中的变量接口) if (pTool->pDllPtr != nullptr) { pTool->pDllPtr->setSyncTarget(g_pUiManager); // UI->Value单向同步:信息存储至UiManager统一处理 // VALUE& value = pTool->pDllPtr->Interface(pDllInf->nIndex).value; // g_pUiManager->bindValueWithUiControl(pDllInf, m_pControlObject->m_pWidget); } else { // TODO: 此处缺一个设置event target的位置(针对局部变量和全局变量) // VALUE& value = pDllInf->value; } pInf->bDataLink = true; g_pUiManager->bindValueWithUiControl(pInf, pVControl->m_pWidget); vDebug() << "Bind [" << pInf->strFullName << "] " << " - " << pVControl->m_pWidget; return true; } /// /// 解绑数值接口的绑定信息(有可能是Dll接口,有可能是数值类型,数值可对应多个UI控件) /// /// /// /// /// bool UiManager::unbindSyncByValue(TOOL* pTool, _INTERFACE* pInf, VControlObject* pVControl) { Q_UNUSED(pTool); // 引用计数 - 1 pInf->nRefCount--; pInf->bDataLink = false; g_pUiManager->unbindValueWithUiControl(pInf, pVControl->m_pWidget); vDebug() << "Unbind [" << pInf->strFullName << "] - " << pVControl->m_pWidget; return true; } /// /// 绑定dll中的信息用于后续同步(复杂类型,暂未绑定,仅引用计数 + 1) /// /// /// /// bool UiManager::bindSyncByComplex(TOOL* pTool, _INTERFACE* pDllInf) { Q_UNUSED(pTool); if (pDllInf->Direction == INF_DIRECTION::INF_DIR_IN && pDllInf->nRefCount > 0) { vDebug() << ("Error: Interface[" + pDllInf->strNameWithType + "] ref count >0 : " + pDllInf->nRefCount + "."); return false; } // 引用计数 + 1 pDllInf->nRefCount++; return true; } /// /// 2022-9-13 解绑dll中的信息(复杂类型,暂未绑定,仅引用计数 - 1) /// /// /// /// bool UiManager::unbindSyncByComplex(TOOL* pTool, _INTERFACE* pDllInf) { Q_UNUSED(pTool); if (pDllInf->Direction == INF_DIRECTION::INF_DIR_IN && pDllInf->nRefCount > 0) { vDebug() << ("Error: Interface[" + pDllInf->strNameWithType + "] ref count >0 : " + pDllInf->nRefCount + "."); return false; } // 引用计数 - 1 pDllInf->nRefCount--; return true; } /// /// 还原反序列化中控件的DataLink关系(简单控件) /// /// /// bool UiManager::restoreDataLinks(const CONTROL_PROPERTY& prop, VControlObject* pUiControl) { if (prop.m_DataLink.isValid()) { this->bindDataLinkSyncInformation(prop.m_DataLink, pUiControl); } return true; } /// /// 还原反序列化中控件的DataLink关系(复杂控件) /// /// /// bool UiManager::restoreDataLinks(const CONTROL_PROPERTY_EX& propex, VControlObject* pUiControl) { bool bRet = true; // 索引链接 this->bindDataLinkSyncInformation(propex.m_refreshLink, pUiControl); // 主数据链接 for (const DataLink& dataLink : propex.m_mainDataLinks) { if (dataLink.isValid()) { this->bindDataLinkSyncInformation(dataLink, pUiControl); } else { qDebug() << ("[Error] UiManager::restoreDataLinks - Property datalink[" + dataLink.title + "] invalid."); bRet = false; } } // 子分组中的数据链接 for (int i = 0; i < propex.m_groups.size(); i++) { const PROPERTY_EX_SUBGROUPS& subGroups = propex.m_groups[i].subGroups; for (int j = 0; j < subGroups.size(); j++) { for (const DataLink& dataLink : subGroups[j].dataLinks) { if (dataLink.isValid()) { this->bindDataLinkSyncInformation(dataLink, pUiControl); } else { qDebug() << ("[Error] UiManager::restoreDataLinks - Property datalink[" + dataLink.title + "] invalid."); bRet = false; } } } } return bRet; } /// /// 用于Dll中的控件事件触发回调(dll中的控件向UI界面同步) /// /// /// void UiManager::syncFromDll(QWidget* pDllControl, UI_SYNC_MSG msg) { if (pDllControl == nullptr) { qWarning() << "[Error] UiManager::syncFromDll - pDllControl is nullptr."; return; } // 根据不同的消息执行不同的处理 if (m_DllToUiControls.contains(pDllControl)) { QWidget* pUiWidget = m_DllToUiControls.value(pDllControl); bool bRet = false; switch (msg) { case UI_SYNC_MSG::EDIT_TEXT_CHANGED: { QLineEdit* pDllEdit = qobject_cast(pDllControl); VLineEdit* pVEdit = qobject_cast(pUiWidget); bRet = syncEditControl(pDllEdit, pVEdit, SYNC_MODE::FROM_DLL); if (bRet) { qDebug() << "UiManager::syncFromDll - VLineEdit:" << pVEdit->text(); } } break; case UI_SYNC_MSG::COMBO_SEL_CHANGED: { QComboBox* pDllCombo = qobject_cast(pDllControl); VComboBox* pVCombo = qobject_cast(pUiWidget); bRet = syncComboControl(pDllCombo, pVCombo, SYNC_MODE::FROM_DLL); if (bRet) { qDebug() << "UiManager::syncFromDll - VComboBox:" << pVCombo->currentIndex(); } } break; case UI_SYNC_MSG::LIST_SEL_CHANGED: { QListWidget* pDllList = qobject_cast(pDllControl); VListBox* pVList = qobject_cast(pUiWidget); bRet = syncListControl(pDllList, pVList, SYNC_MODE::FROM_DLL); qDebug() << "UiManager::syncFromDll - VListBox:" << pDllList->currentRow(); } break; case UI_SYNC_MSG::RADIOBOX_CHANGED: { QRadioButton* pDllRadio= qobject_cast(pDllControl); VRadioBox* pVRadio = qobject_cast(pUiWidget); //// 首次同步需要把名字也复制一下 //if (bFirst) //{ // pVRadio->setText(pDllRadio->text()); //} pVRadio->setChecked(pDllRadio->isChecked()); qDebug() << "UiManager::syncFromDll - VRadioBox:" << pDllRadio->isChecked(); } break; case UI_SYNC_MSG::CHECKBOX_CHANGED: { QCheckBox* pDllCheck = qobject_cast(pDllControl); VCheckBox* pVCheck = qobject_cast(pUiWidget); //// 首次同步需要把名字也复制一下 //if (bFirst) //{ // pVCheck->setText(pDllCheck->text()); //} pVCheck->setCheckState(pDllCheck->checkState()); qDebug() << "UiManager::syncFromDll - VCheckBox:" << pDllCheck->checkState(); } break; default: { qWarning() << "UiManager::syncFromDll - Unknown sync message : " << (int)msg; } break; } // 同步完后,通知UI界面刷新此控件(同时更新属性表) if (m_AllControls.contains(pUiWidget)) { m_AllControls.value(pUiWidget)->uiScene()->refreshControl(pUiWidget); } } } /// /// 用于UI界面向Dll中的控件同步 /// /// /// void UiManager::syncToDll(QWidget* pUiControl, UI_SYNC_MSG msg) { // 根据不同的消息执行不同的处理 if (m_UiToDllControls.contains(pUiControl)) { bool bRet = false; switch (msg) { case UI_SYNC_MSG::EDIT_TEXT_CHANGED: { VLineEdit* pVEdit = qobject_cast(pUiControl); QLineEdit* pDllEdit = qobject_cast(m_UiToDllControls.value(pUiControl)); // pDllEdit->setText(pVEdit->text()); bRet = syncEditControl(pVEdit, pDllEdit, SYNC_MODE::TO_DLL); if (bRet) { qDebug() << "UiManager::syncToDll - QLineEdit:" << pVEdit->text(); } } break; case UI_SYNC_MSG::COMBO_SEL_CHANGED: { VComboBox* pUi = qobject_cast(pUiControl); QComboBox* pDll = qobject_cast(m_UiToDllControls.value(pUiControl)); bRet = syncComboControl(pUi, pDll, SYNC_MODE::TO_DLL); if (bRet) { qDebug() << "UiManager::syncToDll - QComboBox:" << pDll->currentIndex(); } } break; case UI_SYNC_MSG::LIST_SEL_CHANGED: { VListBox* pUi = qobject_cast(pUiControl); QListWidget* pDll = qobject_cast(m_UiToDllControls.value(pUiControl)); bRet = syncListControl(pUi, pDll, SYNC_MODE::TO_DLL); if (bRet) { qDebug() << "UiManager::syncToDll - QListWidget:" << pDll->currentRow(); } } break; case UI_SYNC_MSG::RADIOBOX_CHANGED: break; case UI_SYNC_MSG::CHECKBOX_CHANGED: break; default: { qWarning() << "UiManager::syncToDll - Unknown sync message : " << (int)msg; } break; } } else { //qWarning() << "UiManager::syncToDll - Error : Can't find this control - " << pControl->getText(); } } /// /// 刚绑定时,从dll向UI做一次同步 /// /// void UiManager::syncFromDllFirst(QWidget* pDllControl, VControlObject* pUiControl) { // 根据同步控件的类型执行不同的同步动作 VALUE_TYPE controlType = pUiControl->m_Type; // 逐步增加如下需要同步的类型 switch (controlType) { case VALUE_TYPE::Control_LineEdit: { QLineEdit* pDllEdit = qobject_cast(pDllControl); VLineEdit* pVEdit = qobject_cast(pUiControl->m_pWidget); bool bRet = syncEditControl(pDllEdit, pVEdit, SYNC_MODE::FROM_DLL, true); if (bRet) { qDebug() << "UiManager::syncFromDllFirst - VLineEdit:" << pVEdit->text(); } } //this->syncFromDll(pDllControl, UI_SYNC_MSG::EDIT_TEXT_CHANGED, true); break; case VALUE_TYPE::Control_ComboBox: { QComboBox* pDll= qobject_cast(pDllControl); VComboBox* pUi = qobject_cast(pUiControl->m_pWidget); bool bRet = syncComboControl(pDll, pUi, SYNC_MODE::FROM_DLL, true); if (bRet) { qDebug() << "UiManager::syncFromDllFirst - VComboBox:" << pUi->currentIndex(); } } //this->syncFromDll(pDllControl, UI_SYNC_MSG::COMBO_SEL_CHANGED, true); break; case VALUE_TYPE::Control_RadioBox: { } //this->syncFromDll(pDllControl, UI_SYNC_MSG::RADIOBOX_CHANGED, true); break; case VALUE_TYPE::Control_CheckBox: { } //this->syncFromDll(pDllControl, UI_SYNC_MSG::CHECKBOX_CHANGED, true); break; case VALUE_TYPE::Control_Listbox: { QListWidget* pDll = qobject_cast(pDllControl); VListBox* pUi = qobject_cast(pUiControl->m_pWidget); bool bRet = syncListControl(pDll, pUi, SYNC_MODE::FROM_DLL, true); if (bRet) { qDebug() << "UiManager::syncFromDllFirst - VListBox:" << pUi->currentIndex(); } } //this->syncFromDll(pDllControl, UI_SYNC_MSG::LIST_SEL_CHANGED, true); break; default: break; } } /// /// 用于Runtime界面向UI中的控件同步 /// /// /// void UiManager::syncFromRuntime(QWidget* pRtControl, UI_SYNC_MSG msg) { if (m_RtToUiControls.contains(pRtControl)) { QWidget* pUiWidget = m_RtToUiControls.value(pRtControl); bool bRet = false; switch (msg) { case UI_SYNC_MSG::EDIT_TEXT_CHANGED: { QLineEdit* pRtEdit = qobject_cast(pRtControl); QLineEdit* pUiEdit = qobject_cast(pUiWidget); bRet = syncEditControl(pRtEdit, pUiEdit, SYNC_MODE::FROM_RUNTIME, false); if (bRet) { qDebug() << "UiManager::syncFromRuntime - QLineEdit:" << pRtEdit->text(); } } break; case UI_SYNC_MSG::COMBO_SEL_CHANGED: { QComboBox* pRt= qobject_cast(pRtControl); QComboBox* pUi = qobject_cast(pUiWidget); bRet = syncComboControl(pRt, pUi, SYNC_MODE::FROM_RUNTIME, false); if (bRet) { qDebug() << "UiManager::syncFromRuntime - QComboBox:" << pUi->currentIndex(); } } break; case UI_SYNC_MSG::LIST_SEL_CHANGED: { QListWidget* pRt = qobject_cast(pRtControl); QListWidget* pUi = qobject_cast(pUiWidget); bRet = syncListControl(pRt, pUi, SYNC_MODE::FROM_RUNTIME, false); if (bRet) { qDebug() << "UiManager::syncFromRuntime - QListWidget:" << pUi->currentRow(); } } break; case UI_SYNC_MSG::RADIOBOX_CHANGED: { } break; case UI_SYNC_MSG::CHECKBOX_CHANGED: { } break; case UI_SYNC_MSG::VALUE_CHANGED: { QLineEdit* pRt = qobject_cast(pRtControl); QLineEdit* pUi = qobject_cast(pUiWidget); bRet = syncValueControl(pRt, pUi, SYNC_MODE::TO_RUNTIME); if (bRet) { qDebug() << "UiManager::syncFromRuntime - ValueControl:" << pUi->text(); } } break; default: { qWarning() << "UiManager::syncFromRuntime - Unsupported msg : " << (int)msg; } break; } // 同步完后,通知UI界面刷新此控件(同时更新属性表) // 2022-9-15,只有数据有变动的时候才需要刷新 if (bRet && m_AllControls.contains(pUiWidget)) { m_AllControls.value(pUiWidget)->uiScene()->refreshControl(pUiWidget); } } else { //qWarning() << "UiManager::syncFromRuntime - Error : Can't find this control."; } } /// /// 用于UI向Runtime界面中的控件同步 /// /// /// void UiManager::syncToRuntime(QWidget* pUiControl, UI_SYNC_MSG msg, bool bFirst) { // qDebug() << "UiManager::syncToRuntime - msg:" << (int)msg; if (m_UiToRtControls.contains(pUiControl)) { bool bRet = false; switch (msg) { case UI_SYNC_MSG::EDIT_TEXT_CHANGED: { QLineEdit* pUiEdit = qobject_cast(pUiControl); QLineEdit* pRtEdit = qobject_cast(m_UiToRtControls.value(pUiControl)); bRet = syncEditControl(pUiEdit, pRtEdit, SYNC_MODE::TO_RUNTIME, bFirst); if (bRet) { qDebug() << "UiManager::syncToRuntime - QLineEdit:" << pRtEdit->text(); } } break; case UI_SYNC_MSG::COMBO_SEL_CHANGED: { QComboBox* pUiCombo = qobject_cast(pUiControl); QComboBox* pRtCombo = qobject_cast(m_UiToRtControls.value(pUiControl)); bRet = syncComboControl(pUiCombo, pRtCombo, SYNC_MODE::TO_RUNTIME, bFirst); if (bRet) { qDebug() << "UiManager::syncToRuntime - QComboBox:" << pRtCombo->currentIndex(); } } break; case UI_SYNC_MSG::LIST_SEL_CHANGED: { QListWidget* pUi = qobject_cast(pUiControl); QListWidget* pRt= qobject_cast(m_UiToRtControls.value(pUiControl)); // 首次同步需要同步一下所有的选择项 if (bFirst) { for (int i = 0; i < pUi->count(); i++) { pRt->insertItem(i, pUi->item(i)->text()); } } pRt->setCurrentRow(pUi->currentRow()); qDebug() << "UiManager::syncToRuntime - VListBox:" << pRt->currentRow(); } break; case UI_SYNC_MSG::RADIOBOX_CHANGED: { QRadioButton* pUi = qobject_cast(pUiControl); QRadioButton* pRt = qobject_cast(m_UiToRtControls.value(pUiControl)); //// 首次同步需要把名字也复制一下 //if (bFirst) //{ // pRt->setText(pUi->text()); //} pRt->setChecked(pUi->isChecked()); qDebug() << "UiManager::syncToRuntime - VRadioBox:" << pRt->isChecked(); } break; case UI_SYNC_MSG::CHECKBOX_CHANGED: { QCheckBox* pUi = qobject_cast(pUiControl); QCheckBox* pRt = qobject_cast(m_UiToRtControls.value(pUiControl)); //// 首次同步需要把名字也复制一下 //if (bFirst) //{ // pRt->setText(pUi->text()); //} pRt->setCheckState(pUi->checkState()); qDebug() << "UiManager::syncToRuntime - VCheckBox:" << pRt->checkState(); } break; case UI_SYNC_MSG::VALUE_CHANGED: { QLineEdit* pUi = qobject_cast(pUiControl); QLineEdit* pRt = qobject_cast(m_UiToRtControls.value(pUiControl)); bRet = syncValueControl(pUi, pRt, SYNC_MODE::TO_RUNTIME); if (bRet) { qDebug() << "UiManager::syncToRuntime - ValueControl:" << pRt->text(); } } break; default: break; } } else { //qWarning() << "UiManager::syncToRuntime - Error : Can't find this control."; } } /// /// 用于数值变更触发回调(只有ValueControl可以关联数值) /// /// void UiManager::syncFromValue(VARIABLE* pInf) { // 根据不同的数值类型进行不同的转换 if (m_ValueToUiControls.contains(pInf)) { QList pWidgets = m_ValueToUiControls.values(pInf); // 遍历所有与此Value关联的控件,逐一更新 for (QWidget* pUiWidget : pWidgets) { QString strValueText = pInf->getValueString(); vDebug() << pUiWidget << " - syncFromValue [" << pInf->strName << "](" << strValueText << ")."; // 同步到ValueControl this->syncValueControl(pUiWidget, strValueText, pInf->value.type, SYNC_MODE::FROM_VALUE); // 同步完后,通知UI界面刷新此控件(同时更新属性表) // 2022-5-22 此处在多个属性表同时高速刷新时,会造成控件多个属性表之间切换,所以临时屏蔽。 //if (m_AllControls.contains(pUiWidget)) //{ // m_AllControls.value(pUiWidget)->refreshControl(pUiWidget); //} } } else { //qWarning() << "UiManager::syncFromValue - Error : Can't find this value."; } } /// /// 用于UI变更向数值单向同步 /// /// void UiManager::syncToValue(QWidget* pUiControl) { if (m_UiControlToValues.contains(pUiControl)) { VARIABLE* linkValue = m_UiControlToValues.value(pUiControl); QString className = pUiControl->metaObject()->className(); QString strValue; if (className == CLASS_NAME_VALUECONTROL) { ValueControl* pVControl = qobject_cast(pUiControl); if (pVControl != nullptr) { strValue = pVControl->text(); } } else if (className == CLASS_NAME_RESULT) { VResult* pVControl = qobject_cast(pUiControl); if (pVControl != nullptr) { strValue = pVControl->text(); } } // 2021-11-2增加,如果对应的接口是一个输出接口,那么忽略这个赋值(输出接口不允许从UI输入) if (linkValue->Direction == INF_DIRECTION::INF_DIR_OUT) { qDebug() << "UiManager::syncToValue - ignore: this LinkValue is INF_DIR_OUT."; return; } // 直接将字符串拷贝过去 //QString strValue = pVControl->toPlainText(); //linkValue->setValue(strValue); // 根据不同的数值类型进行不同的转换 bool bRet = false; switch (linkValue->value.type) { case VALUE_TYPE::Type_Int: { // 获取控件数值 int controlValue = strValue.toInt(); bRet = linkValue->setValue(controlValue); if (bRet) { // vDebug() << "Tpye:" << Utility::getTypeString(VALUE_TYPE::Type_Int) << " value:" << controlValue; vDebug() << pUiControl << " - syncToValue [" << linkValue->strName << "](" << controlValue << ")."; } } break; default: { vDebug() << "[Error] : " << (int)linkValue->value.type; } break; } } else { //qWarning() << "UiManager::syncToValue - Error : Can't find this control."; } } /// /// 同步Edit控件 /// /// /// /// /// /// bool UiManager::syncEditControl(QLineEdit* pSrc, QLineEdit* pDst, SYNC_MODE mode, bool bFirst) { Q_UNUSED(bFirst); QString strSrc = pSrc->text(); QString strDst = pDst->text(); if (strDst != strSrc) { if (mode == SYNC_MODE::TO_DLL) { pDst->setText(strSrc); } else { VLineEdit* vEdit = qobject_cast(pDst); vEdit->setText(strSrc); } return true; } return false; } /// /// 同步Combo控件 /// /// /// /// /// /// bool UiManager::syncComboControl(QComboBox* pSrc, QComboBox* pDst, SYNC_MODE mode, bool bFirst /*= false*/) { Q_UNUSED(mode); // 首次同步需要同步Combo列表项 if (bFirst) { for (int i = 0; i < pSrc->count(); i++) { pDst->insertItem(i, pSrc->itemText(i)); } } int nIndexSrc = pSrc->currentIndex(); int nIndexDst = pDst->currentIndex(); if (nIndexDst != nIndexSrc) { pDst->setCurrentIndex(pSrc->currentIndex()); return true; } return false; } /// /// 同步list控件 /// /// /// /// /// /// bool UiManager::syncListControl(QListWidget* pSrc, QListWidget* pDst, SYNC_MODE mode, bool bFirst /*= false*/) { Q_UNUSED(mode); // 首次同步需要同步List列表项 if (bFirst) { for (int i = 0; i < pSrc->count(); i++) { pDst->insertItem(i, pSrc->item(i)->text()); } } int nIndexSrc = pSrc->currentRow(); int nIndexDst = pDst->currentRow(); if (nIndexDst != nIndexSrc) { pDst->setCurrentRow(nIndexSrc); return true; } return false; } /// /// 同步Value Control(数值) /// /// /// /// /// bool UiManager::syncValueControl(QWidget* pValueControl, QString strNewValue, VALUE_TYPE type, SYNC_MODE mode) { Q_UNUSED(mode); Q_UNUSED(type); if (pValueControl == nullptr) { return false; } QString className = pValueControl->metaObject()->className(); if (className == CLASS_NAME_VALUECONTROL) { ValueControl* pControl = qobject_cast(pValueControl); if (pValueControl == nullptr || pControl == nullptr) { return false; } QString strCurrentText = pControl->text(); // 如果文字相同则不更新了,防止消息死循环 if (strCurrentText == strNewValue) { return false; } // 设置新值 pControl->setText(strNewValue); } else if (className == CLASS_NAME_RESULT) { VResult* pControl = qobject_cast(pValueControl); if (pValueControl == nullptr || pControl == nullptr) { return false; } QString strCurrentText = pControl->text(); QString strCurrentTip = pControl->toolTip(); // 剔除掉 Tip 文本 strCurrentText = strCurrentText.replace(QRegExp(strCurrentTip + STRING_INTERVAL), ""); // 如果文字相同则不更新了,防止消息死循环 if (strCurrentText == strNewValue) { return false; } // 设置新值 pControl->setText(strCurrentTip + STRING_INTERVAL + strNewValue); //pControl->setText(strCurrentTip); } else { return false; } //if (mode == SYNC_MODE::FROM_VALUE) //{ // qDebug() << "UiManager::syncFromValue - tpye:" << Utility::getTypeString(type) << " value:" // << strNewValue << " toControl:" << pControl->m_pWidget; //} //else if (mode == SYNC_MODE::TO_VALUE) //{ // qDebug() << "UiManager::syncToValue - tpye:" << Utility::getTypeString(type) << " value:" // << strNewValue << " fromControl:" << pControl->m_pWidget;; //} return true; } /// /// 同步Value Control(控件) /// /// /// /// /// bool UiManager::syncValueControl(QLineEdit* pSrc, QLineEdit* pDst, SYNC_MODE mode) { Q_UNUSED(mode); QString strSrc = pSrc->text(); QString strDst = pDst->text(); if (strDst != strSrc) { if (mode == SYNC_MODE::TO_DLL) { pDst->setText(strSrc); } else { QString className = pDst->metaObject()->className(); if (className == CLASS_NAME_VALUECONTROL) { ValueControl* pVControl = qobject_cast(pDst); if (pVControl != nullptr) { pVControl->setText(strSrc); } } else if (className == CLASS_NAME_RESULT) { VResult* pVControl = qobject_cast(pDst); if (pVControl != nullptr) { pVControl->setText(strSrc); } } else { return false; } } return true; } return false; } ///// ///// 删除所有UI ///// //void UiManager::deleteAllUIs() //{ // //} /// /// 重置所有UI页面以及数据结构(用于反序列化使用) /// void UiManager::reset() { m_pMainPage = nullptr; m_pAllPages.clear(); m_AllControls.clear(); m_DllToUiControls.clear(); m_UiToDllControls.clear(); m_UiToRtControls.clear(); m_RtToUiControls.clear(); m_UiControlToValues.clear(); m_ValueToUiControls.clear(); } /// /// 2022-2-12 根据控件指针查找对应的WindowAppUiView指针 /// /// /// WindowAppUiView* UiManager::getViewByControl(VControlObject* pUiControl) { return m_AllControls.value(pUiControl->m_pWidget); } /// /// 刷新指定控件的选中效果(用于适配geometry的实时更新) /// /// void UiManager::refreshControlDrawPoint(VControlObject* pUiControl) { WindowAppUiView* pUiView = m_AllControls.value(pUiControl->m_pWidget); if (pUiView) { pUiView->uiScene()->refreshDrawPoint(pUiControl->m_pWidget); } } /// /// 2022-2-10 从DataLink中解析Tool信息 /// /// /// /// /// void UiManager::parsePouToolFromDataLink( const DataLink& dataLink, POU*& pPou, TOOL*& pTool, _INTERFACE*& pDllInf ) { pPou = nullptr; pTool = nullptr; pDllInf = nullptr; if (dataLink.value.size() < 3) { return; } // 从DataLink信息中解析出接口信息 QString strCategory = dataLink.value.at(0); QString strCmd = dataLink.value.at(1); QString strDetail = dataLink.value.at(2); // 2021-10-28 解析需要处理局部和全局变量 bool bBindVariables = false; if (strCmd.indexOf(GROUP_GLOBAL_VARIABLE) >= 0 || strCmd.indexOf(GROUP_LOCAL_VARIABLE) >= 0) { bBindVariables = true; } // Tool接口 if (!bBindVariables) { // 根据名字找到对应的_INTERFACE* pPou = g_pPouManager->getPouByName(strCategory); if (pPou != nullptr) { pTool = pPou->GetToolByName(strCmd); if (pTool != nullptr) { pDllInf = pTool->getInterfaceByName(strDetail); } else { qWarning() << "GetToolByName " << strCmd << " Error"; } } } // 局部和全局变量 else { strCategory.remove(VAR_SUFFIX); strCmd = strCategory; pTool = g_pGvlManager->getGvl(strCmd); pDllInf = pTool->getInterfaceByName(strDetail); } } /// /// 2022-2-10 从DataLink中解析Interface信息 /// /// /// void UiManager::parseToolInfFromDataLink( const DataLink& dataLink, _INTERFACE*& pDllInf) { POU* pPou = nullptr; TOOL* pTool = nullptr; pDllInf = nullptr; this->parsePouToolFromDataLink(dataLink, pPou, pTool, pDllInf); }