Qt編寫數據可視化大屏界面電子看板12-數據庫採集

1、前言

數據採集是整個數據可視化大屏界面電子看板系統核心功能,沒有數據源,這僅僅是個玩具UI,沒啥用,固然默認作了定時器模擬數據,產生隨機數據,這個能夠直接配置文件修改來選擇採用何種數據採集方法,總結了一下基本上會有這樣幾種數據源,timer-模擬數據 db-數據庫採集 tcp-網絡採集 http-post請求,大量的web會選擇採用http做爲post網絡請求來獲取數據,而對於本人來講,更喜歡用數據庫做爲數據源,這樣能夠避免不少扯皮的事情,好比請求出錯或者獲得錯誤的數據等,而數據庫是死的,不涉及到其餘任何程序的干擾,也不須要作任何對接,只要規範好數據庫表和字段便可。mysql

本系統默認採用mysql數據庫,固然也支持其餘數據,甚至包括了sqlite這種小衆的數據庫,Qt對數據庫的封裝也是很是完美的,反正在我使用的這些年過程當中,沒有發現過什麼BUG或者事故,Qt提供了一個統一的數據庫接口,這對於程序員來講是巨大的福音,好比查詢數據庫,QSqlQuery查詢的結果,統一用query.value(i)或者,這個數據是通用類型,能夠轉換成你想要的數據類型,這樣就拓展性和兼容性很是強大了。linux

在本系統中,各個模塊的採集間隔均可以自由定義,默認5秒鐘採集一次,我採用的辦法是,開啓一個線程,在線程中打開數據,而後提供方法插入要執行的sql語句,插入的同時記得給定標識符,以便返回結果的時候標識,這樣就造成了一個萬能的方法,自動排隊,也不會說衝突之類的,一個類管理全部的數據庫採集,文字末尾會貼出完整代碼。程序員

2、電子看板介紹

電子看板是目視化管理的一種表現形式,即對數據的情況一目瞭然地表現,主要是對於管理項目,它經過利用形象直觀而又色彩適宜的各類視覺感知信息來組織現場生產活動,目視管理依據人類的生理特徵,在生產現場充分利用信號燈、標識牌、符號顏色等方式來發出視覺信號,鮮明準確地刺激人的神經末梢,快速地傳遞信息,形象直觀地將潛在的問題和浪費現象都顯現出來。以便任何人均可以及時掌握管理現狀和必要的情報,從而可以快速制定並實施應對措施。所以,管理看板是發現問題、解決問題的很是有效且直觀的手段,是優秀的現場管理必不可少的工具之一。web

3、功能特色

  1. 總體總共分三級界面,一級界面是總體佈局,二級界面是單個功能模塊,三級界面是單個控件。
  2. 子控件包括餅圖+圓環圖+曲線圖+柱狀圖+柱狀分組圖+橫向柱狀圖+橫向柱狀分組圖+合格率控件+百分比控件+進度控件+設備狀態面板+表格數據+地圖控件(包括動態閃爍點+遷徙圖等)+視頻控件+其餘控件等。
  3. 二級界面能夠自由拖動懸浮,支持最小化最大化關閉,響應雙擊自定義標題欄。
  4. 數據源支持數據庫採集(默認)、網絡通訊、網絡請求等,可自由設定每一個子界面的採集間隔即數據刷新頻率。
  5. 採用純QWidget編寫,支持Qt4.6到Qt5.12.3任何版本,支持嵌入式linux好比樹莓派、香橙派、全志、imx6等。
  6. 提供三個內核版本,自定義控件版本+qchart版本+echart版本。
  7. 內置多套配色風格樣式,默認紫色,支持任何分辨率。
  8. 可設置標題+目標分辨率+佈局方案,啓動當即應用。
  9. 可設置主背景顏色+面板顏色+十字線遊標顏色。
  10. 可設置多條曲線顏色,沒有設置顏色的狀況下內置15套精美顏色隨機應用。
  11. 可設置標題欄背景顏色+文字顏色。
  12. 可設置曲線圖表背景顏色+文字顏色+網格顏色。
  13. 可設置正常顏色+警惕顏色+報警顏色+禁用顏色+百分比進度顏色。
  14. 可分別設置各類字體大小,好比全局+軟件名稱+標題欄+子標題欄+加粗標籤等。
  15. 可設置標題欄高度+表頭高度+行高度。
  16. 曲線支持遊標+懸停高亮數據點和顯示值,柱狀圖支持頂部(可設置頂端+上部+中間+底部)顯示數據,所有自適應計算位置。
  17. 主界面直接鼠標右鍵切換佈局+配色方案+關閉開啓某個二級窗體。
  18. 自動記憶全部子窗口的大小和位置,下次啓動當即應用。
  19. 動態加載佈局方案菜單,能夠動態新建佈局、恢復佈局、保存佈局、另存佈局等,用戶能夠製造任意佈局。
  20. 二級窗體,雙擊從主窗體分離出來浮動,能夠自由調整大小。再次雙擊標題欄最大化,再次雙擊還原。
  21. 每一個模塊均可以自定義採集速度,若是是數據庫採集會自動排隊處理。

