Qt編寫數據可視化大屏界面電子看板10-改造QCustomPlot

1、前言

爲了拋棄對QChart的依賴,以及echart的依賴,(固然,後期也會作qchart的版本和echart的版本,尤爲是echart的版本是確定會作的,畢竟echart的效果牛逼的一塌糊塗,全宇宙最牛逼吧。)特地對QCustomPlot進行了大刀闊斧的改造,固然這個改造不是直接在源碼上修改,這個就破壞了源碼的完整性,說不定被QCustomPlot的做者知道了有種被QJ的感受,我得改造是直接繼承QCustomPlot中的部分類開始的,好比爲了實現橫向柱狀圖,特地繼承自QCPItemRect類來實現的,包括了橫向柱狀圖和橫向柱狀分組圖。在這個橫向柱狀圖的自動計算過程當中,竟然用到了十幾年前學習的二元一次方程,自動計算數據和柱狀圖位置,給定兩個數據點繪製矩形。linux

QCustomPlot類作的很是好,做者將曲線圖和柱狀圖和其餘幾種形狀的圖,玩得神乎其神,本人直接跪了。尤爲是如今的2.0版本,比之前的1.0版本更加上了一個檔次,直接將各類功能拆分紅一個個小類,分層繪製,至關牛逼,好比要作個遊標,直接繼承QCPLayerable類,而後在void draw(QCPPainter *painter);中繪製本身的東西便可,QCustomPlot提供了一個很是完美的鼠標拉動縮放的二維座標系,還有對應的座標與屏幕座標轉換的函數,繼承自QCPItemRect這個東東,能夠任意繪製任意圖形,包括圓形矩形各類,本人有個大膽的想法就是,直接將那145個控件大全控件在QCustomPlot中繪製一遍,都是徹底可行的,這樣的話還支持滾輪任意縮放呢。sql

2、電子看板介紹

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

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=\x81ea\x5b9a\x4e49\x98ce\x683c 便可。此時打開軟件會應用配置文件中的顏色。
  8. 右鍵菜單能夠截圖保存,默認命名爲 配色方案名稱_佈局方案名稱.png 保存在snap目錄下。
  9. 若是是XP系統請先執行fixff.cmd,用來修復ffmpeg在XP上不可用的BUG。
  10. 在二級窗體的標題欄上右鍵彈出模塊菜單,能夠對單個模塊打開關閉,其餘地方右鍵全局菜單。
  11. 可執行文件下載地址:https://pan.baidu.com/s/1o97IGvZgTgDhlkuXQa4B0w 提取碼:r2bv。
  12. 會不按期更新程序,歡迎各位提出批評和建議。

6、效果圖

7、核心代碼

void CustomPlot::mouseMove(QMouseEvent *event)
{
    if (tracer == 0 || textTip == 0) {
        return;
    }

    //跟蹤鼠標點擊事件點擊位置
    QCPGraph *graph = (QCPGraph *)customPlot->plottableAt(event->pos(), true);
    QRect rect(0, 0, 1, 1);

    QString labx, laby;
    int offset = 10;
    bool toolTip = false;

    if(graph != 0) {
        double posKey;
        double key = 0, value = 0;
        QPoint p;
        p.setX(event->pos().x());
        p.setY(event->pos().y());

#ifdef old
        foreach(QCPData data, graph->data()->values()) {
            key = data.key;
            value = data.value;
#else
        for (int i = 0; i < graph->dataCount(); i++) {
            key = graph->dataMainKey(i);
            value = graph->dataMainValue(i);
#endif
            //取出對應key處的label標籤,若是標籤爲空則取key的字符串
            labx = customPlot->xAxis->tickVectorLabels().at(key);
            labx = labx.isEmpty() ? QString::number(key) : labx;

            //若是啓用了百分比則須要後面顯示百分比
            if (this->getPercentY()) {
                laby = QString("%1%").arg(value);
            } else {
                laby = QString("%1").arg(value);
            }

            posKey = customPlot->xAxis->coordToPixel(key);
            if(qAbs(posKey - event->pos().x()) <= offset) {
                double posx = graph->keyAxis()->coordToPixel(key);
                double posy = graph->valueAxis()->coordToPixel(value);
                rect.setRect(posx - offset, posy - offset, offset * 2, offset * 2);
                if(!rect.contains(event->pos())) {
                    continue;
                } else {
                    break;
                }
            }

            if(posKey - event->pos().x() > offset) {
                break;
            }
        }

        if(!graph->realVisibility()) {
            toolTip = false;
            tracer->setVisible(false);
            customPlot->replot();
        } else if(rect.contains(event->pos())) {
            toolTip = true;
            tracer->setVisible(true);
            tracer->setGraph(graph);
            tracer->setGraphKey(key);
            customPlot->replot();
        } else if(tracer->visible()) {
            toolTip = false;
            tracer->setVisible(false);
            customPlot->replot();
        }
    }
    else if(tracer->visible()) {
        toolTip = false;
        tracer->setVisible(false);
        customPlot->replot();
    }

    //處理提示信息
    if(toolTip) {
        //根據設定的提示信息位置調整
        double x = event->pos().x();
        double y = event->pos().y();
        if (toolTipPosition == 0) {
            //判斷曲線控件的位置已經當前鼠標位置作出調整
            bool right = (customPlot->width() - x < 90);
            bool bottom = (customPlot->height() - y < 50);
            if (right) {
                if (bottom) {
                    x = x - 80;
                    y = y - 50;
                } else {
                    x = x - 80;
                    y = y - 20;
                }
            } else {
                if (bottom) {
                    x = x + 10;
                    y = y - 50;
                } else {
                    x = x + 10;
                    y = y - 20;
                }
            }
        } else if (toolTipPosition == 1) {
            x = x - 30;
            y = y - 50;
        } else if (toolTipPosition == 2) {
            x = x + 10;
            y = y - 50;
        } else if (toolTipPosition == 3) {
            x = x + 10;
            y = y - 20;
        } else if (toolTipPosition == 4) {
            x = x + 10;
            y = y + 10;
        } else if (toolTipPosition == 5) {
            x = x - 30;
            y = y + 10;
        } else if (toolTipPosition == 6) {
            x = x - 75;
            y = y + 10;
        } else if (toolTipPosition == 7) {
            x = x - 80;
            y = y - 20;
        } else if (toolTipPosition == 8) {
            x = x - 80;
            y = y - 50;
        }

        QString text = "橫座標: " + labx + "\n當前值: " + laby;
        textTip->position->setCoords(x, y);
        textTip->setText(text);
        textTip->setVisible(true);
        customPlot->replot();
    } else {
        if (textTip->visible()) {
            textTip->setVisible(false);
            customPlot->replot();
        }
    }
}
相關文章
相關標籤/搜索