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();
相关推荐
Boilermaker199217 小时前
[Java 并发编程] Synchronized 锁升级
java·开发语言
MM_MS17 小时前
Halcon变量控制类型、数据类型转换、字符串格式化、元组操作
开发语言·人工智能·深度学习·算法·目标检测·计算机视觉·视觉检测
꧁Q༒ོγ꧂17 小时前
LaTeX 语法入门指南
开发语言·latex
njsgcs18 小时前
ue python二次开发启动教程+ 导入fbx到指定文件夹
开发语言·python·unreal engine·ue
alonewolf_9918 小时前
JDK17新特性全面解析:从语法革新到模块化革命
java·开发语言·jvm·jdk
古城小栈18 小时前
Rust 迭代器产出的引用层数——分水岭
开发语言·rust
ghie909018 小时前
基于MATLAB的TLBO算法优化实现与改进
开发语言·算法·matlab
恋爱绝缘体118 小时前
2020重学C++重构你的C++知识体系
java·开发语言·c++·算法·junit
wuk99818 小时前
VSC优化算法MATLAB实现
开发语言·算法·matlab
AI小怪兽18 小时前
基于YOLOv13的汽车零件分割系统(Python源码+数据集+Pyside6界面)
开发语言·python·yolo·无人机