4、配置文件說明

(1)、基本配置參數

字段 描述 默認值
WorkMode 工做模式 timer-模擬數據 db-數據庫採集 tcp-網絡採集 http-post請求 db
MapStyle 中間地圖樣式 image-靜態圖片 point-閃爍點 move-遷徙圖 point
Title 軟件標題,顯示在軟件中間頂部 數字化工廠信息中心
Ratio 分辨率,目前無心義 4096*216
Layout 佈局方案,每次切換佈局方案之後都會保存 完整佈局
Theme 配色方案,每次切換配色方案之後都會保存 紫色風格
VideoAddr 視頻流地址,視頻模塊播放的視頻地址 鳳凰衛視
AutoRun 是否開機啓動 false
MoveEnable 模塊是否能夠拖動,啓用之後模塊能夠任意拖動 true
CutLeftBottom 底部佈局左側是否切掉 true
CutRightBottom 底部佈局右側是否切掉 true
StaticLine 是否繪製靜態定位線,爲假則繪製遊標十字線 true
ShowPercent Y軸是否顯示百分比 true
StepY Y軸大尺度步長 6
CursorHideTime 用戶不操做鼠標自動隱藏鼠標的時間間隔,單位秒 5

(2)、顏色配置參數

字段 描述 默認值
ColorMainBg 主背景顏色 QColor(4, 7, 38)
ColorPanelBg 面板背景顏色 QColor(26, 29, 60)
ColorLine 十字線定位線顏色 QColor(255, 0, 0)
ColorLine1 線條1顏色 QColor(0, 176, 180)
ColorLine2 線條2顏色 QColor(32, 159, 223)
ColorLine3 線條3顏色 QColor(255, 192, 0)
ColorTitleBg 標題欄背景顏色 QColor(48, 48, 85)
ColorTitleText 標題欄文字顏色 QColor(255, 255, 255)
ColorChartBg 曲線圖表背景顏色 QColor(38, 41, 74)
ColorChartText 曲線圖表文字顏色 QColor(250, 250, 250)
ColorChartGrid 曲線圖表網格顏色 QColor(180, 180, 180)
ColorOk 正常顏色 QColor(0, 176, 180)
ColorLow 警惕顏色 QColor(255, 192, 0)
ColorAlarm 報警顏色 QColor(214, 77, 84)
ColorDisable 禁用背景顏色 QColor(210, 210, 210)
ColorPercent 環形百分比背景顏色 QColor(0, 254, 254)

(3)、字體和尺寸配置參數

字段 描述 默認值
MainFont 全局字號 微軟雅黑,12
NameFont 軟件名稱字號 19
LabFont 加粗標籤字號 12
DeviceFont 設備面板字號 12
SubTitleFont 模塊子標題欄字號 13
TitleFont 模塊標題欄字號 15
TitleHeight 模塊標題欄高度 23
HeadHeight 表格表頭高度 28
RowHeight 表格行高度 25

(4)、採集速度配置參數

字段 描述 默認值
IntervalModule1 模塊1採集間隔 5000
IntervalModule2 模塊2採集間隔 5000
IntervalModule3 模塊3採集間隔 5000
IntervalModule4 模塊4採集間隔 5000
IntervalModule5 模塊5採集間隔 5000
IntervalModule6 模塊6採集間隔 5000
IntervalModule7 模塊7採集間隔 5000
IntervalModule8 模塊8採集間隔 5000

