Qt实战14.告警信息滚动轮播控件

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 下载

示例代码

上一篇:Vue高阶用法:provide / inject


下一篇:RecyclerView实现多种item布局