Qt编写自定义控件:跑马灯文本控件

news2025/1/22 8:53:29
#ifndef RUNNINGTEXTWIDGET_H
#define RUNNINGTEXTWIDGET_H

#include <QWidget>

enum Direction
{
    North = 0, //上
    South, //下
    West,  //左
    East   //右
};

class RunningTextWidget : public QWidget
{
    Q_OBJECT
public:
    explicit RunningTextWidget(QWidget *parent = nullptr);
    void setText(const QString & newText);
    void setDirection(Direction newDirection);
    void setSpeed(uint newSpeed);

protected:
    void paintEvent(QPaintEvent *event) override final;

private:
    void onTime();
    std::shared_ptr<struct RunningTextWidgetPrivate> d_ptr;
};

#endif // RUNNINGTEXTWIDGET_H
#include "runningtextwidget.h"
#include <QPainter>
#include <QTimer>

struct RunningTextWidgetPrivate
{
    QString text{"飞流直下三千尺,疑是银河落九天"};
    QString drawText;
    QColor textColor{Qt::red};
    int offset{0};
    uint changeOffset{6};//调节变化速度
    RunningTextWidget * p_ptr;
    QSize verticalTextSize;
    Direction direction{Direction::South};
    RunningTextWidget * q_ptr;
    QTimer timer;

    void updateText();
    void updateVerticalTextBoundingSize();
    void move();
};

void RunningTextWidgetPrivate::updateText()
{
    if(direction == Direction::West || direction == Direction::East)
    {
        if(direction == Direction::East)
        {
            drawText.clear();;
            for (auto it = text.rbegin(); it != text.rend(); ++it)
            {
                drawText.append(*it);
            }
        }
        else
        {
            drawText = text;
        }
    }
    else
    {
        if(direction == Direction::South)
        {
            auto temp = text.split("", Qt::SkipEmptyParts).join("\n");
            drawText.clear();
            for (auto it = temp.rbegin(); it != temp.rend(); ++it)
            {
                drawText.append(*it);
            }
        }
        else
        {
            drawText = text.split("", Qt::SkipEmptyParts).join("\n");
        }

        updateVerticalTextBoundingSize();
    }
}

void RunningTextWidgetPrivate::updateVerticalTextBoundingSize()
{
    auto lines = drawText.split("\n");

    int maxWidth = 0;
    int totalHeight = 0;

    auto fontMetrics = q_ptr->fontMetrics();
    for (const auto &line : lines)
    {
        int width = fontMetrics.horizontalAdvance(line);
        if (width > maxWidth)
        {
            maxWidth = width;
        }
        totalHeight += fontMetrics.height();
        totalHeight += fontMetrics.leading();
    }
    totalHeight -= fontMetrics.descent();

    verticalTextSize = QSize(maxWidth, totalHeight);
}

void RunningTextWidgetPrivate::move()
{
    if(direction == Direction::West)
    {
        offset -= changeOffset;
        if(offset < 0 && abs(offset) >= q_ptr->fontMetrics().horizontalAdvance(drawText))
        {
            offset = q_ptr->width();
        }
    }
    else if(direction == Direction::East)
    {
        offset += changeOffset;
        if(offset > q_ptr->width())
        {
            offset = -q_ptr->fontMetrics().horizontalAdvance(drawText);
        }
    }
    else if(direction == Direction::North)
    {
        offset -= changeOffset;
        if(offset < 0 && abs(offset) >= verticalTextSize.height())
        {
            offset = q_ptr->height();
        }
    }
    else if(direction == Direction::South)
    {
        offset += changeOffset;
        if(offset > q_ptr->height())
        {
            offset = -verticalTextSize.height();
        }
    }
}

RunningTextWidget::RunningTextWidget(QWidget *parent)
    : QWidget{parent}
{
    d_ptr = std::make_shared<RunningTextWidgetPrivate>();
    d_ptr->q_ptr = this;
    connect(&d_ptr->timer,&QTimer::timeout,this,&RunningTextWidget::onTime);
    d_ptr->timer.start(40);

    auto font = this->font();
    font.setPixelSize(36);
    font.setBold(true);
    setFont(font);

    d_ptr->updateText();
}

void RunningTextWidget::setText(const QString &newText)
{
    d_ptr->text = newText;
    d_ptr->offset = 0;
    d_ptr->updateText();
    update();
}

void RunningTextWidget::setDirection(Direction newDirection)
{
    d_ptr->direction = newDirection;
    d_ptr->updateText();
}

void RunningTextWidget::setSpeed(uint newSpeed)
{
    d_ptr->changeOffset = newSpeed;
}

void RunningTextWidget::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    painter.setFont(this->font());
    painter.setPen(d_ptr->textColor);
    auto bRect = painter.boundingRect(rect(),Qt::AlignCenter,d_ptr->drawText);

    if(d_ptr->direction == Direction::West || d_ptr->direction == Direction::East)
    {
        painter.drawText(QRect(d_ptr->offset,bRect.y(),bRect.width(),bRect.height()),d_ptr->drawText);
    }
    else
    {
        painter.drawText(QRect(bRect.x(),d_ptr->offset,bRect.width(),bRect.height()),Qt::AlignCenter,d_ptr->drawText);
    }
}

void RunningTextWidget::onTime()
{
    d_ptr->move();
    update();
}
#include "runningtextwidget.h"
#include <QApplication>
#include <QHBoxLayout>
#include <QRandomGenerator>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    QWidget widget;
    auto hb = new QHBoxLayout(&widget);
    for(int i = 0;i < 4;++i)
    {
        auto w = new RunningTextWidget;
        w->setDirection(static_cast<Direction>(i));
        w->setSpeed(QRandomGenerator::global()->bounded(8, 50));
        hb->addWidget(w);
    }
    widget.show();
    return a.exec();
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1957587.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

第二期:集成电路(IC)——智能世界的微观建筑大师

嘿&#xff0c;小伙伴们&#xff01;&#x1f44b; 我是你们的老朋友小竹笋&#xff0c;一名热爱创作和技术的工程师。上一期我们聊了聊AI芯片&#xff0c;这次我们要深入到更微观的层面&#xff0c;来探究集成电路&#xff08;IC&#xff09;的世界。准备好一起探索了吗&#…

50+受高度近视屈光参差与白内障阻碍,巫雷院长一场手术“均衡”双眼

周女士双眼近视度数一直差异很大&#xff0c;这么多年从未看清。“这次”是因为发现视力逐渐下降检查得知并发性白内障&#xff0c;以屈光性白内障手术得以一次性治疗多个问题。 周女士小时候就近视了&#xff0c;那时家里不重视&#xff0c;且自己觉得戴眼镜“不好”&#xf…

强制重新启动 iPhone

官网&#xff1a;https://support.apple.com/zh-cn/guide/iphone/iph8903c3ee6/ios 按住调高音量按钮&#xff0c;然后快速松开。按住调低音量按钮&#xff0c;然后快速松开。按住侧边按钮。当 Apple 标志出现时&#xff0c;松开侧边按钮。

【初阶数据结构题目】1.返回倒数第k个节点

