1. 程式人生 > >Qt編寫資料視覺化大屏介面電子看板3-新建佈局

Qt編寫資料視覺化大屏介面電子看板3-新建佈局

一、前言

能夠新建佈局,也是資料視覺化大屏介面電子看板系統中的必備功能之一,新建佈局這樣的功能一般做到右鍵選單中,單擊新建佈局選單,彈出輸入框要求輸入新的佈局的名稱,為了更符合國情,直接支援中文名稱,儲存成配置檔案直接中文名稱命名,這樣方便使用者理解,Qt5以來對亂碼的問題解決的就比較好了,不像Qt4時代稍不留神就亂碼了,Qt5只要保證原始碼檔案utf-8編碼基本上就很少遇到亂碼問題了。新建佈局必須要有個預設的窗體排列,Qt中的dock窗體,預設佈局會以窗體的sizehint作為大小參照標準,也不一定是完全正確的,還跟窗體中的子控制元件有關係,不過這些都不影響佈局以後重新從配置檔案載入的佈局,QMainWindow提供saveState()函式直接儲存當前窗體的所有佈局位置大小等資訊到配置檔案,至於配置檔案的內容格式,那是人類無法理解的格式,反正我是看不懂,這些都沒有關係的,你重新用restoreState()函式載入讀取配置檔案的資訊時,會自動應用,這樣就很爽很完美了。

二、電子看板介紹

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

三、功能特點

  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請求timer
Title軟體標題,顯示在軟體中間頂部數字化工廠資訊中心
Ratio解析度,目前無意義4096*216
Layout佈局方案,每次切換佈局方案以後都會儲存完整佈局
Theme配色方案,每次切換配色方案以後都會儲存紫色風格
VideoAddr視訊流地址,視訊模組播放的視訊地址鳳凰衛視
AutoRun是否開機啟動false
MoveEnable模組是否可以拖動,啟用以後模組可以任意拖動true
CutLeftBottom底部佈局左側是否切掉true
CutRightBottom底部佈局右側是否切掉true
StaticLine是否繪製靜態定位線,為假則繪製遊標十字線true

