WindowRuntime.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667
  1. #include "WindowRuntime.h"
  2. #include "WindowRuntimeView.h"
  3. #include "TaskManager.h"
  4. #include "PouManager.h"
  5. #include "vpControls/VTableControl.h"
  6. #include "vpControls/VPieChart.h"
  7. #include "vpControls/VCustomPlot.h"
  8. #include "vpControls/VImageControl.h"
  9. #define MAINPAGE_INDEX 0
  10. WindowRuntime::WindowRuntime(QWidget *parent)
  11. : QMainWindow(parent)
  12. , m_pRuntimeViews(nullptr)
  13. {
  14. ui.setupUi(this);
  15. // 界面初始化
  16. this->initUI();
  17. // 注册本窗体
  18. VPGlobal::Register(this);
  19. }
  20. WindowRuntime::~WindowRuntime()
  21. {
  22. }
  23. /// <summary>
  24. /// 界面初始化
  25. /// </summary>
  26. void WindowRuntime::initUI()
  27. {
  28. this->setWindowFlags(Qt::Widget);
  29. if (1)
  30. {
  31. // 创建Stack式页面栈
  32. m_pRuntimeViews = new QStackedWidget();
  33. // 创建对应的发布页面
  34. WindowRuntimeView* pNew = new WindowRuntimeView(m_pRuntimeViews);
  35. m_pRuntimeViews->addWidget(pNew);
  36. // 设置布局
  37. QGridLayout* layout = new QGridLayout();
  38. layout->setMargin(0);
  39. layout->setSpacing(0);
  40. layout->addWidget(m_pRuntimeViews);
  41. ui.centralWidget->setLayout(layout);
  42. }
  43. else
  44. {
  45. // TODO: RunTime 超过 UI的尺寸时,需要显示滚动条。
  46. // TODO: RunTime 小于 UI的尺寸时,需要显示边框
  47. //////////////////////////////////////////////////////////////////////////
  48. QGridLayout* gridLayout = new QGridLayout(ui.centralWidget);
  49. m_pRuntimeViews = new QStackedWidget(ui.centralWidget);
  50. QWidget* page = new QWidget();
  51. QGridLayout* gridLayout_3 = new QGridLayout(page);
  52. QScrollArea* scrollArea = new QScrollArea(page);
  53. // scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
  54. // scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
  55. scrollArea->setWidgetResizable(true);
  56. QWidget* scrollAreaWidgetContents = new QWidget();
  57. QGridLayout* gridLayout_2 = new QGridLayout(scrollAreaWidgetContents);
  58. WindowRuntimeView* pNew = new WindowRuntimeView(scrollAreaWidgetContents); ;
  59. gridLayout_2->addWidget(pNew, 0, 0, 1, 1);
  60. scrollArea->setWidget(scrollAreaWidgetContents);
  61. gridLayout_3->addWidget(scrollArea, 0, 0, 1, 1);
  62. m_pRuntimeViews->addWidget(page);
  63. gridLayout->addWidget(m_pRuntimeViews, 0, 0, 1, 1);
  64. pNew->setMinimumSize(QSize(80, 80));
  65. }
  66. }
  67. /// <summary>
  68. /// 发布对应的页面
  69. /// </summary>
  70. /// <param name="pPage"></param>
  71. /// <param name="bMainPage">标记当前页面是否是主页</param>
  72. /// <returns></returns>
  73. bool WindowRuntime::publishPage(WindowAppUiView* pPage, bool bMainPage /* = false */)
  74. {
  75. // 确保首页是一定是第一个页面
  76. if (bMainPage)
  77. {
  78. if (m_pRuntimeViews!=nullptr && m_pRuntimeViews->count() > 0)
  79. {
  80. CRITICAL_MESSAGE("Run main page [" + pPage->m_strPageName + "] error!");
  81. return false;
  82. }
  83. // 新建StackWidget
  84. m_pRuntimeViews = new QStackedWidget();
  85. ui.centralWidget->layout()->addWidget(m_pRuntimeViews);
  86. }
  87. // 创建新的Runtime页面添加到Stack中
  88. WindowRuntimeView* pNewView = new WindowRuntimeView(m_pRuntimeViews);
  89. m_pRuntimeViews->addWidget(pNewView);
  90. // 保存页面序号
  91. m_AllViews.insert(pPage->m_strPageName, m_pRuntimeViews->count() - 1);
  92. // 发布本页面中的所有控件
  93. // 此处需要检查是否所有的控件都拷贝成功
  94. bool bRet = pNewView->copyFrom(pPage);
  95. Q_UNUSED(bRet);
  96. return true;
  97. }
  98. /// <summary>
  99. /// 启动所有的UI界面(目前先只支持启动所有页面的方式)
  100. /// </summary>
  101. bool WindowRuntime::publishAllPages(
  102. WindowAppUiView* pMainPage,
  103. QMap<QString, WindowAppUiView*> allPages
  104. )
  105. {
  106. // 首先执行数据结构重置
  107. this->reset();
  108. // 首先发布主页
  109. bool bRet = publishPage(pMainPage, true);
  110. // 如果首页发布失败,则退出
  111. if (!bRet)
  112. {
  113. return false;
  114. }
  115. // 根据每一个 WindowAppUiView 生成对应的页面,并且把所有的控件都分布上去
  116. QMapIterator<QString, WindowAppUiView*> it(allPages);
  117. while (it.hasNext())
  118. {
  119. WindowAppUiView* pPage = it.next().value();
  120. if (pPage != pMainPage)
  121. {
  122. // 其余子页面暂时不检查返回值,如果发布失败则继续发布下一个页面
  123. bRet = publishPage(pPage);
  124. }
  125. }
  126. // 页面全部发布完毕后,默认显示主页
  127. if (m_pRuntimeViews!=nullptr &&
  128. m_pRuntimeViews->count() > 0)
  129. {
  130. m_pRuntimeViews->setCurrentIndex(MAINPAGE_INDEX);
  131. }
  132. return true;
  133. }
  134. /// <summary>
  135. /// 执行指令
  136. /// </summary>
  137. /// <param name="strCmd">命令名字</param>
  138. /// <param name="strParam">命令参数</param>
  139. /// <returns></returns>
  140. bool WindowRuntime::runCmd(const QString& strCmd, const QString& strParam /*= ""*/)
  141. {
  142. // 启动所有Task的执行
  143. if (strCmd == SYS_CMD_TASK_RUN)
  144. {
  145. qDebug() << "[Command] runCmd - " << SYS_CMD_TASK_RUN;
  146. g_pTaskManager->executeAllTasks(false);
  147. }
  148. // 启动所有Task的执行一次
  149. else if (strCmd == SYS_CMD_TASK_RUNONCE)
  150. {
  151. qDebug() << "[Command] runCmd - " << SYS_CMD_TASK_RUNONCE;
  152. g_pTaskManager->executeAllTasks(true);
  153. }
  154. // 停止所有任务
  155. else if (strCmd == SYS_CMD_TASK_STOP)
  156. {
  157. qDebug() << "[Command] runCmd - " << SYS_CMD_TASK_STOP;
  158. g_pTaskManager->stopAllTask(false);
  159. }
  160. // 切换UI
  161. else if (strCmd == SYS_CMD_UI_SWITCH)
  162. {
  163. qDebug() << "[Command] runCmd - " << SYS_CMD_UI_SWITCH << " - " << strParam;
  164. g_pRuntime->switchToPage(strParam);
  165. }
  166. // 不应该执行到这里
  167. else
  168. {
  169. qWarning() << "SystemCommand::runCmd - unknown command : " << strCmd;
  170. return false;
  171. }
  172. return true;
  173. }
  174. /// <summary>
  175. /// 执行Dll中的Tool Interface
  176. /// </summary>
  177. /// <param name="strPouName"></param>
  178. /// <param name="strToolName"></param>
  179. /// <param name="strInfName"></param>
  180. /// <returns></returns>
  181. bool WindowRuntime::runDllInterface(
  182. const QString& strPouName,
  183. const QString& strToolName,
  184. const QString& strInfName,
  185. VALUE_TYPE controlType
  186. )
  187. {
  188. // 首先根据名字找到Pou
  189. POU* pPou = g_pPouManager->getPouByName(strPouName);
  190. if (pPou == nullptr)
  191. {
  192. qWarning() << "[Error] in WindowRuntime::runDllInterface() - Invalid pou name : " << strPouName;
  193. return false;
  194. }
  195. // 然后找到对应的接口
  196. QString strInfFullname = strToolName + "." + strInfName;
  197. _INTERFACE* pInf = pPou->GetInterface(strInfFullname);
  198. if (pInf == nullptr)
  199. {
  200. qWarning() << "[Error] in WindowRuntime::runDllInterface() - Invalid interface name : " << strInfFullname;
  201. return false;
  202. }
  203. // 根据不同的Runtime控件类型进行不同的处理
  204. if (controlType == VALUE_TYPE::Control_Button)
  205. {
  206. // 获取dll中导出的控件指针
  207. QPushButton* pInfButton = (QPushButton*)pInf->getValuePtr();
  208. // 发送clicked信号
  209. emit pInfButton->clicked();
  210. return true;
  211. }
  212. else
  213. {
  214. qWarning() << "[Error] in WindowRuntime::runDllInterface() - Control type is not support : " << static_cast<short>(controlType);
  215. return false;
  216. }
  217. }
  218. /// <summary>
  219. /// 系统命令,切换到指定页面
  220. /// </summary>
  221. /// <param name="strPageName"></param>2121
  222. /// <returns></returns>
  223. bool WindowRuntime::switchToPage(const QString& strPageName)
  224. {
  225. // 执行界面的切换
  226. if (m_AllViews.contains(strPageName))
  227. {
  228. int nPageIndex = m_AllViews[strPageName];
  229. // 找到指定页面,并切换
  230. m_pRuntimeViews->setCurrentIndex(nPageIndex);
  231. qDebug() << "WindowRuntime::switchToPage() - " << strPageName << " index: " << nPageIndex;
  232. return true;
  233. }
  234. // Error: 不应该执行到这里
  235. else
  236. {
  237. qDebug() << "[Error] in WindowRuntime::switchToPage() - " << strPageName << ", but can;t find this page";
  238. return false;
  239. }
  240. }
  241. //========================================================================
  242. //
  243. // 变量同步相关代码
  244. //
  245. //========================================================================
  246. /// <summary>
  247. /// 接收来自变量到复杂控件单向同步的Event
  248. /// 备注:复杂控件是根据索引值绑定变量主动发起的event来触发更新的
  249. /// </summary>
  250. /// <param name="event"></param>
  251. void WindowRuntime::customEvent(QEvent* event)
  252. {
  253. // 如果是数值同步消息
  254. if (event->type() == VALUE_EVENT_TYPEID)
  255. {
  256. qDebug() << "WindowRuntime::customEvent - VALUE_EVENT_TYPEID";
  257. SyncValueEvent* pValueEvent = dynamic_cast<SyncValueEvent*> (event);
  258. // 取出参数
  259. QList<VARIABLE*> syncValues = pValueEvent->getSyncValues();
  260. for (VARIABLE* syncVal : syncValues)
  261. {
  262. // 从变量中同步
  263. this->syncFromComplexSource(syncVal);
  264. }
  265. }
  266. else
  267. {
  268. QEvent::Type type = event->type();
  269. qWarning() << "WindowRuntime::customEvent Type:" <<type;
  270. }
  271. }
  272. /// <summary>
  273. /// 添加一个新的索引和控件对应关系
  274. /// </summary>
  275. /// <param name="pIndex"></param>
  276. /// <param name="pControl"></param>
  277. void WindowRuntime::registerNewIndex(VARIABLE* pIndex, QWidget* pControl)
  278. {
  279. if (pIndex == nullptr || pControl == nullptr)
  280. {
  281. return;
  282. }
  283. // 为接口设置索引标识
  284. pIndex->bComplexLinkIndex = true;
  285. // 加入数据结构中
  286. m_IndexToComplexControls.insertMulti(pIndex, pControl);
  287. }
  288. /// <summary>
  289. /// 为控件添加一个变量
  290. /// </summary>
  291. /// <param name="pControl"></param>
  292. /// <param name="pVariable"></param>
  293. void WindowRuntime::registerNewVariable(QWidget* pControl, const QString& strPropertyName, const VARIABLE* pVariable)
  294. {
  295. if (pVariable == nullptr || pControl == nullptr)
  296. {
  297. return;
  298. }
  299. RUNTIME_SYNC_VAR newVar(strPropertyName, pVariable);
  300. // 如果找到了本Control对应的变量,则直接添加变量
  301. if (m_ComplexControlToVariables.contains(pControl))
  302. {
  303. RUNTIME_SYNC_VARS& vars = m_ComplexControlToVariables[pControl];
  304. vars.push_back(newVar);
  305. }
  306. // 如果没有找到,则新建此变量
  307. else
  308. {
  309. RUNTIME_SYNC_VARS vars;
  310. vars.push_back(newVar);
  311. m_ComplexControlToVariables.insert(pControl, vars);
  312. }
  313. }
  314. /// <summary>
  315. /// 释放对应控件关系
  316. /// </summary>
  317. /// <param name="pWidget"></param>
  318. void WindowRuntime::releaseControl(QWidget* pWidget)
  319. {
  320. m_ComplexControlToVariables.remove(pWidget);
  321. // QMutableHashIterator<const VARIABLE*, QWidget*> iter(m_IndexToComplexControls);
  322. // while (iter.hasNext())
  323. // {
  324. // // 更新了删除元素的方式
  325. // const QList<QWidget*>& listWidgets = m_IndexToComplexControls.values(iter.next().key());
  326. for (const VARIABLE* pVar : m_IndexToComplexControls.uniqueKeys())
  327. {
  328. // 更新了删除元素的方式
  329. const QList<QWidget*>& listWidgets = m_IndexToComplexControls.values(pVar);
  330. for (int i = 0; i < listWidgets.count(); i++)
  331. {
  332. if (listWidgets.at(i) == pWidget)
  333. {
  334. // m_IndexToComplexControls.remove(iter.key(), pWidget);
  335. m_IndexToComplexControls.remove(pVar, pWidget);
  336. return;
  337. }
  338. }
  339. }
  340. }
  341. /// <summary>
  342. /// 从复杂控件的触发源头同步(一般都是Pou中的Execute,每轮执行会触发更新一遍Runtime)
  343. /// </summary>
  344. /// <param name="syncVal"></param>
  345. void WindowRuntime::syncFromComplexSource(const VARIABLE* syncVal)
  346. {
  347. // 如果本轮需要同步的Value的不是索引所在的pou,那么就不更新,等着索引所在的pou执行后再统一更新
  348. // (MEMO:这个判断放在Pou中了,只有索引变量才会被推送过来)
  349. // 所以这个判断不可能命中
  350. if (syncVal == nullptr || !syncVal->bComplexLinkIndex)
  351. {
  352. return;
  353. }
  354. // 如果本轮执行的是索引所在的pou则更新其他所有pou中的关联值
  355. // 首先找到这个索引变量对应的控件指针
  356. if (m_IndexToComplexControls.contains(syncVal))
  357. {
  358. // 2021-12-28 修改,此处改为一个索引源触发多个控件刷新
  359. QList<QWidget*> pControls = m_IndexToComplexControls.values(syncVal);
  360. for (QWidget* pControl : pControls)
  361. {
  362. // 根据控件类型的不同,单独进行处理
  363. QString strClassName = pControl->metaObject()->className();
  364. // 如果是Table类型
  365. if (strClassName == CLASS_NAME_TABLECONTROL)
  366. {
  367. // 传递Table指针以及对应的列索引数据
  368. int nRowIndex = syncVal->getValueString().toInt();
  369. this->syncToTableControl(pControl, nRowIndex);
  370. }
  371. // 如果是VCustomPlot类型
  372. else if (strClassName == CLASS_NAME_CUSTOMPLOT)
  373. {
  374. // 传递VCustomPlot指针以及对应的分块索引数据
  375. int nRowIndex = syncVal->getValueString().toInt();
  376. this->syncToCustomPlot(pControl, nRowIndex);
  377. }
  378. // 如果是Pie类型
  379. else if (strClassName == CLASS_NAME_PIECHART)
  380. {
  381. // 传递Pie指针以及对应的分块索引数据
  382. int nRowIndex = syncVal->getValueString().toInt();
  383. this->syncToPieChart(pControl, nRowIndex);
  384. }
  385. // 如果是Image类型
  386. else if (strClassName == CLASS_NAME_IMAGECONTROL)
  387. {
  388. this->syncToImageControl(pControl);
  389. }
  390. }
  391. }
  392. // 不应该走到这里
  393. else
  394. {
  395. qDebug() << "WindowRuntime::syncFromComplexSource - Critical error : can't find correct relation from syncvalue["
  396. << syncVal->strFullName << "].";
  397. }
  398. }
  399. /// <summary>
  400. /// 同步到Table控件中
  401. /// </summary>
  402. /// <param name="pTable"></param>
  403. void WindowRuntime::syncToTableControl(QWidget* pControl, int nRowIndex)
  404. {
  405. VTableControl* pTableWidget = qobject_cast<VTableControl*>(pControl);
  406. // 如果给定的Index数值超出了Table的最大范围,则忽略
  407. if (nRowIndex >= pTableWidget->rowCount())
  408. {
  409. //qDebug() << "WindowRuntime::syncToTableControl - nRowIndex > table row count, ignore : " << nRowIndex;
  410. nRowIndex = 0;
  411. //return;
  412. }
  413. // 找到Table对应的各个数值信息
  414. if (m_ComplexControlToVariables.contains(pControl))
  415. {
  416. RUNTIME_SYNC_VARS sync_vars = m_ComplexControlToVariables[pControl];
  417. // 刷新对应的表格
  418. // this->updateTableControl(pTableWidget, vars, nRowIndex);
  419. // 刷新这一行
  420. pTableWidget->updateRowFromVariables(sync_vars, nRowIndex);
  421. }
  422. // 不应该走到这里
  423. else
  424. {
  425. qDebug() << "WindowRuntime::syncToTableControl - Critical error : can't find correct relation from m_ComplexControlToVariables.";
  426. }
  427. }
  428. ///// <summary>
  429. ///// 刷新Table控件中的值
  430. ///// </summary>
  431. ///// <param name="pTableWidget"></param>
  432. ///// <param name="vars"></param>
  433. //void WindowRuntime::updateTableControl(QTableWidget* pTableWidget, const RUNTIME_SYNC_VARS& vars, int nRowIndex)
  434. //{
  435. // // 将最新的值都更新到Table控件中(一次更新一整列)
  436. // int nColCount = pTableWidget->columnCount();
  437. //
  438. // for (int i = 0; i < nColCount; i++)
  439. // {
  440. // QString strValue = vars[i]->getValueString();
  441. //
  442. // pTableWidget->setItem(
  443. // nRowIndex,
  444. // i,
  445. // new QTableWidgetItem(strValue)
  446. // );
  447. // }
  448. //}
  449. /// <summary>
  450. /// 同步到CustomPlot控件中
  451. /// </summary>
  452. /// <param name="pPie"></param>
  453. /// <param name="nSliceIndex"></param>
  454. void WindowRuntime::syncToCustomPlot(QWidget* pControl, int nSliceIndex)
  455. {
  456. Q_UNUSED(nSliceIndex);
  457. VCustomPlot* pCustomPlot = qobject_cast<VCustomPlot*>(pControl);
  458. if (pCustomPlot != nullptr)
  459. {
  460. // 找到对应的各个数值信息
  461. if (m_ComplexControlToVariables.contains(pControl))
  462. {
  463. RUNTIME_SYNC_VARS sync_vars = m_ComplexControlToVariables[pControl];
  464. for (int i = 0; i < sync_vars.size(); i++)
  465. {
  466. int nValue = sync_vars[i].pVariable->getValueString().toInt();
  467. // 防止数据越界
  468. if (pCustomPlot->getCustomPlotCount() > i)
  469. {
  470. pCustomPlot->updateCustomPlotValue(nValue, i);
  471. }
  472. }
  473. }
  474. // 不应该走到这里
  475. else
  476. {
  477. qWarning() << "WindowRuntime::syncToPieChart - Critical error : can't find correct relation from m_ComplexControlToVariables.";
  478. }
  479. }
  480. }
  481. /// <summary>
  482. /// 同步到Pie控件中
  483. /// </summary>
  484. /// <param name="pPie"></param>
  485. /// <param name="nSliceIndex"></param>
  486. void WindowRuntime::syncToPieChart(QWidget* pControl, int nSliceIndex)
  487. {
  488. Q_UNUSED(nSliceIndex);
  489. VPieChart* pPieChart = qobject_cast<VPieChart*>(pControl);
  490. if (pPieChart != nullptr)
  491. {
  492. // 找到对应的各个数值信息
  493. if (m_ComplexControlToVariables.contains(pControl))
  494. {
  495. RUNTIME_SYNC_VARS sync_vars = m_ComplexControlToVariables[pControl];
  496. for (int i = 0; i < sync_vars.size(); i++)
  497. {
  498. int nValue = sync_vars[i].pVariable->getValueString().toInt();
  499. // 防止数据越界
  500. if (pPieChart->getSliceCount() > i )
  501. {
  502. pPieChart->updateSliceValue(nValue, i);
  503. }
  504. }
  505. }
  506. // 不应该走到这里
  507. else
  508. {
  509. qWarning() << "WindowRuntime::syncToPieChart - Critical error : can't find correct relation from m_ComplexControlToVariables.";
  510. }
  511. }
  512. }
  513. /// <summary>
  514. /// 同步到Image控件中
  515. /// </summary>
  516. /// <param name="pControl"></param>
  517. void WindowRuntime::syncToImageControl(QWidget* pControl)
  518. {
  519. VImageControl* pImageControl = qobject_cast<VImageControl*>(pControl);
  520. // 找到对应的各个数值信息
  521. if (m_ComplexControlToVariables.contains(pControl))
  522. {
  523. RUNTIME_SYNC_VARS sync_vars = m_ComplexControlToVariables[pControl];
  524. // 刷新本图像
  525. pImageControl->updateImageFromVariables(sync_vars);
  526. }
  527. // 不应该走到这里
  528. else
  529. {
  530. qDebug() << "WindowRuntime::syncToImageControl - Critical error : can't find correct relation from m_ComplexControlToVariables.";
  531. }
  532. }
  533. /// <summary>
  534. /// 重置所有数据结构,准备执行新的发布动作
  535. /// </summary>
  536. void WindowRuntime::reset()
  537. {
  538. // 首先清空当前所有页面
  539. RELEASE(m_pRuntimeViews);
  540. m_AllViews.clear();
  541. m_IndexToComplexControls.clear();
  542. m_ComplexControlToVariables.clear();
  543. }