本項目對設備的監控有四種視圖模式,能夠任意切換,數據監控、地圖監控、設備監控、曲線監控,其中數據監控是最經常使用的,因此在主界面導航中也排在第一位,綜合觀察分析了不少氣體安全或者組態監控軟件,大部分用戶習慣都是有個表格一行行顯示對應設備的實時數據和狀態等,加上一些特殊的顏色標識,這樣顯得更直觀,有時候還會分門別類展現。node
Qt提供了表格控件QTableWidget,能夠直接以行列的形式展現數據,使用接口和方法也是很是友好,直接new一個QTableWidgetItem而後指定行列位置setItem便可。通常在系統初始化的時候經過讀取數據庫中的設備列表實例化item而後加載,難點在於如何動態更新這些數據,並根據收到的值以不一樣的顏色顯示,爲此還專門寫了一個方法setColor來對傳進來的數據進行過濾,好比報警的值紅色加粗顯示,這些顏色還特地作了自定義,能夠在系統設置中分別設置低報、高報、離線、正常等各類顏色。mysql
在協議解析的類中,並非收到數據就立馬發送到數據表格中,那樣刷新頻率太大,沒有意義也沒有必要,由於絕大部分時間的數據實際上是不變的,因此在協議解析的類中,有一個隊列專門存儲的每一個設備對應的值,只有當值發生了變化,才須要從新發送到界面進行展現,設備上線下線也是一樣的處理,只有當設備首次上線或者離線的時候,才須要去更新狀態。linux
皮膚開源:https://gitee.com/feiyangqingyun/QWidgetDemo https://github.com/feiyangqingyun/QWidgetDemo 文件名稱:styledemoc++
體驗地址:https://gitee.com/feiyangqingyun/QWidgetExe https://github.com/feiyangqingyun/QWidgetExe 文件名稱:bin_sams.zipgit
void DeviceHelper::deviceValue(const QString &positionID, float value) { //下面的不會被頻繁執行,只有數據變更了纔會執行,已經在解析的地方作了過濾 //處理設備面板 if (App::PanelMode == 0) { foreach (frmDeviceNode *device, devices) { if (device->getPositionID() == positionID) { device->setValue(value); break; } } } else if (App::PanelMode == 1) { foreach (frmDeviceNode2 *device, devices2) { if (device->getPositionID() == positionID) { device->setValue(value); break; } } } //處理設備按鈕 bool alarm = false; foreach (ButtonDefence *btn, btns) { if (btn->property("positionID").toString() == positionID) { alarm = (btn->getButtonStatus() == ButtonDefence::ButtonStatus_Alarm); btn->setProperty("value", value); //有兩個傳感器 是開關量 數值是 一、2 顯示時 用正常 和異常代替 QString nodeType = btn->property("nodeType").toString(); if (nodeType == "SJ-0001" || nodeType == "JG-0001") { btn->setText(value == 1 ? "正常" : "異常"); } else { btn->setText(QString("%1 %2").arg(value).arg(btn->property("nodeSign").toString())); } break; } } //處理設備表格 int count = deviceData->rowCount(); for (int i = 0; i < count; i++) { QString id = deviceData->item(i, 1)->text(); if (id == positionID) { deviceData->item(i, 7)->setText(QString::number(value)); break; } } } void DeviceHelper::deviceAlarm(const QString &positionID, quint8 alarmType) { //0-濃度上限報警 2-濃度下限報警 5-其餘報警 bool alarm = (alarmType == 0 || alarmType == 2 || alarmType == 5); //處理設備面板 if (App::PanelMode == 0) { foreach (frmDeviceNode *device, devices) { if (device->getPositionID() == positionID) { device->setAlarm(alarm); break; } } } else if (App::PanelMode == 1) { foreach (frmDeviceNode2 *device, devices2) { if (device->getPositionID() == positionID) { device->setAlarm(alarm); break; } } } //處理設備按鈕 foreach (ButtonDefence *btn, btns) { if (btn->property("positionID").toString() == positionID) { btn->setButtonStatus(alarm ? ButtonDefence::ButtonStatus_Alarm : ButtonDefence::ButtonStatus_Arming); //切換到當前地圖 initDeviceMapCurrent(btn->property("nodeImage").toString()); break; } } //處理設備表格 int count = deviceData->rowCount(); for (int i = 0; i < count; i++) { QString id = deviceData->item(i, 1)->text(); if (id == positionID) { setColor(deviceData->item(i, 7), deviceData->item(i, 9), alarmType); break; } } //雲端數據同步 if (App::UseNetDB) { int nodeStatus = 1; if (alarmType == 0) { nodeStatus = 3; } else if (alarmType == 2) { nodeStatus = 2; } else if (alarmType == 5) { nodeStatus = 5; } QString sql = QString("update NodeData set NodeStatus='%1' where PositionID='%2'").arg(nodeStatus).arg(positionID); DbTcpClientThread::Instance()->append(sql); } } void DeviceHelper::setColor(QTableWidgetItem *itemValue, QTableWidgetItem *itemStatus, quint8 alarmType) { //0-低報 1-低報恢復 2-高報 3-高報恢復 5-其餘報警 6-其餘報警恢復 if (alarmType == 0) { itemValue->setForeground(QColor(App::ColorLimit)); itemStatus->setForeground(QColor(App::ColorLimit)); itemStatus->setText("低報"); } else if (alarmType == 2) { itemValue->setForeground(QColor(App::ColorUpper)); itemStatus->setForeground(QColor(App::ColorUpper)); itemStatus->setText("高報"); } else if (alarmType == 1 || alarmType == 3 || alarmType == 6) { itemValue->setForeground(QColor(App::ColorNormal)); itemStatus->setForeground(QColor(App::ColorNormal)); itemStatus->setText("正常"); } else if (alarmType == 4) { itemValue->setForeground(QColor(App::ColorZero)); itemStatus->setForeground(QColor(App::ColorZero)); itemStatus->setText("離線"); itemValue->setText("0"); } else if (alarmType == 5) { itemValue->setForeground(QColor(App::ColorOther)); itemStatus->setForeground(QColor(App::ColorOther)); itemStatus->setText("失效"); } } void DeviceHelper::setColor(QTableWidgetItem *itemValue, QTableWidgetItem *itemStatus, float value, float max, float min, const QString &alarmType) { //這裏還有個未處理的,是否須要對初始值進行判斷報警 if (value == 0) { itemValue->setForeground(QColor(App::ColorZero)); itemStatus->setForeground(QColor(App::ColorZero)); } else if (value > max) { itemValue->setForeground(QColor(App::ColorUpper)); itemStatus->setForeground(QColor(App::ColorUpper)); } else if (value < min) { itemValue->setForeground(QColor(App::ColorLimit)); itemStatus->setForeground(QColor(App::ColorLimit)); } else { itemValue->setForeground(QColor(App::ColorNormal)); itemStatus->setForeground(QColor(App::ColorNormal)); } itemValue->setText(QString::number(value)); }