#include "WindowRuntime.h" #include "WindowRuntimeView.h" #include "TaskManager.h" #include "PouManager.h" #include "vpControls/VTableControl.h" #include "vpControls/VPieChart.h" #include "vpControls/VCustomPlot.h" #include "vpControls/VImageControl.h" #define MAINPAGE_INDEX 0 WindowRuntime::WindowRuntime(QWidget *parent) : QMainWindow(parent) , m_pRuntimeViews(nullptr) { ui.setupUi(this); // 界面初始化 this->initUI(); // 注册本窗体 VPGlobal::Register(this); } WindowRuntime::~WindowRuntime() { } /// /// 界面初始化 /// void WindowRuntime::initUI() { this->setWindowFlags(Qt::Widget); if (1) { // 创建Stack式页面栈 m_pRuntimeViews = new QStackedWidget(); // 创建对应的发布页面 WindowRuntimeView* pNew = new WindowRuntimeView(m_pRuntimeViews); m_pRuntimeViews->addWidget(pNew); // 设置布局 QGridLayout* layout = new QGridLayout(); layout->setMargin(0); layout->setSpacing(0); layout->addWidget(m_pRuntimeViews); ui.centralWidget->setLayout(layout); } else { // TODO: RunTime 超过 UI的尺寸时,需要显示滚动条。 // TODO: RunTime 小于 UI的尺寸时,需要显示边框 ////////////////////////////////////////////////////////////////////////// QGridLayout* gridLayout = new QGridLayout(ui.centralWidget); m_pRuntimeViews = new QStackedWidget(ui.centralWidget); QWidget* page = new QWidget(); QGridLayout* gridLayout_3 = new QGridLayout(page); QScrollArea* scrollArea = new QScrollArea(page); // scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); // scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn); scrollArea->setWidgetResizable(true); QWidget* scrollAreaWidgetContents = new QWidget(); QGridLayout* gridLayout_2 = new QGridLayout(scrollAreaWidgetContents); WindowRuntimeView* pNew = new WindowRuntimeView(scrollAreaWidgetContents); ; gridLayout_2->addWidget(pNew, 0, 0, 1, 1); scrollArea->setWidget(scrollAreaWidgetContents); gridLayout_3->addWidget(scrollArea, 0, 0, 1, 1); m_pRuntimeViews->addWidget(page); gridLayout->addWidget(m_pRuntimeViews, 0, 0, 1, 1); pNew->setMinimumSize(QSize(80, 80)); } } /// /// 发布对应的页面 /// /// /// 标记当前页面是否是主页 /// bool WindowRuntime::publishPage(WindowAppUiView* pPage, bool bMainPage /* = false */) { // 确保首页是一定是第一个页面 if (bMainPage) { if (m_pRuntimeViews!=nullptr && m_pRuntimeViews->count() > 0) { CRITICAL_MESSAGE("Run main page [" + pPage->m_strPageName + "] error!"); return false; } // 新建StackWidget m_pRuntimeViews = new QStackedWidget(); ui.centralWidget->layout()->addWidget(m_pRuntimeViews); } // 创建新的Runtime页面添加到Stack中 WindowRuntimeView* pNewView = new WindowRuntimeView(m_pRuntimeViews); m_pRuntimeViews->addWidget(pNewView); // 保存页面序号 m_AllViews.insert(pPage->m_strPageName, m_pRuntimeViews->count() - 1); // 发布本页面中的所有控件 // 此处需要检查是否所有的控件都拷贝成功 bool bRet = pNewView->copyFrom(pPage); Q_UNUSED(bRet); return true; } /// /// 启动所有的UI界面(目前先只支持启动所有页面的方式) /// bool WindowRuntime::publishAllPages( WindowAppUiView* pMainPage, QMap allPages ) { // 首先执行数据结构重置 this->reset(); // 首先发布主页 bool bRet = publishPage(pMainPage, true); // 如果首页发布失败,则退出 if (!bRet) { return false; } // 根据每一个 WindowAppUiView 生成对应的页面,并且把所有的控件都分布上去 QMapIterator it(allPages); while (it.hasNext()) { WindowAppUiView* pPage = it.next().value(); if (pPage != pMainPage) { // 其余子页面暂时不检查返回值,如果发布失败则继续发布下一个页面 bRet = publishPage(pPage); } } // 页面全部发布完毕后,默认显示主页 if (m_pRuntimeViews!=nullptr && m_pRuntimeViews->count() > 0) { m_pRuntimeViews->setCurrentIndex(MAINPAGE_INDEX); } return true; } /// /// 执行指令 /// /// 命令名字 /// 命令参数 /// bool WindowRuntime::runCmd(const QString& strCmd, const QString& strParam /*= ""*/) { // 启动所有Task的执行 if (strCmd == SYS_CMD_TASK_RUN) { qDebug() << "[Command] runCmd - " << SYS_CMD_TASK_RUN; g_pTaskManager->executeAllTasks(false); } // 启动所有Task的执行一次 else if (strCmd == SYS_CMD_TASK_RUNONCE) { qDebug() << "[Command] runCmd - " << SYS_CMD_TASK_RUNONCE; g_pTaskManager->executeAllTasks(true); } // 停止所有任务 else if (strCmd == SYS_CMD_TASK_STOP) { qDebug() << "[Command] runCmd - " << SYS_CMD_TASK_STOP; g_pTaskManager->stopAllTask(false); } // 切换UI else if (strCmd == SYS_CMD_UI_SWITCH) { qDebug() << "[Command] runCmd - " << SYS_CMD_UI_SWITCH << " - " << strParam; g_pRuntime->switchToPage(strParam); } // 不应该执行到这里 else { qWarning() << "SystemCommand::runCmd - unknown command : " << strCmd; return false; } return true; } /// /// 执行Dll中的Tool Interface /// /// /// /// /// bool WindowRuntime::runDllInterface( const QString& strPouName, const QString& strToolName, const QString& strInfName, VALUE_TYPE controlType ) { // 首先根据名字找到Pou POU* pPou = g_pPouManager->getPouByName(strPouName); if (pPou == nullptr) { qWarning() << "[Error] in WindowRuntime::runDllInterface() - Invalid pou name : " << strPouName; return false; } // 然后找到对应的接口 QString strInfFullname = strToolName + "." + strInfName; _INTERFACE* pInf = pPou->GetInterface(strInfFullname); if (pInf == nullptr) { qWarning() << "[Error] in WindowRuntime::runDllInterface() - Invalid interface name : " << strInfFullname; return false; } // 根据不同的Runtime控件类型进行不同的处理 if (controlType == VALUE_TYPE::Control_Button) { // 获取dll中导出的控件指针 QPushButton* pInfButton = (QPushButton*)pInf->getValuePtr(); // 发送clicked信号 emit pInfButton->clicked(); return true; } else { qWarning() << "[Error] in WindowRuntime::runDllInterface() - Control type is not support : " << static_cast(controlType); return false; } } /// /// 系统命令,切换到指定页面 /// /// 2121 /// bool WindowRuntime::switchToPage(const QString& strPageName) { // 执行界面的切换 if (m_AllViews.contains(strPageName)) { int nPageIndex = m_AllViews[strPageName]; // 找到指定页面,并切换 m_pRuntimeViews->setCurrentIndex(nPageIndex); qDebug() << "WindowRuntime::switchToPage() - " << strPageName << " index: " << nPageIndex; return true; } // Error: 不应该执行到这里 else { qDebug() << "[Error] in WindowRuntime::switchToPage() - " << strPageName << ", but can;t find this page"; return false; } } //======================================================================== // // 变量同步相关代码 // //======================================================================== /// /// 接收来自变量到复杂控件单向同步的Event /// 备注:复杂控件是根据索引值绑定变量主动发起的event来触发更新的 /// /// void WindowRuntime::customEvent(QEvent* event) { // 如果是数值同步消息 if (event->type() == VALUE_EVENT_TYPEID) { qDebug() << "WindowRuntime::customEvent - VALUE_EVENT_TYPEID"; SyncValueEvent* pValueEvent = dynamic_cast (event); // 取出参数 QList syncValues = pValueEvent->getSyncValues(); for (VARIABLE* syncVal : syncValues) { // 从变量中同步 this->syncFromComplexSource(syncVal); } } else { QEvent::Type type = event->type(); qWarning() << "WindowRuntime::customEvent Type:" < /// 添加一个新的索引和控件对应关系 /// /// /// void WindowRuntime::registerNewIndex(VARIABLE* pIndex, QWidget* pControl) { if (pIndex == nullptr || pControl == nullptr) { return; } // 为接口设置索引标识 pIndex->bComplexLinkIndex = true; // 加入数据结构中 m_IndexToComplexControls.insertMulti(pIndex, pControl); } /// /// 为控件添加一个变量 /// /// /// void WindowRuntime::registerNewVariable(QWidget* pControl, const QString& strPropertyName, const VARIABLE* pVariable) { if (pVariable == nullptr || pControl == nullptr) { return; } RUNTIME_SYNC_VAR newVar(strPropertyName, pVariable); // 如果找到了本Control对应的变量,则直接添加变量 if (m_ComplexControlToVariables.contains(pControl)) { RUNTIME_SYNC_VARS& vars = m_ComplexControlToVariables[pControl]; vars.push_back(newVar); } // 如果没有找到,则新建此变量 else { RUNTIME_SYNC_VARS vars; vars.push_back(newVar); m_ComplexControlToVariables.insert(pControl, vars); } } /// /// 释放对应控件关系 /// /// void WindowRuntime::releaseControl(QWidget* pWidget) { m_ComplexControlToVariables.remove(pWidget); // QMutableHashIterator iter(m_IndexToComplexControls); // while (iter.hasNext()) // { // // 更新了删除元素的方式 // const QList& listWidgets = m_IndexToComplexControls.values(iter.next().key()); for (const VARIABLE* pVar : m_IndexToComplexControls.uniqueKeys()) { // 更新了删除元素的方式 const QList& listWidgets = m_IndexToComplexControls.values(pVar); for (int i = 0; i < listWidgets.count(); i++) { if (listWidgets.at(i) == pWidget) { // m_IndexToComplexControls.remove(iter.key(), pWidget); m_IndexToComplexControls.remove(pVar, pWidget); return; } } } } /// /// 从复杂控件的触发源头同步(一般都是Pou中的Execute,每轮执行会触发更新一遍Runtime) /// /// void WindowRuntime::syncFromComplexSource(const VARIABLE* syncVal) { // 如果本轮需要同步的Value的不是索引所在的pou,那么就不更新,等着索引所在的pou执行后再统一更新 // (MEMO:这个判断放在Pou中了,只有索引变量才会被推送过来) // 所以这个判断不可能命中 if (syncVal == nullptr || !syncVal->bComplexLinkIndex) { return; } // 如果本轮执行的是索引所在的pou则更新其他所有pou中的关联值 // 首先找到这个索引变量对应的控件指针 if (m_IndexToComplexControls.contains(syncVal)) { // 2021-12-28 修改,此处改为一个索引源触发多个控件刷新 QList pControls = m_IndexToComplexControls.values(syncVal); for (QWidget* pControl : pControls) { // 根据控件类型的不同,单独进行处理 QString strClassName = pControl->metaObject()->className(); // 如果是Table类型 if (strClassName == CLASS_NAME_TABLECONTROL) { // 传递Table指针以及对应的列索引数据 int nRowIndex = syncVal->getValueString().toInt(); this->syncToTableControl(pControl, nRowIndex); } // 如果是VCustomPlot类型 else if (strClassName == CLASS_NAME_CUSTOMPLOT) { // 传递VCustomPlot指针以及对应的分块索引数据 int nRowIndex = syncVal->getValueString().toInt(); this->syncToCustomPlot(pControl, nRowIndex); } // 如果是Pie类型 else if (strClassName == CLASS_NAME_PIECHART) { // 传递Pie指针以及对应的分块索引数据 int nRowIndex = syncVal->getValueString().toInt(); this->syncToPieChart(pControl, nRowIndex); } // 如果是Image类型 else if (strClassName == CLASS_NAME_IMAGECONTROL) { this->syncToImageControl(pControl); } } } // 不应该走到这里 else { qDebug() << "WindowRuntime::syncFromComplexSource - Critical error : can't find correct relation from syncvalue[" << syncVal->strFullName << "]."; } } /// /// 同步到Table控件中 /// /// void WindowRuntime::syncToTableControl(QWidget* pControl, int nRowIndex) { VTableControl* pTableWidget = qobject_cast(pControl); // 如果给定的Index数值超出了Table的最大范围,则忽略 if (nRowIndex >= pTableWidget->rowCount()) { //qDebug() << "WindowRuntime::syncToTableControl - nRowIndex > table row count, ignore : " << nRowIndex; nRowIndex = 0; //return; } // 找到Table对应的各个数值信息 if (m_ComplexControlToVariables.contains(pControl)) { RUNTIME_SYNC_VARS sync_vars = m_ComplexControlToVariables[pControl]; // 刷新对应的表格 // this->updateTableControl(pTableWidget, vars, nRowIndex); // 刷新这一行 pTableWidget->updateRowFromVariables(sync_vars, nRowIndex); } // 不应该走到这里 else { qDebug() << "WindowRuntime::syncToTableControl - Critical error : can't find correct relation from m_ComplexControlToVariables."; } } ///// ///// 刷新Table控件中的值 ///// ///// ///// //void WindowRuntime::updateTableControl(QTableWidget* pTableWidget, const RUNTIME_SYNC_VARS& vars, int nRowIndex) //{ // // 将最新的值都更新到Table控件中(一次更新一整列) // int nColCount = pTableWidget->columnCount(); // // for (int i = 0; i < nColCount; i++) // { // QString strValue = vars[i]->getValueString(); // // pTableWidget->setItem( // nRowIndex, // i, // new QTableWidgetItem(strValue) // ); // } //} /// /// 同步到CustomPlot控件中 /// /// /// void WindowRuntime::syncToCustomPlot(QWidget* pControl, int nSliceIndex) { Q_UNUSED(nSliceIndex); VCustomPlot* pCustomPlot = qobject_cast(pControl); if (pCustomPlot != nullptr) { // 找到对应的各个数值信息 if (m_ComplexControlToVariables.contains(pControl)) { RUNTIME_SYNC_VARS sync_vars = m_ComplexControlToVariables[pControl]; for (int i = 0; i < sync_vars.size(); i++) { int nValue = sync_vars[i].pVariable->getValueString().toInt(); // 防止数据越界 if (pCustomPlot->getCustomPlotCount() > i) { pCustomPlot->updateCustomPlotValue(nValue, i); } } } // 不应该走到这里 else { qWarning() << "WindowRuntime::syncToPieChart - Critical error : can't find correct relation from m_ComplexControlToVariables."; } } } /// /// 同步到Pie控件中 /// /// /// void WindowRuntime::syncToPieChart(QWidget* pControl, int nSliceIndex) { Q_UNUSED(nSliceIndex); VPieChart* pPieChart = qobject_cast(pControl); if (pPieChart != nullptr) { // 找到对应的各个数值信息 if (m_ComplexControlToVariables.contains(pControl)) { RUNTIME_SYNC_VARS sync_vars = m_ComplexControlToVariables[pControl]; for (int i = 0; i < sync_vars.size(); i++) { int nValue = sync_vars[i].pVariable->getValueString().toInt(); // 防止数据越界 if (pPieChart->getSliceCount() > i ) { pPieChart->updateSliceValue(nValue, i); } } } // 不应该走到这里 else { qWarning() << "WindowRuntime::syncToPieChart - Critical error : can't find correct relation from m_ComplexControlToVariables."; } } } /// /// 同步到Image控件中 /// /// void WindowRuntime::syncToImageControl(QWidget* pControl) { VImageControl* pImageControl = qobject_cast(pControl); // 找到对应的各个数值信息 if (m_ComplexControlToVariables.contains(pControl)) { RUNTIME_SYNC_VARS sync_vars = m_ComplexControlToVariables[pControl]; // 刷新本图像 pImageControl->updateImageFromVariables(sync_vars); } // 不应该走到这里 else { qDebug() << "WindowRuntime::syncToImageControl - Critical error : can't find correct relation from m_ComplexControlToVariables."; } } /// /// 重置所有数据结构,准备执行新的发布动作 /// void WindowRuntime::reset() { // 首先清空当前所有页面 RELEASE(m_pRuntimeViews); m_AllViews.clear(); m_IndexToComplexControls.clear(); m_ComplexControlToVariables.clear(); }