qt toast

#include <QPushButton>
#include <QVBoxLayout>
#include <QWidget>
#include <QLabel>
#include <QHBoxLayout>
#include <QTimer>
#include <QPainter>
#include <QMap>
#include <QGridLayout>
#include <QLineEdit>
#include <QGraphicsDropShadowEffect>
#include <QDesktopWidget>
#include <QGroupBox>

// Toast类定义
class Toast : public QWidget
{
    Q_OBJECT

public:
    enum Position {
        Top = 0,
        Center,
        Bottom,
        TopLeft,
        TopRight,
        BottomLeft,
        BottomRight
    };

    enum ToastType {
        Info = 0,
        Success,
        Warning,
        Error
    };

    static void show(const QString& text,
                     int duration = 2000,
                     Position position = Bottom,
                     ToastType type = Info,
                     QWidget* parent = nullptr) {
        static QMap<QString, Toast*> activeToasts;

        QString key = QString("%1-%2-%3").arg(text).arg(static_cast<int>(type)).arg(static_cast<int>(position));

        if (activeToasts.contains(key)) {
            Toast* existingToast = activeToasts[key];
            existingToast->restartTimer(duration);
            return;
        }

        Toast* toast = new Toast(text, duration, position, type, parent);
        activeToasts[key] = toast;

        QObject::connect(toast, &Toast::destroyed, [key]() {
            activeToasts.remove(key);
        });

        toast->showToast();
    }

    static void info(const QString& text, int duration = 2000, Position position = Bottom, QWidget* parent = nullptr) {
        show(text, duration, position, Info, parent);
    }

    static void success(const QString& text, int duration = 2000, Position position = Bottom, QWidget* parent = nullptr) {
        show(text, duration, position, Success, parent);
    }

    static void warning(const QString& text, int duration = 2000, Position position = Bottom, QWidget* parent = nullptr) {
        show(text, duration, position, Warning, parent);
    }

    static void error(const QString& text, int duration = 2000, Position position = Bottom, QWidget* parent = nullptr) {
        show(text, duration, position, Error, parent);
    }

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

        // 绘制圆角背景
        painter.setBrush(getBackgroundColor());
        painter.setPen(Qt::NoPen);
        painter.drawRoundedRect(rect(), 8, 8);

        // 绘制图标
        if (!m_icon.isNull()) {
            int iconSize = 20;
            int iconX = 15;
            int iconY = (height() - iconSize) / 2;
            painter.drawPixmap(iconX, iconY, iconSize, iconSize, m_icon);
        }

        // 绘制文字
        painter.setPen(getTextColor());
        QFont font = painter.font();
        font.setPixelSize(14);
        painter.setFont(font);

        int textX = m_icon.isNull() ? 20 : 45;
        QRect textRect(textX, 0, width() - textX - 20, height());
        painter.drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, m_text);
    }

private:
    explicit Toast(const QString& text,
                   int duration,
                   Position position,
                   ToastType type,
                   QWidget* parent = nullptr)
        : QWidget(parent)
        , m_text(text)
        , m_duration(duration)
        , m_position(position)
        , m_type(type)
    {
        // 设置窗口属性
        setWindowFlags(Qt::FramelessWindowHint | Qt::Tool | Qt::WindowStaysOnTopHint);
        setAttribute(Qt::WA_TranslucentBackground);
        setAttribute(Qt::WA_DeleteOnClose);

        // 不要设置为ToolTip,可能会被系统隐藏
        setFocusPolicy(Qt::NoFocus);

        initUI();
        initTimer();

        // 添加阴影效果
        QGraphicsDropShadowEffect* shadowEffect = new QGraphicsDropShadowEffect(this);
        shadowEffect->setBlurRadius(15);
        shadowEffect->setColor(QColor(0, 0, 0, 80));
        shadowEffect->setOffset(0, 2);
        setGraphicsEffect(shadowEffect);
    }

    void initUI() {
        QFontMetrics fm(QFont("", 14));
        int textWidth = fm.width(m_text);

        // 设置图标
        switch (m_type) {
        case Success:
            m_icon = createColoredIcon(QColor(46, 125, 50), QChar(0x2713));  // 对勾
            break;
        case Warning:
            m_icon = createColoredIcon(QColor(237, 108, 2), QChar(0x26A0));  // 警告
            break;
        case Error:
            m_icon = createColoredIcon(QColor(211, 47, 47), QChar(0x26D4));  // 错误
            break;
        case Info:
        default:
            m_icon = createColoredIcon(QColor(2, 119, 189), QChar(0x2139));  // 信息
            break;
        }

        // 计算宽度
        int width = textWidth + 40;
        if (!m_icon.isNull()) width += 25;

        width = qMin(qMax(width, 150), 400);
        setFixedSize(width, 50);
    }

    QPixmap createColoredIcon(const QColor& color, QChar unicodeChar) {
        QPixmap pixmap(20, 20);
        pixmap.fill(Qt::transparent);

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

        painter.setBrush(color);
        painter.setPen(Qt::NoPen);
        painter.drawEllipse(0, 0, 20, 20);

        painter.setPen(Qt::white);
        QFont font = painter.font();
        font.setPixelSize(12);
        font.setBold(true);
        painter.setFont(font);
        painter.drawText(pixmap.rect(), Qt::AlignCenter, unicodeChar);

        return pixmap;
    }

    void initTimer() {
        m_timer = new QTimer(this);
        m_timer->setSingleShot(true);
        connect(m_timer, &QTimer::timeout, this, &Toast::hideToast);
    }


    void adjustPosition() {
        QWidget* parent = parentWidget();
        QRect screenRect = QApplication::desktop()->availableGeometry();

        int x = 0, y = 0;
        int margin = 20;

        switch (m_position) {
        case Top:
            x = screenRect.left() + (screenRect.width() - width()) / 2;
            y = screenRect.top() + margin;
            break;
        case Center:
            x = screenRect.left() + (screenRect.width() - width()) / 2;
            y = screenRect.top() + (screenRect.height() - height()) / 2;
            break;
        case TopLeft:
            x = screenRect.left() + margin;
            y = screenRect.top() + margin;
            break;
        case TopRight:
            x = screenRect.right() - width() - margin;
            y = screenRect.top() + margin;
            break;
        case BottomLeft:
            x = screenRect.left() + margin;
            y = screenRect.bottom() - height() - margin;
            break;
        case BottomRight:
            x = screenRect.right() - width() - margin;
            y = screenRect.bottom() - height() - margin;
            break;
        case Bottom:
        default:
            x = screenRect.left() + (screenRect.width() - width()) / 2;
            y = screenRect.bottom() - height() - margin;
            break;
        }

        move(x, y);
    }

    void showToast() {
        // 先调整位置
        adjustPosition();

        // 淡入效果
        setWindowOpacity(0.0);
        QWidget::show();
        QTimer::singleShot(10, this, [this]() {
            // 使用定时器来实现淡入效果
            for (int i = 0; i <= 100; i += 5) {
                setWindowOpacity(i / 100.0);
                QApplication::processEvents();
            }
            setWindowOpacity(1.0);
        });

        m_timer->start(m_duration);
    }

    void restartTimer(int duration) {
        if (m_timer) {
            m_timer->stop();
            m_timer->start(duration);
        }
    }

private slots:
    void hideToast() {
        // 淡出效果
        for (int i = 100; i >= 0; i -= 5) {
            setWindowOpacity(i / 100.0);
            QApplication::processEvents();
        }
        close();
    }

private:
    QColor getBackgroundColor() const {
        switch (m_type) {
        case Success: return QColor(237, 247, 237);
        case Warning: return QColor(255, 243, 224);
        case Error: return QColor(253, 237, 237);
        case Info:
        default: return QColor(229, 246, 253);
        }
    }

    QColor getTextColor() const {
        switch (m_type) {
        case Success: return QColor(30, 70, 32);
        case Warning: return QColor(102, 60, 0);
        case Error: return QColor(95, 33, 32);
        case Info:
        default: return QColor(1, 67, 97);
        }
    }

private:
    QString m_text;
    int m_duration;
    Position m_position;
    ToastType m_type;
    QPixmap m_icon;
    QTimer* m_timer = nullptr;
};

  

posted @ 2025-12-18 16:38  tdyx  阅读(3)  评论(0)    收藏  举报