1. 程式人生 > >Qt編寫資料視覺化大屏介面電子看板11-自定義控制元件

Qt編寫資料視覺化大屏介面電子看板11-自定義控制元件

一、前言

說到自定義控制元件,我是感覺特別熟悉的幾個字,本人親自原創的自定義控制元件超過110個,都是來自各個行業的具體應用真實需求,而不是憑空捏造的,當然有幾個小控制元件也有點湊數的嫌疑,在編寫整個資料視覺化大屏介面電子看板系統中,也用到了四五個自定義的控制元件,比如那個環形百分比圖,多型進度條,合格率儀表盤,速度儀表盤等,這些控制元件在現有的類中是沒有的,需要用QPainter這個牛逼的工具來繪製,類似於神筆馬良似的,給我一個畫筆,可以畫出任意你想要的圖形,好比我常說的心中有座標,萬物皆painter。

自定義控制元件為了適應整體換膚,需要用Q_PROPERTY類指定,類似於元物件,用Q_PROPERTY指定的東西,可以直接樣式表控制,比如GaugePercent{qproperty-baseColor:#FF0000;}就可以對所有的GaugePercent類進行顏色更換,而且是動態更換,用Q_PROPERTY指定的東西還可以直接出現在Qtcreator的右側屬性欄,直接修改屬性即可,所見即所得,非常方便。

二、電子看板介紹

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

三、功能特點

  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. 每個模組都可以自定義採集速度,如果是資料庫採集會自動排隊處理。

四、配置檔案說明

(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
ShowPercentY軸是否顯示百分比true
StepYY軸大尺度步長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

五、特別說明

  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. 會不定期更新程式,歡迎各位提出批評和建議。

六、效果圖

七、核心程式碼

void ProgressRing::paintEvent(QPaintEvent *)
{
    int width = this->width();
    int height = this->height();
    int side = qMin(width, height);

    //繪製準備工作,啟用反鋸齒,平移座標軸中心,等比例縮放
    QPainter painter(this);
    painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);
    painter.translate(width / 2, height / 2);
    painter.scale(side / 200.0, side / 200.0);

    //繪製背景
    drawBg(&painter);
    //繪製進度
    drawRing(&painter);

    //繪製間隔,重新繪製一個圓遮住,產生間距效果
    if (ringPadding > 0) {
        drawPadding(&painter);
    }

    //繪製中間圓
    drawCircle(&painter);
    //繪製當前值
    drawValue(&painter);
}

void ProgressRing::drawBg(QPainter *painter)
{
    int radius = 99;
    painter->save();
    painter->setPen(Qt::NoPen);
    //這裡有個技巧,如果沒有間距則設定成圓環的背景色
    painter->setBrush(ringPadding == 0 ? ringBgColor : bgColor);
    painter->drawEllipse(-radius, -radius, radius * 2, radius * 2);
    painter->restore();
}

void ProgressRing::drawRing(QPainter *painter)
{
    int radius = 99 - ringPadding;
    painter->save();
    painter->setPen(Qt::NoPen);
    painter->setBrush(ringColor);

    QRectF rect(-radius, -radius, radius * 2, radius * 2);

    //計算總範圍角度,當前值範圍角度,剩餘值範圍角度
    double angleAll = 360.0;
    double angleCurrent = angleAll * ((currentValue - minValue) / (maxValue - minValue));
    double angleOther = angleAll - angleCurrent;

    //如果逆時針
    if (!clockWise) {
        angleCurrent = -angleCurrent;
        angleOther = -angleOther;
    }

    //動態設定當前進度顏色
    QColor color = ringColor;
    if (alarmMode == 1) {
        if (currentValue >= ringValue3) {
            color = ringColor3;
        } else if (currentValue >= ringValue2) {
            color = ringColor2;
        } else {
            color = ringColor1;
        }
    } else if (alarmMode == 2) {
        if (currentValue <= ringValue1) {
            color = ringColor1;
        } else if (currentValue <= ringValue2) {
            color = ringColor2;
        } else {
            color = ringColor3;
        }
    }

    //繪製當前值餅圓
    painter->setBrush(color);
    painter->drawPie(rect, (startAngle - angleCurrent) * 16, angleCurrent * 16);

    //繪製剩餘值餅圓
    painter->setBrush(ringBgColor);
    painter->drawPie(rect, (startAngle - angleCurrent - angleOther) * 16, angleOther * 16);

    painter->restore();
}

void ProgressRing::drawPadding(QPainter *painter)
{
    int radius = 99 - ringWidth - ringPadding;
    painter->save();
    painter->setPen(Qt::NoPen);
    painter->setBrush(bgColor);
    painter->drawEllipse(-radius, -radius, radius * 2, radius * 2);
    painter->restore();
}

void ProgressRing::drawCircle(QPainter *painter)
{
    //文字的區域要減去進度的寬度及間距
    int radius = 99 - ringWidth - (ringPadding * 2);
    painter->save();
    painter->setPen(Qt::NoPen);
    painter->setBrush(circleColor);
    painter->drawEllipse(-radius, -radius, radius * 2, radius * 2);
    painter->restore();
}

void ProgressRing::drawValue(QPainter *painter)
{
    //文字的區域要減去進度的寬度及間距
    int radius = 99 - ringWidth - (ringPadding * 2);
    painter->save();
    painter->setPen(textColor);

    QFont font;
    int fontSize = radius - (showPercent ? 20 : 6);
    font.setPixelSize(fontSize);
    painter->setFont(font);

    QRectF textRect(-radius, -radius, radius * 2, radius * 2);
    QString strValue;
    if (showPercent) {
        double percent = (currentValue * 100) / (maxValue - minValue);
        strValue = QString("%1%").arg(percent, 0, 'f', precision);
    } else {
        strValue = QString("%1").arg(currentValue, 0, 'f', precision);
    }

    //如果定義了顯示的文字則優先顯示
    strValue = text.isEmpty() ? strValue : text;
    painter->drawText(textRect, Qt::AlignCenter, strValue);

    painter->r