文章目录 题目描述代码 题目描述 返回倒数第k个节点 代码 /*** Definition for singly-linked list.* struct ListNode {* int val;* struct ListNode *next;* };*/typedef struct ListNode ListNode; int kthToLast(struct ListNode* head, int k){ListNode* t hea…

保姆级教程!!教你通过【Pycharm远程】连接服务器运行项目代码

小罗碎碎念 这篇文章主要解决一个问题——我有服务器&#xff0c;但是不知道怎么拿来写代码&#xff0c;跑深度学习项目。确实&#xff0c;玩深度学习的成本比较高&#xff0c;无论是前期的学习成本&#xff0c;还是你需要具备的硬件成本&#xff0c;都是拦路虎。小罗没有办法…

「12月·长沙」人工智能与网络安全国际学术会议(ISAICS 2024)

人工智能与网络安全国际学术会议(ISAICS 2024)将于2024年12月20日-2024年12月22日在湖南长沙召开。会议中发表的文章将会被收录,并于见刊后提交EI核心索引。会议旨在在为国内与国际学者搭建交流平台,推进不同学科领域的融合发展&#xff0c;就当今人工智能与网络安全范畴内各学…

史上最全的Seata教学并且连接springcloudAlibaba进行使用

来都来了点个赞收藏一下在走呗~~&#x1f339;&#x1f339;玫瑰 一、Seata是什么 Seata&#xff08;Simple Extensible Autonomous Transaction Architecture&#xff0c;简单可扩展自治事务框架&#xff09;是一种分布式事务解决方案&#xff0c;旨在解决分布式系统中的事务…

【iOS】通知的底层原理(实现)

通知 一. 通知的基本使用 1. 基本概念 NSNotification 是iOS中一个调度消息通知的类,采用单例模式设计,在程序中实现传值、回调等地方应用很广。在iOS中&#xff0c;NSNotification & NSNotificationCenter是使用观察者模式来实现的用于跨层传递消息。 概要&#xff1a…

C++ 关键字与库函数 学习总结

sizeof与strlen 含义 sizeof&#xff1a;是一个操作符&#xff0c;用于计算数据类型或变量的大小&#xff08;以字节为单位&#xff09;。在编译时求值strlen&#xff1a; 是一个函数&#xff0c;用于计算字符串的长度&#xff08;不包括终止符 \0&#xff09;。在运行时求值不…

QT基础教程(QEvent事件和事件过滤器)

文章目录 前言一、具体介绍二、具体案例1.鼠标事件2.键盘事件3.窗口事件 三、事件过滤器事件过滤器的工作原理 总结 前言 本篇文章将带大家来学习QT中的QEvent事件&#xff0c;QEvent 是 Qt 框架中的一个核心类&#xff0c;用于处理各种事件。在 Qt 的事件处理系统中&#xff…

framebuffer(帧缓冲)

framebuffer 在Linux系统中&#xff0c;Framebuffer通常是指Framebuffer设备&#xff0c;它是一种特殊的字符设备&#xff0c;在Linux系统中&#xff0c;Framebuffer设备使得程序员可以通过其设定的函数接口直接访问硬件&#xff0c;而不需要通过CPU。 framebuffer的一般操作流…

江协科技51单片机学习- p29 DS18B20温度传感器

&#x1f680;write in front&#x1f680; &#x1f50e;大家好&#xff0c;我是黄桃罐头&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流 &#x1f381;欢迎各位→点赞&#x1f44d; 收藏⭐️ 留言&#x1f4dd;​…

2-49 基于matlab的表面缺陷的自动分割

基于matlab的表面缺陷的自动分割。基于梯度图操作&#xff0c;对得到的梯度图进行开运算去噪&#xff0c;二值化后经过一定的形态学处理得到缺陷轮廓。通过在两个尺度上同时操作&#xff0c;高尺度的图精细&#xff0c;噪点多&#xff1b;低尺度的图粗糙&#xff0c;但包含的噪…

【人工智能】人工智能概述(二)人工智能的关键技术

文章目录 一. 机器学习与深度学习1. 机器学习2. 深度学习 二. 计算机视觉1. 基本概念和分类2. 未来计算机视觉面临的主要挑战 三. 自然语言处理1. 基本概念与分类2. 自然语言处理面临的四大挑战 四. 知识图谱1. 基本概念2. 应用场景 五. SLAM技术1. 基本概念2. 主要分类 六. 人…

Halcon 感兴趣区域

一 感兴趣区域 机器视觉中感兴趣区域是必不可少的&#xff0c;尤其是Halcon。其目的是将集中处理图像中的特定部分。此方法将区域信息与图像矩阵相结合&#xff0c;只与图像中的某些区域保持关联&#xff0c;减少图像处理的像素。使用ROI的优势&#xff1a;第一&#xff0c;减…

Redis学习[1] ——基本概念和数据类型

Redis学习[1] ——基本概念和数据类型 一、Redis基础概念 1.1 Redis是什么&#xff0c;有什么特点&#xff1f; Redis是一个基于**内存的数据库&#xff0c;因此读写速度非常快**&#xff0c;常用作缓存、消息队列、分布式锁和键值存储数据库。支持多种数据结构&#xff1a;…

网络协议二 : 使用Cisco Packet Traceer工具模拟网络环境,集线器,网桥,交换机,路由器,IP,同一网段

1. 安装 Cisco Packet Tracer baidu 网盘地址&#xff0c;感谢大神分享 安装&#xff0c;破解&#xff0c;中文化&#xff0c;都有说明&#xff0c;建议使用7.x的那个版本&#xff0c;感觉比8.x的翻译要完整一点 https://pan.baidu.com/s/18iWBOfhJJRhqgQqdNQcfMQ?pwddcch#…

【C++】实验七

题目&#xff1a; 1、自己找规律利用数组完成下列数据的输出&#xff1a; 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765 思路&#xff1a;数据是斐波那契数列的前20项。该数列特点是除第一第二项以…

公交车客流统计产品介绍

在当今智能科技与交通运输融合的背景下&#xff0c;一款新型公交车客流统计产品应运而生。该系统采用先进的双目客流统计算法&#xff0c;实现多通道视频的客流数据统计&#xff0c;以其高实时性和98%的准确性在复杂环境下准确统计人数。 产品特点 双目客流统计算法 该公交车客…

Vscode报错:line too long (84 > 79 characters)

原因&#xff1a;不允许一行超过79个字母&#xff0c;但是该行代码超出该范围。 参考博客&#xff1a;解决Vs CodeFlake8 报错line too long (108 &#xff1e; 79 characters)Flake8(E501)_flake8 line too long-CSDN博客