Qt實戰14.告警信息滾動輪播控件


1 需求描述

做一個獨立的控件,該控件能夠滾動輪播報警信息,告警信息分為一般、嚴重、危險三個等級,分別用不同顏色做標記。

2 設計思路

做滾動輪播效果,優先想到Qt的動畫框架,同時考慮到圖形視圖框架的易用性,實現上應該會簡單不少,所以該控件會使用圖形視圖框架並結合動畫框架實現。

  • 每一條告警信息用QGraphicsTextItem表示
  • 由於整體要使用動畫輪播,所有的QGraphicsTextItem會添加到一個QGraphicsItemGroup中,方便做整體動畫
  • 動畫使用QVariantAnimation即可,畢竟輪播只是改變了QGraphicsItemGroup的y坐標
  • 為了能夠適應窗口大小的變化,需要動態調整場景的大小和動畫參數

3 代碼實現

控件為QGraphicsView的子類,設定了自定義的場景類,場景封裝在控件內部,場景提供了必要的接口,例如添加、清空告警信息:

3.1 AlarmHistoryScene.h

class AlarmHistoryScene : public QGraphicsScene
{
    Q_OBJECT

public:
    explicit AlarmHistoryScene(QObject *parent = 0);

    void addAlarmText(WarningLevel level, const QString &alarm);
    void clear();

private:
    void updateAnimation();

private:
    QStringList m_alarmList;
    QGraphicsItemGroup *m_pItemGroup = nullptr;
    QVariantAnimation *m_pAnimation = nullptr;
};

addAlarmText添加告警信息接口,clear清空告警信息,updateAnimation會在初次啟動或窗口大小變化時自動調用。

3.2 AlarmHistoryScene.cpp

AlarmHistoryScene::AlarmHistoryScene(QObject *parent) : QGraphicsScene(parent)
{
    m_pItemGroup = new QGraphicsItemGroup();

    addItem(m_pItemGroup);
    m_pItemGroup->setPos(0, 0);

    connect(this, &AlarmHistoryScene::sceneRectChanged, this, &AlarmHistoryScene::updateAnimation);
}

void AlarmHistoryScene::addAlarmText(WarningLevel level ,const QString &alarm)
{
    QString detail = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss")
            .append(QStringLiteral(":"))
            .append(alarm);

    QGraphicsTextItem *item = new QGraphicsTextItem(detail);

    QFont font;
    font.setFamily("System");
    font.setPixelSize(12);

    item->setFont(font);
    switch (level) {
    case WarningLevel::Normal:
        item->setDefaultTextColor(QColor(227, 207, 87));
        break;
    case WarningLevel::Serious:
        item->setDefaultTextColor(QColor(243, 130, 19));
        break;
    case WarningLevel::Danger:
        item->setDefaultTextColor(QColor("red"));
        break;
    default:
        break;
    }

    int count = m_pItemGroup->childItems().count();

    item->setPos(0, m_pItemGroup->y() + count * (font.pixelSize() + 2));
    m_pItemGroup->addToGroup(item);

    updateAnimation();
}

根據日志等級實例化QGraphicsTextItem並添加到m_pItemGroup中,再更新下動畫,這里沒啥可說的。

void AlarmHistoryScene::clear()
{
    if (m_pAnimation) {
        m_pAnimation->stop();
        m_pAnimation->deleteLater();
        m_pAnimation = nullptr;
    }

    m_pItemGroup->setPos(0, 0);
    auto list = m_pItemGroup->childItems();
    int count = list.count();
    for (int i = 0; i < count; ++i) {
        auto item = list.at(i);
        m_pItemGroup->removeFromGroup(item);
        removeItem(item);
        delete item;
    }
}

這里主要是關閉動畫,並清空所有告警信息。

void AlarmHistoryScene::updateAnimation()
{
    if (m_pAnimation) {
        m_pAnimation->stop();
        m_pAnimation->deleteLater();
        m_pAnimation = nullptr;
    }

    m_pAnimation = new QVariantAnimation(this);
    connect(m_pAnimation, &QVariantAnimation::valueChanged, this, [=](const QVariant &value) {
        m_pItemGroup->setPos(0, value.toDouble());
    });
    m_pAnimation->setLoopCount(-1);

    qreal sceneHeight = this->sceneRect().height();
    m_pItemGroup->setPos(0, sceneHeight);

    m_pAnimation->setDuration((sceneHeight + m_pItemGroup->boundingRect().height()) * 12);
    m_pAnimation->setStartValue(sceneHeight);
    m_pAnimation->setEndValue(-m_pItemGroup->boundingRect().height());
    m_pAnimation->start();
}

更新動畫,作用於m_pItemGroup,輪播只需要改變y坐標值,所以使用QVariantAnimation即可實現。

3.3 AlarmHistoryView.cpp

場景封裝在視圖內部,這里需要根據視圖大小動態調整場景大小,以便使動畫適應窗口。

AlarmHistoryView::AlarmHistoryView(QWidget *parent) : QGraphicsView(parent)
{
    m_pScene = new AlarmHistoryScene(this);
    setScene(m_pScene);

    setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
}

void AlarmHistoryView::addAlarmText(WarningLevel level, const QString &alarm)
{
    m_pScene->addAlarmText(level, alarm);
}

void AlarmHistoryView::resizeEvent(QResizeEvent *event)
{
    QGraphicsView::resizeEvent(event);
    m_pScene->setSceneRect(0, 0, this->size().width(), this->size().height());
}

好啦,主要代碼就這么多了,還是挺簡單的。

4 總結

Qt圖形視圖框架異常強大,結合動畫框架能夠實現很多酷炫效果,這里也只用到了一點點皮毛,多看看Qt的Demo程序會有很多意外收獲,一般人我不告訴他,哈哈。溜了溜了。。。新年快樂!

5 下載

示例代碼


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM