综合平台编程器项目的远程存储
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 
 

298 linhas
10 KiB

  1. #include "free_monitor_widget.h"
  2. #include "services/register_monitor_service.h"
  3. #include "toolbar_icon_factory.h"
  4. #include "ui_free_monitor_widget.h"
  5. #include <QComboBox>
  6. #include <QHeaderView>
  7. #include <QIntValidator>
  8. #include <QLineEdit>
  9. #include <QMessageBox>
  10. #include <QPushButton>
  11. #include <QTableWidgetItem>
  12. #include <cstdint>
  13. #include <set>
  14. namespace {
  15. QString fromUtf8(const std::string &value)
  16. {
  17. return QString::fromUtf8(value.data(), static_cast<int>(value.size()));
  18. }
  19. QString addressText(const RegisterAddress &address)
  20. {
  21. return QString::fromStdString(address.toString());
  22. }
  23. } // namespace
  24. FreeMonitorWidget::FreeMonitorWidget(
  25. RegisterMonitorService &service,
  26. QWidget *parent)
  27. : QWidget(parent),
  28. ui_(std::make_unique<Ui::FreeMonitorWidget>()),
  29. service_(service)
  30. {
  31. ui_->setupUi(this);
  32. ui_->removeButton->setIcon(makeUiIcon(UiIcon::Delete));
  33. ui_->clearButton->setIcon(makeUiIcon(UiIcon::ClearList));
  34. ui_->monitorTable->horizontalHeader()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
  35. ui_->monitorTable->horizontalHeader()->setSectionResizeMode(1, QHeaderView::ResizeToContents);
  36. ui_->monitorTable->horizontalHeader()->setSectionResizeMode(2, QHeaderView::Stretch);
  37. ui_->monitorTable->horizontalHeader()->setSectionResizeMode(3, QHeaderView::Stretch);
  38. ui_->monitorTable->horizontalHeader()->setSectionResizeMode(4, QHeaderView::ResizeToContents);
  39. ui_->monitorTable->horizontalHeader()->setSectionResizeMode(5, QHeaderView::Stretch);
  40. ui_->monitorTable->verticalHeader()->setVisible(false);
  41. connect(ui_->addButton, &QPushButton::clicked, this, &FreeMonitorWidget::addAddresses);
  42. connect(ui_->addressEdit, &QLineEdit::returnPressed,
  43. this, &FreeMonitorWidget::addAddresses);
  44. connect(ui_->removeButton, &QToolButton::clicked,
  45. this, &FreeMonitorWidget::removeSelectedAddresses);
  46. connect(ui_->clearButton, &QToolButton::clicked,
  47. this, &FreeMonitorWidget::clearAddresses);
  48. reloadAddresses();
  49. }
  50. FreeMonitorWidget::~FreeMonitorWidget() = default;
  51. void FreeMonitorWidget::setWriteEnabled(bool enabled)
  52. {
  53. write_enabled_ = enabled;
  54. updateWriteControls();
  55. }
  56. void FreeMonitorWidget::refreshValues(
  57. ApplicationMode mode, PlcConnectionState plc_state)
  58. {
  59. QString source = tr("数据源:未启用");
  60. bool values_available = false;
  61. bool communication_fault = false;
  62. if (mode == ApplicationMode::OfflineRunning)
  63. {
  64. source = tr("数据源:虚拟 M/D");
  65. values_available = true;
  66. }
  67. else if (mode == ApplicationMode::OnlineRunning)
  68. {
  69. source = tr("数据源:PLC 缓存");
  70. values_available = true;
  71. communication_fault = plc_state == PlcConnectionState::Faulted;
  72. }
  73. ui_->sourceLabel->setText(source);
  74. const std::vector<MonitorValue> values = values_available
  75. ? service_.values(communication_fault) : std::vector<MonitorValue>{};
  76. for (int row = 0; row < ui_->monitorTable->rowCount(); ++row)
  77. {
  78. QTableWidgetItem *value_item = ui_->monitorTable->item(row, 2);
  79. QTableWidgetItem *state_item = ui_->monitorTable->item(row, 5);
  80. if (!values_available || static_cast<std::size_t>(row) >= values.size())
  81. {
  82. value_item->setText(QStringLiteral("--"));
  83. state_item->setText(tr("未运行"));
  84. continue;
  85. }
  86. const MonitorValue &value = values.at(static_cast<std::size_t>(row));
  87. if (value.state == MonitorValueState::Unavailable)
  88. {
  89. value_item->setText(QStringLiteral("--"));
  90. state_item->setText(mode == ApplicationMode::OnlineRunning
  91. ? tr("等待读取") : tr("不可用"));
  92. continue;
  93. }
  94. value_item->setText(value.address.area() == RegisterArea::M
  95. ? (value.bitValue ? QStringLiteral("ON")
  96. : QStringLiteral("OFF"))
  97. : QString::number(value.wordValue));
  98. state_item->setText(value.state == MonitorValueState::CommunicationFault
  99. ? tr("通信故障,最后有效值") : tr("有效"));
  100. }
  101. updateWriteControls();
  102. }
  103. void FreeMonitorWidget::reloadAddresses()
  104. {
  105. const std::vector<RegisterAddress> &addresses = service_.addresses();
  106. ui_->monitorTable->setRowCount(static_cast<int>(addresses.size()));
  107. for (std::size_t index = 0; index < addresses.size(); ++index)
  108. {
  109. const RegisterAddress &address = addresses[index];
  110. const int row = static_cast<int>(index);
  111. ui_->monitorTable->setItem(row, 0, new QTableWidgetItem(addressText(address)));
  112. ui_->monitorTable->setItem(
  113. row, 1, new QTableWidgetItem(address.area() == RegisterArea::M
  114. ? tr("位") : tr("16 位整数")));
  115. ui_->monitorTable->setItem(row, 2, new QTableWidgetItem(QStringLiteral("--")));
  116. if (address.area() == RegisterArea::M)
  117. {
  118. auto *target = new QComboBox(ui_->monitorTable);
  119. target->addItem(tr("OFF"), false);
  120. target->addItem(tr("ON"), true);
  121. ui_->monitorTable->setCellWidget(row, 3, target);
  122. }
  123. else
  124. {
  125. auto *target = new QLineEdit(ui_->monitorTable);
  126. target->setValidator(new QIntValidator(-32768, 32767, target));
  127. target->setText(QStringLiteral("0"));
  128. target->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
  129. ui_->monitorTable->setCellWidget(row, 3, target);
  130. }
  131. auto *write_button = new QPushButton(tr("写入"), ui_->monitorTable);
  132. write_button->setProperty("monitorRow", row);
  133. connect(write_button, &QPushButton::clicked, this,
  134. [this, write_button]
  135. {
  136. writeRow(write_button->property("monitorRow").toInt());
  137. });
  138. ui_->monitorTable->setCellWidget(row, 4, write_button);
  139. ui_->monitorTable->setItem(row, 5, new QTableWidgetItem(tr("未运行")));
  140. }
  141. updateWriteControls();
  142. }
  143. void FreeMonitorWidget::writeRow(int row)
  144. {
  145. if (!write_enabled_ || row < 0
  146. || static_cast<std::size_t>(row) >= service_.addresses().size())
  147. {
  148. return;
  149. }
  150. const RegisterAddress address = service_.addresses().at(static_cast<std::size_t>(row));
  151. RegisterMonitorWriteResult result;
  152. if (address.area() == RegisterArea::M)
  153. {
  154. auto *target = qobject_cast<QComboBox *>(ui_->monitorTable->cellWidget(row, 3));
  155. if (target == nullptr)
  156. {
  157. return;
  158. }
  159. result = service_.writeBit(address, target->currentData().toBool());
  160. }
  161. else
  162. {
  163. auto *target = qobject_cast<QLineEdit *>(ui_->monitorTable->cellWidget(row, 3));
  164. if (target == nullptr)
  165. {
  166. return;
  167. }
  168. bool converted = false;
  169. const int value = target->text().toInt(&converted);
  170. if (!converted || value < -32768 || value > 32767)
  171. {
  172. ui_->monitorTable->item(row, 5)->setText(tr("目标值无效"));
  173. emit operationMessage(tr("写入 D 区地址失败:请输入 -32768~32767 的整数"));
  174. return;
  175. }
  176. result = service_.writeWord(address, static_cast<std::int16_t>(value));
  177. }
  178. QTableWidgetItem *state_item = ui_->monitorTable->item(row, 5);
  179. if (result.succeeded)
  180. {
  181. state_item->setText(tr("写入请求已发送"));
  182. emit operationMessage(tr("%1 写入请求已发送,等待当前值刷新")
  183. .arg(addressText(address)));
  184. return;
  185. }
  186. state_item->setText(tr("写入失败"));
  187. handleResult(tr("写入 %1").arg(addressText(address)), false, result.message);
  188. }
  189. void FreeMonitorWidget::updateWriteControls()
  190. {
  191. for (int row = 0; row < ui_->monitorTable->rowCount(); ++row)
  192. {
  193. QWidget *target = ui_->monitorTable->cellWidget(row, 3);
  194. if (target != nullptr)
  195. {
  196. target->setEnabled(write_enabled_);
  197. }
  198. QWidget *write_button = ui_->monitorTable->cellWidget(row, 4);
  199. if (write_button != nullptr)
  200. {
  201. write_button->setEnabled(write_enabled_);
  202. }
  203. }
  204. }
  205. void FreeMonitorWidget::addAddresses()
  206. {
  207. const QByteArray address = ui_->addressEdit->text().toUtf8();
  208. const RegisterMonitorResult result = service_.addRange(
  209. std::string(address.constData(), static_cast<std::size_t>(address.size())),
  210. ui_->countSpinBox->value());
  211. if (result.succeeded)
  212. {
  213. reloadAddresses();
  214. ui_->addressEdit->selectAll();
  215. emit monitorAddressesChanged();
  216. emit operationMessage(tr("已添加 %1 个监控地址").arg(result.affectedCount));
  217. return;
  218. }
  219. handleResult(tr("添加监控地址"), false, result.message);
  220. }
  221. void FreeMonitorWidget::removeSelectedAddresses()
  222. {
  223. std::set<int> rows;
  224. for (const QModelIndex &index : ui_->monitorTable->selectionModel()->selectedRows())
  225. {
  226. rows.insert(index.row());
  227. }
  228. std::vector<RegisterAddress> addresses;
  229. const std::vector<RegisterAddress> &all_addresses = service_.addresses();
  230. for (int row : rows)
  231. {
  232. if (row >= 0 && static_cast<std::size_t>(row) < all_addresses.size())
  233. {
  234. addresses.push_back(all_addresses.at(static_cast<std::size_t>(row)));
  235. }
  236. }
  237. const RegisterMonitorResult result = service_.remove(addresses);
  238. if (result.succeeded)
  239. {
  240. reloadAddresses();
  241. emit monitorAddressesChanged();
  242. emit operationMessage(tr("已删除 %1 个监控地址").arg(result.affectedCount));
  243. return;
  244. }
  245. handleResult(tr("删除监控地址"), false, result.message);
  246. }
  247. void FreeMonitorWidget::clearAddresses()
  248. {
  249. if (service_.addresses().empty())
  250. {
  251. return;
  252. }
  253. if (QMessageBox::question(
  254. this, tr("清空自由监控"), tr("确定清空当前监控表吗?"))
  255. != QMessageBox::Yes)
  256. {
  257. return;
  258. }
  259. const RegisterMonitorResult result = service_.clear();
  260. if (result.succeeded)
  261. {
  262. reloadAddresses();
  263. emit monitorAddressesChanged();
  264. emit operationMessage(tr("自由监控已清空"));
  265. return;
  266. }
  267. handleResult(tr("清空自由监控"), false, result.message);
  268. }
  269. void FreeMonitorWidget::handleResult(
  270. const QString &action, bool succeeded, const std::string &message)
  271. {
  272. if (!succeeded)
  273. {
  274. emit operationMessage(action + QStringLiteral(":") + fromUtf8(message));
  275. }
  276. }