(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. 可執行檔案下載地址:https://pan.baidu.com/s/1o97IGvZgTgDhlkuXQa4B0w 提取碼:r2bv ,會不定期更新程式,歡迎各位提出批評和建議。

六、效果圖

七、核心程式碼

#include "frmmodulecenter.h"
#include "ui_frmmodulecenter.h"
#include "quiwidget.h"

frmModuleCenter::frmModuleCenter(QWidget *parent) : QWidget(parent), ui(new Ui::frmModuleCenter)
{
    ui->setupUi(this);
    this->initForm();
}

frmModuleCenter::~frmModuleCenter()
{
    delete ui;
}

bool frmModuleCenter::eventFilter(QObject *watched, QEvent *event)
{
    if (watched == this) {
        if (event->type() == QEvent::MouseButtonPress) {
            if (qApp->mouseButtons() == Qt::RightButton) {
                menuMain->exec(QCursor::pos());
            }
        }
    }

    return QWidget::eventFilter(watched, event);
}

void frmModuleCenter::initForm()
{
    ui->labName->setText(App::Title);
    this->installEventFilter(this);

    //滑鼠右鍵選單
    menuMain = new QMenu(this);

    //從目錄下找佈局檔案自動生成選單
    menuLayout = menuMain->addMenu("佈局方案");
    QDir dir(QUIHelper::appPath() + "/layout");
    QStringList files = dir.entryList(QStringList() << "*.ini");
    foreach (QString file, files) {
        QString name = file.split(".").first();
        menuLayout->addAction(name, this, SLOT(changeLayout()));
    }

    menuTheme = menuMain->addMenu("配色方案");
    menuTheme->addAction("紫色風格", this, SLOT(changeTheme()));
    menuTheme->addAction("藍色風格", this, SLOT(changeTheme()));
    menuTheme->addAction("深藍風格", this, SLOT(changeTheme()));
    menuTheme->addAction("黑色風格", this, SLOT(changeTheme()));
    menuTheme->addAction("自定義風格", this, SLOT(changeTheme()));
    menuMain->addSeparator();

    menuMain->addAction("新建佈局", this, SLOT(doAction()));
    menuMain->addAction("恢復佈局", this, SLOT(doAction()));
    menuMain->addAction("儲存佈局", this, SLOT(doAction()));
    menuMain->addAction("佈局另存", this, SLOT(doAction()));
    menuMain->addSeparator();

    menuMain->addAction("擷取螢幕", this, SLOT(doAction()));
    menuMain->addAction("退出系統", this, SLOT(doAction()));

    //設定選單允許複選框+選中配置檔案對應選單
    actionLayout = menuLayout->actions();
    foreach (QAction *action, actionLayout) {
        action->setCheckable(true);
        action->setChecked(action->text() == App::Layout);
    }

    actionTheme = menuTheme->actions();
    foreach (QAction *action, actionTheme) {
        action->setCheckable(true);
        action->setChecked(action->text() == App::Theme);
    }
}

void frmModuleCenter::changeLayout()
{
    QAction *ac = (QAction *)sender();
    emit changeLayout(ac->text());
    foreach (QAction *action, actionLayout) {
        action->setChecked(action == ac);
    }
}

void frmModuleCenter::changeTheme()
{
    QAction *ac = (QAction *)sender();
    emit changeTheme(ac->text());
    foreach (QAction *action, actionTheme) {
        action->setChecked(action == ac);
    }
}

void frmModuleCenter::addLayout(const QString &layout, int type)
{
    if (!layout.isEmpty()) {
        //判斷名稱不能重複
        foreach (QAction *action, actionLayout) {
            if (action->text() == layout) {
                QUIHelper::showMessageBoxError("佈局已經存在,請重新輸入!", 3);
                return;
            }
        }

        //增加右鍵選單中的佈局子選單
        QAction *action = menuLayout->addAction(layout, this, SLOT(changeLayout()));
        //取消原有所有選中
        foreach (QAction *action, actionLayout) {
            action->setChecked(false);
        }

        action->setCheckable(true);
        action->setChecked(true);
        actionLayout.append(action);
        emit saveLayout(layout, type);
    }
}

void frmModuleCenter::doAction()
{
    QAction *action = (QAction *)sender();
    QString text = action->text();

    if (text == "新建佈局") {
        QString layout = QUIHelper::showInputBox("佈局名稱");
        addLayout(layout, 0);
    } else if (text == "恢復佈局") {
        emit saveLayout("", 1);
    } else if (text == "儲存佈局") {
        if (QUIHelper::showMessageBoxQuestion("確定要儲存嗎?儲存後不可恢復!") == QMessageBox::Yes) {
            emit saveLayout(App::Layout, 2);
            QUIHelper::showMessageBoxInfo("恭喜,儲存當前佈局成功!", 3);
        }
    } else if (text == "佈局另存") {
        QString layout = QUIHelper::showInputBox("佈局名稱");
        addLayout(layout, 3);
    } else if (text == "擷取螢幕") {
        QWidget *w = (QWidget *)this->parent();
        if (w == 0) {
            return;
        }

        QPixmap pix;
        int x = 0;
        int y = 0;
        int width = w->width() - 0;
        int height = w->height() - 0;

#if (QT_VERSION <= QT_VERSION_CHECK(5,0,0))
        pix = pix.grabWindow(w->winId(), x, y, width, height);
#else
        QScreen *pscreen = QApplication::primaryScreen();
        pix = pscreen->grabWindow(w->winId(), x, y, width, height);
#endif

        QString file = QString("%1/snap/%2_%3.png").arg(QUIHelper::appPath()).arg(App::Theme).arg(App::Layout);
        pix.save(file, "png");
    } else if (text == "退出系統") {
        emit closeAll(