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();
相关推荐
m0_748708051 天前
C++中的观察者模式实战
开发语言·c++·算法
qq_537562671 天前
跨语言调用C++接口
开发语言·c++·算法
wjs20241 天前
DOM CDATA
开发语言
Tingjct1 天前
【初阶数据结构-二叉树】
c语言·开发语言·数据结构·算法
猷咪1 天前
C++基础
开发语言·c++
IT·小灰灰1 天前
30行PHP,利用硅基流动API,网页客服瞬间上线
开发语言·人工智能·aigc·php
快点好好学习吧1 天前
phpize 依赖 php-config 获取 PHP 信息的庖丁解牛
android·开发语言·php
秦老师Q1 天前
php入门教程(超详细,一篇就够了!!!)
开发语言·mysql·php·db
烟锁池塘柳01 天前
解决Google Scholar “We‘re sorry... but your computer or network may be sending automated queries.”的问题
开发语言
是誰萆微了承諾1 天前
php 对接deepseek
android·开发语言·php