123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736 |
- #include "WindowRuntimeView.h"
- #include "WindowAppUiView.h"
- #include "WindowAppUiScene.h"
- #include "WindowRuntime.h"
- #include "selectwidget.h"
- #include "PouManager.h"
- #include "UiManager.h"
- #include "GvlManager.h"
- #include "VPControls.h"
- WindowRuntimeView::WindowRuntimeView(QWidget *parent)
- : QWidget(parent)
- {
- // 初始化Logo贴图
- this->initLogoImage();
- }
- WindowRuntimeView::~WindowRuntimeView()
- {
- }
- /// <summary>
- /// 从设计页面中拷贝,并且建立Runtime和UI、Dll的三方消息同步
- /// </summary>
- /// <param name="pDesignView"></param>
- /// <returns></returns>
- bool WindowRuntimeView::copyFrom(WindowAppUiView* pDesignView)
- {
- m_pControls = pDesignView->uiScene()->getAllControls();
- // 枚举该UI页面中的所有的控件,照着复制一份到Runtime窗体中
- // 创建控件时,要留出左侧的基础宽度 APP_RM_WIDTH
- for (SelectWidget* pUiWidget : m_pControls)
- {
- QWidget* pNewControl = nullptr;
- // 获取控件位置和尺寸
- QPoint ptPos = pUiWidget->pos();
- //ptPos.setX(ptPos.x());
- //int nWidth = pUiWidget->width();
- //int nHeight = pUiWidget->height();
- QSize controlSize = pUiWidget->size();
- // 解析扩展属性是否成功(仅用于复杂控件)
- bool bPasrseOk = true;
- if (pUiWidget->m_pProperty == nullptr)
- {
- qWarning() << "[Error] in WindowRuntimeView::copyFrom() - m_pProperty in selectWidget is nullptr.";
- continue;
- }
- // 根据不同类型创建不同的控件实例
- switch (pUiWidget->m_Type)
- {
- case VALUE_TYPE::Control_Label:
- {
- pNewControl = new VLabel(this, ptPos, controlSize, pUiWidget->m_pProperty);
- }
- break;
- case VALUE_TYPE::Control_Button:
- {
- pNewControl = new VButton(this, ptPos, controlSize, pUiWidget->m_pProperty);
- // 绑定点击信号
- // 绑定信号的目的是为了做控件的三方同步
- connect(pNewControl, SIGNAL(clicked()), this, SLOT(slotControlClickedDispatcher()));
- }
- break;
- case VALUE_TYPE::Control_CheckBox:
- {
- pNewControl = new VCheckBox(this, ptPos, controlSize, pUiWidget->m_pProperty);
- // 绑定CheckBox变动信号
- connect(pNewControl, SIGNAL(stateChanged(int)), this, SLOT(onVCheckChanged(int)));
- }
- break;
- case VALUE_TYPE::Control_RadioBox:
- {
- pNewControl = new VRadioBox(this, ptPos, controlSize, pUiWidget->m_pProperty);
- // 绑定RadioBox变动信号
- connect(pNewControl, SIGNAL(toggled(bool)), this, SLOT(onVRadioChanged(bool)));
- }
- break;
- case VALUE_TYPE::Control_Groupbox:
- {
- pNewControl = new VGroupBox(this, ptPos, controlSize, pUiWidget->m_pProperty);
- }
- break;
- case VALUE_TYPE::Control_LineEdit:
- {
- pNewControl = new VLineEdit(this, ptPos, controlSize, pUiWidget->m_pProperty);
- // 注册文字变更消息用于反向同步
- connect(pNewControl, SIGNAL(textChanged(QString)), this, SLOT(onVEditChanged(QString)));
- }
- break;
- case VALUE_TYPE::Control_Listbox:
- {
- pNewControl = new VListBox(this, ptPos, controlSize, pUiWidget->m_pProperty);
- // 绑定ListBox变动信号
- connect(pNewControl, SIGNAL(currentRowChanged(int)), this, SLOT(onVListChanged(int)));
- }
- break;
- case VALUE_TYPE::Control_ComboBox:
- {
- pNewControl = new VComboBox(this, ptPos, controlSize, pUiWidget->m_pProperty);
- // 绑定ComboBox变动信号
- connect(pNewControl, SIGNAL(currentIndexChanged(int)), this, SLOT(onVComboChanged(int)));
- }
- break;
- case VALUE_TYPE::Control_Value:
- {
- pNewControl = new ValueControl(this, ptPos, controlSize, pUiWidget->m_pProperty);
- // 注册文字变更消息用于反向同步
- connect(pNewControl, SIGNAL(textChanged(QString)), this, SLOT(onValueControlChanged(QString)));
- }
- break;
- case VALUE_TYPE::Control_Result:
- {
- pNewControl = new VResult(this, ptPos, controlSize, pUiWidget->m_pProperty);
- }
- break;
- case VALUE_TYPE::Control_PieChart:
- {
- if (pUiWidget->m_pPropertyEx == nullptr)
- {
- qWarning() << "[Error] in WindowRuntimeView::copyFrom() - Control_PieChart m_pPropertyEx in selectWidget is nullptr.";
- continue;
- }
- pNewControl = new VPieChart(
- this,
- ptPos,
- controlSize,
- pUiWidget->m_pProperty,
- pUiWidget->m_pPropertyEx
- );
- // 解析传入的复杂控件属性
- bPasrseOk = this->parseComplexPropertyEx(pNewControl, pUiWidget->m_pPropertyEx);
- }
- break;
- case VALUE_TYPE::Control_CustomPlot:
- {
- if (pUiWidget->m_pPropertyEx == nullptr)
- {
- qWarning() << "[Error] in WindowRuntimeView::copyFrom() - Control_PieChart m_pPropertyEx in selectWidget is nullptr.";
- continue;
- }
- pNewControl = new VCustomPlot(
- this,
- ptPos,
- controlSize,
- pUiWidget->m_pProperty,
- pUiWidget->m_pPropertyEx
- );
- // 2021-12-15 对于复杂控件还需要额外解析扩展属性
- bPasrseOk = this->parseComplexPropertyEx(pNewControl, pUiWidget->m_pPropertyEx);
- }
- break;
- case VALUE_TYPE::Control_Table:
- {
- if (pUiWidget->m_pPropertyEx == nullptr)
- {
- qWarning() << "[Error] in WindowRuntimeView::copyFrom() - Control_Table m_pPropertyEx in selectWidget is nullptr.";
- continue;
- }
- pNewControl = new VTableControl(
- this,
- ptPos,
- controlSize,
- pUiWidget->m_pProperty,
- pUiWidget->m_pPropertyEx
- );
- // 2021-12-15 对于复杂控件还需要额外解析扩展属性
- bPasrseOk = this->parseComplexPropertyEx(pNewControl, pUiWidget->m_pPropertyEx);
- }
- break;
- case VALUE_TYPE::Control_Image:
- {
- if (pUiWidget->m_pPropertyEx == nullptr)
- {
- qWarning() << "[Error] in WindowRuntimeView::copyFrom() - Control_Image m_pPropertyEx in selectWidget is nullptr.";
- continue;
- }
- pNewControl = new VImageControl(
- this,
- ptPos,
- controlSize,
- pUiWidget->m_pProperty,
- pUiWidget->m_pPropertyEx,
- true
- );
- // 解析传入的复杂控件属性
- bPasrseOk = this->parseComplexPropertyEx(pNewControl, pUiWidget->m_pPropertyEx);
- }
- break;
- default:
- {
- qWarning() << "[Runtime] WindowRuntime::runPage - invalid control type:" << static_cast<short>(pUiWidget->m_Type);
- continue;
- }
- // return false;
- }
- // 创建控件失败
- if (pNewControl == nullptr)
- {
- qWarning() << "[Error] WindowRuntimeView::copyFrom - New control failed.";
- continue;
- }
- // 解析扩展属性失败(仅用于复杂控件)
- if (!bPasrseOk)
- {
- QString str = pUiWidget->m_pPropertyEx->m_strTitle + "[" + pUiWidget->m_pProperty->m_strText + "]";
- qWarning() << "[Error] WindowRuntimeView::copyFrom - " << str << "parseComplexPropertyEx() failed.";
- continue;
- }
- // 绑定UI控件和Runtime控件对应关系用于同步
- // MEMO:此处对于复杂控件也进行了绑定,但是此处暂时是不需要的
- // 因为复杂控件不需要UI向Runtime设计中实时同步,而是直接从数据源触发更新
- g_pUiManager->bindUiControlWithRtControl(pUiWidget->m_pWidget, pNewControl);
- // 执行控件的首次同步
- // 简单控件
- if (pUiWidget->m_pPropertyEx == nullptr)
- {
- this->doFirstSync(pUiWidget->m_pWidget, pUiWidget->m_Type, nullptr);
- }
- // 复杂控件
- else
- {
- VARIABLE* pVariable = pUiWidget->m_pPropertyEx->m_refreshLink.linkValue;
- this->doFirstSync(
- pUiWidget->m_pWidget,
- pUiWidget->m_Type,
- pVariable
- );
- }
- //pNewControl->resize(controlSize);
- //pNewControl->move(ptPos);
- }
- return true;
- }
- /// <summary>
- /// 初始化Logo贴图
- /// </summary>
- void WindowRuntimeView::initLogoImage()
- {
- m_pLogoImage = new QPixmap(64, 64);
- QString strPath = QCoreApplication::applicationDirPath() + "/Logo.png";
- QFileInfo info(strPath);
- if (info.exists() != true)
- {
- strPath = "./image/logo64.png";
- }
- m_pLogoImage->load(strPath);
- }
- /// <summary>
- /// 绘制界面背景
- /// </summary>
- /// <param name=""></param>
- void WindowRuntimeView::paintEvent(QPaintEvent*)
- {
- QRect rc = this->geometry();
- if (m_pControls.size() == 0)
- {
- // 绘制背景图片
- QString path = ":/image/background.png";
- QString strPath = QCoreApplication::applicationDirPath() + "/Desktop.bmp";
- QFileInfo info(strPath);
- if (info.exists() != true)
- {
- strPath = path;
- }
- QPixmap pixmap = QPixmap(strPath).scaled(this->size());
- QPalette palette(this->palette());
- //palette.setBrush(QPalette::Window, QBrush(pixmap));
- //this->setPalette(palette);
- QPainter painter(this);
- painter.drawImage(QRect(0, 0, this->width(), this->height()), pixmap.toImage());
- }
- // 在当前界面的右上角显示logo
- QPainter painter(this);
- painter.drawPixmap(rc.right() - 100, rc.top(), 64, 64, *m_pLogoImage);
- }
- /// <summary>
- /// 控件点击事件的总体调度
- /// </summary>
- void WindowRuntimeView::slotControlClickedDispatcher()
- {
- QObject* pSender = sender();
- QString strSenderClassName = pSender->metaObject()->className();
- qDebug() << "WindowRuntimeView::slotControlClicked()" << strSenderClassName;
- // 通过sender的类型来判断具体是哪个控件触发
- // 如果是Button类型
- if (strSenderClassName == CLASS_NAME_BUTTON)
- {
- onButtonClicked(qobject_cast<VButton*>(pSender));
- }
- else
- {
- qDebug() << "WindowRuntimeView::slotControlClickedDispatcher - Unknow sender class: " << strSenderClassName;
- }
- }
- /// <summary>
- /// VButton的点击处理
- /// </summary>
- /// <param name="pClickButton"></param>
- void WindowRuntimeView::onButtonClicked(VButton* pClickButton)
- {
- // 根据按钮的DataLink信息进行相应的处理
- const DataLink& dataLink = pClickButton->getDataLink();
- // 如果DataLink是空的则说明没设置数据连接
- if (dataLink.value.size() <= 0)
- {
- qDebug() << "WindowRuntimeView::onButtonClicked - dataLink is nullptr.";
- return;
- }
-
- // 解析按钮链接信息
- QString strCategory = dataLink.value.at(0);
- QString strCmd = dataLink.value.at(1);
- QString strDetail = dataLink.value.at(2);
- // 如果是系统命令
- if (strCategory == SYS_CMD_GROUP_NAME)
- {
- // 直接执行
- g_pRuntime->runCmd(strCmd, strDetail);
- }
- // 如果没有选择第三层级的内容,那么可能是选择了TOOL本身
- else if (strDetail.trimmed().isEmpty())
- {
- // 根据名字找到对应的TOOL*
- POU* pPou = g_pPouManager->getPouByName(strCategory);
- TOOL* pTool = pPou->GetToolByName(strCmd);
- if (pTool != nullptr)
- {
- // 弹出Tool中的对话框
- pTool->pDllPtr->ShowDialog();
- }
- else
- {
- QString strMsg = strCategory + "." + strCmd;
- qWarning() << strMsg << " is NULL";
- }
- }
- // 否则应该是Tool导出的Button接口
- else
- {
- // 交给父级统一处理
- g_pRuntime->runDllInterface(
- strCategory,
- strCmd,
- strDetail,
- pClickButton->m_Type
- );
- }
- }
- //=====================================================================
- //
- // 子控件同步相关
- //
- //=====================================================================
- /// <summary>
- /// 当Edit控件内容变更时
- /// </summary>
- /// <param name="strText"></param>
- void WindowRuntimeView::onVEditChanged(const QString& strText)
- {
- Q_UNUSED(strText);
- qDebug() << "WindowRuntimeView::onVEditChanged - " << strText;
- VLineEdit* pSender = qobject_cast<VLineEdit*>(sender());
- // 向UI同步
- g_pUiManager->syncFromRuntime(pSender, UI_SYNC_MSG::EDIT_TEXT_CHANGED);
- }
- /// <summary>
- /// ComboBox变更消息
- /// </summary>
- /// <param name="nIndex"></param>
- void WindowRuntimeView::onVComboChanged(const int nIndex)
- {
- Q_UNUSED(nIndex);
- qDebug() << "WindowRuntimeView::onVComboChanged - " << nIndex;
- VComboBox* pSender = qobject_cast<VComboBox*>(sender());
- // 向UI同步
- g_pUiManager->syncFromRuntime(pSender, UI_SYNC_MSG::COMBO_SEL_CHANGED);
- }
- /// <summary>
- /// ListBox变更消息
- /// </summary>
- /// <param name="nRow"></param>
- void WindowRuntimeView::onVListChanged(const int nRow)
- {
- Q_UNUSED(nRow);
- qDebug() << "WindowRuntimeView::onVListChanged - " << nRow;
- VListBox* pSender = qobject_cast<VListBox*>(sender());
- // 向UI同步
- g_pUiManager->syncFromRuntime(pSender, UI_SYNC_MSG::LIST_SEL_CHANGED);
- }
- /// <summary>
- /// RadioBox变更消息
- /// </summary>
- /// <param name="checked"></param>
- void WindowRuntimeView::onVRadioChanged(bool checked)
- {
- Q_UNUSED(checked);
- }
- /// <summary>
- /// CheckBox变更消息
- /// </summary>
- /// <param name="state"></param>
- void WindowRuntimeView::onVCheckChanged(int state)
- {
- Q_UNUSED(state);
- }
- /// <summary>
- /// 当Value控件内容变更时
- /// </summary>
- void WindowRuntimeView::onValueControlChanged(const QString& strText)
- {
- Q_UNUSED(strText);
- vDebug() << strText;
- ValueControl* pEdit = qobject_cast<ValueControl*>(sender());
- // 向UI同步
- g_pUiManager->syncFromRuntime(pEdit, UI_SYNC_MSG::VALUE_CHANGED);
- }
- /// <summary>
- /// 执行控件的首次同步
- /// </summary>
- /// <param name="pRtControl"></param>
- /// <param name="type"></param>
- void WindowRuntimeView::doFirstSync(QWidget* pUiControl, VALUE_TYPE controlType, const VARIABLE* pVariable)
- {
- if (pUiControl == nullptr)
- {
- return;
- }
- // 根据不同的类型执行首次同步
- switch (controlType)
- {
- case VALUE_TYPE::Control_ComboBox:
- g_pUiManager->syncToRuntime(pUiControl, UI_SYNC_MSG::COMBO_SEL_CHANGED, true);
- break;
- case VALUE_TYPE::Control_RadioBox:
- g_pUiManager->syncToRuntime(pUiControl, UI_SYNC_MSG::RADIOBOX_CHANGED, true);
- break;
- case VALUE_TYPE::Control_CheckBox:
- g_pUiManager->syncToRuntime(pUiControl, UI_SYNC_MSG::CHECKBOX_CHANGED, true);
- break;
- case VALUE_TYPE::Control_Listbox:
- g_pUiManager->syncToRuntime(pUiControl, UI_SYNC_MSG::LIST_SEL_CHANGED, true);
- break;
- case VALUE_TYPE::Control_LineEdit:
- g_pUiManager->syncToRuntime(pUiControl, UI_SYNC_MSG::EDIT_TEXT_CHANGED, true);
- break;
- // 2022-9-14 加入了ValueControl的首次同步
- case VALUE_TYPE::Control_Value:
- g_pUiManager->syncToRuntime(pUiControl, UI_SYNC_MSG::VALUE_CHANGED, true);
- break;
- case VALUE_TYPE::Control_Result:
- g_pUiManager->syncToRuntime(pUiControl, UI_SYNC_MSG::VALUE_CHANGED, true);
- break;
- case VALUE_TYPE::Control_Image:
- g_pRuntime->syncFromComplexSource(pVariable);
- break;
- default:
- break;
- }
- }
- //=====================================================================
- //
- // 复杂控件同步相关
- //
- //=====================================================================
- /// <summary>
- /// 解析复杂控件传入的扩展属性(用于执行扩展属性中的数值链接同步)
- /// </summary>
- /// <param name="propertyEx"></param>
- bool WindowRuntimeView::parseComplexPropertyEx(QWidget* pWidget, CONTROL_PROPERTY_EX* propertyEx)
- {
- VARIABLE* pValue = nullptr;
- DataLink dataLink;
- // 解析刷新索引值(索引值不允许defaultValue,所以此处如果刷新索引解析失败了则报错退出)
- bool bRet = this->parseDatalink(propertyEx->m_refreshLink, pValue);
- if (bRet)
- {
- g_pRuntime->registerNewIndex(pValue, pWidget);
- propertyEx->m_refreshLink.linkValue = pValue;
- vDebug() << "Bind refreshLink to [" << propertyEx->m_refreshLink.toString() << "].";
- }
- else
- {
- // TODO:这个默认值指针如果不传送出去的话,在execute的时候就触发不了(暂未启用)
- // g_pRuntime->registerNewIndex(propertyEx->m_refreshLink.defaultValue, pWidget);
- QString str = propertyEx->m_strTitle + "." + propertyEx->m_refreshLink.title;
- qWarning() << "[Error] WindowRuntimeView::parseComplexPropertyEx() -" << str << "Parse refreshLink failed.";
- return false;
- }
- // 解析主索引值(可能会有0个或者多个)
- for ( DataLink& dataLink : propertyEx->m_mainDataLinks )
- {
- bool bRet = this->parseDatalink(dataLink, pValue);
- if (bRet)
- {
- // 注册新的变量
- g_pRuntime->registerNewVariable(pWidget, dataLink.title, pValue);
- }
- // 错误
- else
- {
- qDebug() << "[Error] WindowRuntimeView::parseComplexPropertyEx() - Parse mainLink failed.";
- return false;
- }
- }
- // 解析其他数据链接数值(如果解析失败,直接用默认值)
- for (int i = 0; i < propertyEx->m_groups.size(); i++)
- {
- PROPERTY_EX_SUBGROUPS& subGroups = propertyEx->m_groups[i].subGroups;
- for (int j = 0; j < subGroups.size(); j++)
- {
- for (DataLink& dataLink : subGroups[j].dataLinks)
- {
- bool bRet = this->parseDatalink(dataLink, pValue);
- // 2022-1-18,如果没有解析成功,那么直接用默认值
- if (bRet)
- {
- // 在Runtime中保存 控件-接口 对应关系
- g_pRuntime->registerNewVariable(pWidget, dataLink.title, pValue);
- }
- // 默认值
- else
- {
- // 在Runtime中保存 控件-接口 对应关系
- g_pRuntime->registerNewVariable(pWidget, dataLink.title, dataLink.defaultValue);
- }
- }
- }
- }
- return true;
- }
- /// <summary>
- /// 解析Datalink信息
- /// </summary>
- /// <param name="dataLink"></param>
- /// <param name="pVar"></param>
- /// <returns></returns>
- bool WindowRuntimeView::parseDatalink(
- DataLink& dataLink,
- VARIABLE*& pVar
- )
- {
- // 2022-1-18,首先判断数据连接是否有效,因为有的数据链接不是强制赋值的
- // 到了这里可能会有直接录入数字的,或者留空的
- if (dataLink.value.size() != 3)
- {
- return false;
- }
- POU* pPou = nullptr;
- TOOL* pTool = nullptr;
- // 从DataLink信息中解析出接口信息
- QString strCategory = dataLink.value.at(0);
- QString strType = dataLink.value.at(1);
- QString strDetail = dataLink.value.at(2);
- // 判断变量源是来自于Tool还是来自于全局变量
- bool bVariables = false;
- if (strType.indexOf(GROUP_GLOBAL_VARIABLE) >= 0
- || strType.indexOf(GROUP_LOCAL_VARIABLE) >= 0)
- {
- bVariables = true;
- }
- // Tool接口
- if (!bVariables)
- {
- // 根据名字找到对应的_INTERFACE*
- pPou = g_pPouManager->getPouByName(strCategory);
- pTool = pPou->GetToolByName(strType);
- if (pTool)
- {
- pVar = pTool->getInterfaceByName(strDetail);
- if (pVar == nullptr)
- {
- QString str = strCategory + "." + strType;
- qWarning() << "[Error] Link To [" << str << "] Interface failed.";
- return false;
- }
- }
- else
- {
- return false;
- }
-
- }
- // 局部和全局变量
- else
- {
- strCategory.remove(VAR_SUFFIX);
- strType = strCategory;
- pTool = g_pGvlManager->getGvl(strType);
- pVar = pTool->getInterfaceByName(strDetail);
- if (pVar == nullptr)
- {
- QString str = strCategory + VAR_SUFFIX + "." + strDetail ;
- qWarning() << "[Error] Link To [" << str << "] Interface failed.";
- return false;
- }
- }
- //// 2022-1-18,变量在属性表中的属性名字(用于后续更新使用)
- //pVar->strPropertyName = dataLink.title;
- // 在dataLink中保存对应的VARIABLE*指针
- dataLink.linkValue = pVar;
- return true;
- }
|