(5)、本地數據庫配置參數

字段 描述 默認值
LocalDBType 本地數據庫類型,Sqlite、Mysql等 Mysql
LocalDBIP 本地數據庫主機地址 127.0.0.1
LocalDBPort 本地數據庫端口 3306
LocalDBName 本地數據庫名稱 bigscreen
LocalUserName 本地數據庫用戶名 root
LocalUserPwd 本地數據庫密碼 root

5、特別說明

  1. 可執行文件同級文件夾有layout+layout_1440+layout_1920,程序默認自動識別分辨率並加載對應的佈局文件夾,好比1920分辨率則從layout_1920文件夾加載佈局,並做爲總體佈局文件夾。
  2. 程序默認是模擬數據,若是須要從數據庫採集則修改配置文件WorkMode=db便可。
  3. 若是發現佈局拖動亂了,能夠直接鼠標右鍵選擇恢復佈局便可,在保存佈局之前。
  4. 在中間地圖模塊鼠標右鍵能夠彈出菜單,切換佈局和配色方案等。
  5. 在模塊的標題欄上右鍵能夠彈出默認的dock菜單,用來顯示和隱藏各模塊。
  6. 軟件關閉過程當中會自動保存佈局,下次啓動之後自動應用。
  7. 若是使用的默認的默認的配色方案好比紫色風格,則配置文件中的顏色所有無效,會自動應用代碼中的顏色,若是須要啓用自定義的顏色,則將配置文件的 Theme=x81eax5b9ax4e49x98cex683c 便可。此時打開軟件會應用配置文件中的顏色。
  8. 右鍵菜單能夠截圖保存,默認命名爲 配色方案名稱_佈局方案名稱.png 保存在snap目錄下。
  9. 若是是XP系統請先執行fixff.cmd,用來修復ffmpeg在XP上不可用的BUG。
  10. 在二級窗體的標題欄上右鍵彈出模塊菜單,能夠對單個模塊打開關閉,其餘地方右鍵全局菜單。
  11. 可執行文件下載地址:https://pan.baidu.com/s/1o97I... 提取碼:r2bv。
  12. 會不按期更新程序,歡迎各位提出批評和建議。

6、效果圖

7、核心代碼

#include "datadb.h"
#include "quiwidget.h"

QScopedPointer<DataDb> DataDb::self;
DataDb *DataDb::Instance()
{
    if (self.isNull()) {
        static QMutex mutex;
        QMutexLocker locker(&mutex);
        if (self.isNull()) {
            self.reset(new DataDb);
        }
    }

    return self.data();
}

DataDb::DataDb(QObject *parent) : QThread(parent)
{
    stopped = false;

    dbOkLocal = false;
    errorCount = 0;
    lastCheckTimeLocal = QDateTime::currentDateTime();

    checkConn = false;
    checkInterval = 30;

    dbTypeLocal = DbType_MySql;
    connNameLocal = "qt_sql_default_connection";
    hostNameLocal = "127.0.0.1";
    portLocal = 3306;
    dbNameLocal = "db_mysql";
    userNameLocal = "root";
    userPwdLocal = "root";

    connect(this, SIGNAL(error(QString)), this, SLOT(doError(QString)));
}

DataDb::~DataDb()
{
    this->stop();
    this->wait();
}

void DataDb::run()
{
    //打開數據庫
    openDb();
    msleep(1000);

    while(!stopped) {
        //定時執行一次校驗數據庫鏈接是否正常
        QDateTime now = QDateTime::currentDateTime();
        if (checkConn && lastCheckTimeLocal.secsTo(now) >= checkInterval) {
            checkDb();
            lastCheckTimeLocal = now;
            continue;
        }

        //若是數據庫鏈接正常則處理數據,不正常則重連數據庫
        if (!dbOkLocal) {
            if (errorCount >= 3) {
                closeDb();
                msleep(3000);
                openDb();
                emit debug(QString("重連本地數據庫%1").arg(dbOkLocal ? "成功" : "失敗"));
                msleep(3000);
            }
        } else {
            //取出隊列sql語句執行
            if (tags.count() > 0) {
                //從最前面開始取
                QMutexLocker locker(&mutex);
                QString tag = tags.takeFirst();
                QString sql = sqls.takeFirst();
                //qDebug() << TIMEMS << tag << sql;

                QSqlQuery query(dbConnLocal);
                if (query.exec(sql)) {
                    QStringList data;
                    while(query.next()) {
                        int count = query.record().count();
                        for (int i = 0; i < count; i++) {
                            data << query.value(i).toString();
                        }
                    }

                    emit receiveData(tag, data);
                }
            }

            msleep(10);
        }
    }

    stopped = false;
}

