Qt自绘制动态字体,模糊的,毛茸茸的fuzzy。

cpp 复制代码
#ifndef FUZZYTEXTWIDGET_H
#define FUZZYTEXTWIDGET_H

#include <QWidget>
#include <QTimer>
#include <QColor>
#include <QFont>

class FuzzyTextWidget : public QWidget
{
    Q_OBJECT

public:
    explicit FuzzyTextWidget(QWidget *parent = nullptr);
    ~FuzzyTextWidget();

    void setText(const QString &text);
    void setFontSize(const QString &fontSize);
    void setFontWeight(QFont::Weight fontWeight);
    void setFontFamily(const QString &fontFamily);
    void setColor(const QColor &color);
    void setEnableHover(bool enable);
    void setBaseIntensity(double intensity);
    void setHoverIntensity(double intensity);

protected:
    void paintEvent(QPaintEvent *event) override;
    void mouseMoveEvent(QMouseEvent *event) override;
    void leaveEvent(QEvent *event) override;
    void resizeEvent(QResizeEvent *event) override;

private slots:
    void updateFuzzyEffect();

private:
    void initializeOffscreenBuffer();
    void updateTextMetrics();
    double parseFontSize(const QString &fontSizeStr, double defaultSize);

    QString m_text;
    QString m_fontSizeStr;
    QFont::Weight m_fontWeight;
    QString m_fontFamily;
    QColor m_color;
    bool m_enableHover;
    double m_baseIntensity;
    double m_hoverIntensity;

    QTimer *m_animationTimer;
    QPixmap m_offscreenPixmap;
    bool m_isHovering;
    QRect m_textBoundingRect;
    double m_numericFontSize;
};

#endif // FUZZYTEXTWIDGET_H
cpp 复制代码
#include "FuzzyTextWidget.h"
#include <QPainter>
#include <QPaintEvent>
#include <QMouseEvent>
#include <QDebug>
#include <QScreen>
#include <QApplication>
#include <QFontMetricsF>
#include <QRandomGenerator>

FuzzyTextWidget::FuzzyTextWidget(QWidget *parent)
    : QWidget(parent),
    m_text("Hello, Qt!"),
    m_fontSizeStr("clamp(2rem, 10vw, 10rem)"),
    m_fontWeight(QFont::Black),
    m_fontFamily("Arial"),
    m_color(Qt::white),
    m_enableHover(true),
    m_baseIntensity(0.18),
    m_hoverIntensity(0.5),
    m_isHovering(false),
    m_numericFontSize(0.0)
{
    setAttribute(Qt::WA_TranslucentBackground);
    setMouseTracking(true);

    m_animationTimer = new QTimer(this);
    connect(m_animationTimer, &QTimer::timeout, this, &FuzzyTextWidget::updateFuzzyEffect);
    m_animationTimer->start(16);

    updateTextMetrics();
    initializeOffscreenBuffer();
    setMinimumSize(m_offscreenPixmap.size() + QSize(100, 0));
}

FuzzyTextWidget::~FuzzyTextWidget()
{
    m_animationTimer->stop();
    delete m_animationTimer;
}

void FuzzyTextWidget::setText(const QString &text)
{
    if (m_text != text) {
        m_text = text;
        updateTextMetrics();
        initializeOffscreenBuffer();
        update();
    }
}

void FuzzyTextWidget::setFontSize(const QString &fontSize)
{
    if (m_fontSizeStr != fontSize)
    {
        m_fontSizeStr = fontSize;
        updateTextMetrics();
        initializeOffscreenBuffer();
        update();
    }
}

void FuzzyTextWidget::setFontWeight(QFont::Weight fontWeight)
{
    if (m_fontWeight != fontWeight)
    {
        m_fontWeight = fontWeight;
        updateTextMetrics();
        initializeOffscreenBuffer();
        update();
    }
}

void FuzzyTextWidget::setFontFamily(const QString &fontFamily)
{
    if (m_fontFamily != fontFamily)
    {
        m_fontFamily = fontFamily;
        updateTextMetrics();
        initializeOffscreenBuffer();
        update();
    }
}

void FuzzyTextWidget::setColor(const QColor &color)
{
    if (m_color != color)
    {
        m_color = color;
        initializeOffscreenBuffer();
        update();
    }
}

void FuzzyTextWidget::setEnableHover(bool enable)
{
    m_enableHover = enable;
    if (!m_enableHover) {
        m_isHovering = false;
        update();
    }
}

void FuzzyTextWidget::setBaseIntensity(double intensity)
{
    m_baseIntensity = intensity;
}

void FuzzyTextWidget::setHoverIntensity(double intensity)
{
    m_hoverIntensity = intensity;
}

double FuzzyTextWidget::parseFontSize(const QString &fontSizeStr, double defaultSize)
{
    if (fontSizeStr.endsWith("px", Qt::CaseInsensitive))
    {
        return fontSizeStr.chopped(2).toDouble();
    }
    else if (fontSizeStr.endsWith("rem", Qt::CaseInsensitive))
    {
        return fontSizeStr.chopped(3).toDouble() * 16.0;
    }
    else if (fontSizeStr.endsWith("vw", Qt::CaseInsensitive))
    {
        QScreen *screen = QGuiApplication::primaryScreen();
        if (screen)
        {
            return fontSizeStr.chopped(2).toDouble() / 100.0 * screen->geometry().width();
        }
        return defaultSize;
    }
    else if (fontSizeStr.startsWith("clamp(", Qt::CaseInsensitive) && fontSizeStr.endsWith(")"))
    {
        QString content = fontSizeStr.mid(6, fontSizeStr.length() - 7);
        QStringList parts = content.split(",", Qt::SkipEmptyParts);
        if (parts.size() == 3) {
            double minVal = parseFontSize(parts[0].trimmed(), defaultSize);
            double preferredVal = parseFontSize(parts[1].trimmed(), defaultSize);
            double maxVal = parseFontSize(parts[2].trimmed(), defaultSize);
            return qBound(minVal, preferredVal, maxVal);
        }
    }
    return defaultSize;
}

void FuzzyTextWidget::updateTextMetrics()
{
    QFont font;
    font.setFamily(m_fontFamily);
    font.setWeight(m_fontWeight);
    m_numericFontSize = parseFontSize(m_fontSizeStr, 48.0);
    font.setPixelSize(static_cast<int>(m_numericFontSize));

    QFontMetricsF metrics(font);
    m_textBoundingRect = metrics.boundingRect(m_text).toRect();

    int extraWidthBuffer = 10;
    int horizontalMargin = 50;
    int verticalMargin = 0;

    int offscreenWidth = m_textBoundingRect.width() + extraWidthBuffer;
    int tightHeight = m_textBoundingRect.height();

    setFixedSize(offscreenWidth + horizontalMargin * 2, tightHeight + verticalMargin * 2);

    qDebug() << "Calculated font size:" << m_numericFontSize;
    qDebug() << "Text bounding rect:" << m_textBoundingRect;
    qDebug() << "Widget fixed size:" << size();
}

void FuzzyTextWidget::initializeOffscreenBuffer()
{
    if (m_text.isEmpty())
    {
        m_offscreenPixmap = QPixmap();
        return;
    }

    updateTextMetrics();

    int offscreenWidth = m_textBoundingRect.width() + 10;
    int offscreenHeight = m_textBoundingRect.height();

    m_offscreenPixmap = QPixmap(offscreenWidth, offscreenHeight);
    m_offscreenPixmap.fill(Qt::transparent);

    QPainter painter(&m_offscreenPixmap);
    painter.setRenderHint(QPainter::Antialiasing);

    QFont font;
    font.setFamily(m_fontFamily);
    font.setWeight(m_fontWeight);
    font.setPixelSize(static_cast<int>(m_numericFontSize));
    painter.setFont(font);
    painter.setPen(m_color);

    painter.drawText(5 - m_textBoundingRect.left(), -m_textBoundingRect.top(), m_text);
}

void FuzzyTextWidget::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);

    if (m_offscreenPixmap.isNull() || m_text.isEmpty())
    {
        return;
    }

    const int fuzzRange = 30;
    double intensity = m_isHovering ? m_hoverIntensity : m_baseIntensity;

    for (int j = 0; j < m_offscreenPixmap.height(); j++)
    {
        int dx = static_cast<int>(intensity * (QRandomGenerator::global()->generateDouble() - 0.5) * fuzzRange);

        painter.drawPixmap(dx + 50,
                           j + 0,
                           m_offscreenPixmap,
                           0,
                           j,
                           m_offscreenPixmap.width(),
                           1);
    }
}

void FuzzyTextWidget::mouseMoveEvent(QMouseEvent *event)
{
    if (m_enableHover)
    {
        QRect interactiveArea(55, 0, m_textBoundingRect.width(), m_textBoundingRect.height());
        bool nowHovering = interactiveArea.contains(event->pos());

        if (nowHovering != m_isHovering)
        {
            m_isHovering = nowHovering;
            update();
        }
    }
    QWidget::mouseMoveEvent(event);
}

void FuzzyTextWidget::leaveEvent(QEvent *event)
{
    if (m_enableHover && m_isHovering)
    {
        m_isHovering = false;
        update();
    }
    QWidget::leaveEvent(event);
}

void FuzzyTextWidget::resizeEvent(QResizeEvent *event)
{
    updateTextMetrics();
    initializeOffscreenBuffer();
    QWidget::resizeEvent(event);
}

void FuzzyTextWidget::updateFuzzyEffect()
{
    update();
}

使用说明

cpp 复制代码
FuzzyTextWidget *pt1=new FuzzyTextWidget();
   pt1-> setText("gogo");
    pt1->show();
相关推荐
识途老码5 小时前
python装饰器
开发语言·python
JIngJaneIL5 小时前
基于Java饮食营养管理信息平台系统(源码+数据库+文档)
java·开发语言·数据库·vue.js·spring boot
fresh hacker5 小时前
【Python数据分析】速通NumPy
开发语言·python·数据挖掘·数据分析·numpy
长安第一美人5 小时前
整车控制器标定软件介绍 || 汽车标定协议CPP
开发语言·qt
宠..5 小时前
获取输入内容
开发语言·c++·qt
郝学胜-神的一滴5 小时前
Linux系统调用中断机制深度解析
linux·运维·服务器·开发语言·c++·程序人生
古城小栈5 小时前
Go 语言 WebAssembly 原生支持:前后端一体化开发详解
开发语言·golang·wasm
悟能不能悟5 小时前
JAVA 中dao层的实体应该属于哪个层次VO,还是DTO,或者其他
java·开发语言
二狗哈6 小时前
Cesium快速入门17:与entity和primitive交互
开发语言·前端·javascript·3d·webgl·cesium·地图可视化