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即可實現,同時動畫時間需要根據視圖大小動態調整。
好啦,主要代碼就這麼多了,還是挺簡單的。

4 總結

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

5 下載

示例代碼

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章