void DataDb::doError(const QString &msg)
{
    QUIHelper::showMessageBoxError(msg, 3);
}

bool DataDb::openDb()
{
    //能夠自行增長其餘數據庫的支持
    if (dbTypeLocal == DbType_Sqlite) {
        dbConnLocal = QSqlDatabase::addDatabase("QSQLITE", connNameLocal);
        dbConnLocal.setDatabaseName(dbNameLocal);
    } else if (dbTypeLocal == DbType_MySql) {
        dbConnLocal = QSqlDatabase::addDatabase("QMYSQL", connNameLocal);
        dbConnLocal.setConnectOptions("MYSQL_OPT_RECONNECT=1;MYSQL_OPT_CONNECT_TIMEOUT=1;MYSQL_OPT_READ_TIMEOUT=1;MYSQL_OPT_WRITE_TIMEOUT=1");
        dbConnLocal.setHostName(hostNameLocal);
        dbConnLocal.setPort(portLocal);
        dbConnLocal.setDatabaseName(dbNameLocal);
        dbConnLocal.setUserName(userNameLocal);
        dbConnLocal.setPassword(userPwdLocal);
    }

    errorCount = 0;
    dbOkLocal = dbConnLocal.open();
    if (!dbOkLocal) {
        emit error("打開數據庫失敗!請檢查用戶名和密碼是否正確!");
    }

    return dbOkLocal;
}

bool DataDb::checkDb()
{
    QDateTime dtStart = QDateTime::currentDateTime();

    QString sql = "select 1";
    QSqlQuery query(dbConnLocal);
    dbOkLocal = query.exec(sql);
    dbOkLocal ? (errorCount = 0) : errorCount++;

    QDateTime dtEnd = QDateTime::currentDateTime();
    double ms = dtStart.msecsTo(dtEnd);
    emit debug(QString("檢查本地數據庫鏈接(共 %1 條/用時 %2 秒)").arg(1).arg(QString::number(ms / 1000, 'f', 3)));

    return dbOkLocal;
}

void DataDb::closeDb()
{
    dbConnLocal.close();
    QSqlDatabase::removeDatabase(connNameLocal);
    dbOkLocal = false;
    emit debug("關閉本地數據庫");
}

void DataDb::stop()
{
    stopped = true;
}

void DataDb::setConnInfo(DataDb::DbType dbType, const QString &connName,
                         const QString &hostName, int port, const QString &dbName,
                         const QString &userName, const QString &userPwd)
{
    this->dbTypeLocal = dbType;
    this->connNameLocal = connName;
    this->hostNameLocal = hostName;
    this->portLocal = port;
    this->dbNameLocal = dbName;
    this->userNameLocal = userName;
    this->userPwdLocal = userPwd;
}

void DataDb::setCheckConn(bool checkConn)
{
    this->checkConn = checkConn;
}

void DataDb::setCheckInterval(int checkInterval)
{
    if (checkInterval > 5 && this->checkInterval != checkInterval) {
        this->checkInterval = checkInterval;
    }
}

QSqlDatabase DataDb::getDb()
{
    return dbConnLocal;
}

bool DataDb::getOk()
{
    return dbOkLocal;
}

void DataDb::select(const QString &tableName, const QString &columnName, bool append)
{
    //超過隊列中最大數量限制則無需處理
    QMutexLocker locker(&mutex);
    if (tags.count() < 100) {
        //若是是append表示追加在隊列末尾,不然插到最前面優先級最高
        if (append) {
            tags << tableName;
            sqls << QString("select %1 from %2").arg(columnName).arg(tableName);
        } else {
            tags.insert(0, tableName);
            sqls.insert(0, QString("select %1 from %2").arg(columnName).arg(tableName));
        }
    }
}
相關文章
相關標籤/搜索