Qt widget 弹窗动画控件

   开坑一个系列来分享一下我自己做的QT应用,这个应用还只是雏形很多功能并没有完成,但是关于界面的功能已经实现了许多,用麻雀虽小五脏俱全来形容挺合适。

感兴趣的可以下载源码:Commits · TTTTHBBBB/Coord (github.com)

  Qt中实现弹窗效果,首先需要自定义一个widget,关键要做的就是使用QPropertyAnimation来控制弹窗的位置,在设置动画的初始位置需要将弹窗底部的初始位置和结束位置设置在窗口的上方,这样就可以实现弹窗的弹出和回弹。动画的效果选择:QEasingCurve::OutBounce和QEasingCurve::InBounce达到弹出和弹回的效果。

  弹窗的所有图标,文本,以及背景都是使用Qpainter重新绘制的,在父类中设置窗口的显示时,如果父类的类型是window那么是可以正常显示的;但是如果父类是widget或者时frame,而你的父类使用了QSS,那么就会出现一个BUG,父类的样式可能会覆盖弹窗的绘制,导致无法显示图标。正常效果如下:

#include <QPainter>
#include <QPen>
#include <QtMath>
#include <QPolygonF>
#include <QVector>

#include "flickwindow.h"
#include "ui_flickwindow.h"

FlickWindow::FlickWindow(QWidget *parent ,FLICKTYPE type)
    : QFrame(parent)
    , filcktype(type)
    , ui(new Ui::FlickWindow)
{
    ui->setupUi(this);
    this->Init();
}

void FlickWindow::Init()
{
    ui->frameBtn->installEventFilter(this);
    continueTime = new QTimer();
    continueTime->setInterval(1500);

    ShowAnimation = new QPropertyAnimation(this,"geometry");
    HideAnimation = new QPropertyAnimation(this,"geometry");

    if(QWidget *parentWidget = this->parentWidget())
    {
        int width = parentWidget->width();
        int height = 50;
        this->setFixedWidth(width);
        this->setFixedHeight(height);
        this->setGeometry(0,-height,width,height);

        //设置弹出动画
        ShowAnimation->setDuration(800);
        ShowAnimation->setStartValue(QRect(0,-height,width,height));
        ShowAnimation->setEndValue(QRect(0,0,width,height));
        ShowAnimation->setEasingCurve(QEasingCurve::OutBounce);

        //设置弹回动画
        HideAnimation->setDuration(800);
        HideAnimation->setStartValue(QRect(0,0,width,height));
        HideAnimation->setEndValue(QRect(0,-height,width,height));
        HideAnimation->setEasingCurve(QEasingCurve::InBounce);
    }

    connect(continueTime, &QTimer::timeout, this, &FlickWindow::Slot_timeout);
    connect(ShowAnimation, &QPropertyAnimation::finished, this,[=](){
        continueTime->start();
    });
    connect(HideAnimation, &QPropertyAnimation::finished, this,[=](){
        this->hide();
    });
}

void FlickWindow::setFlickWidth(int width)
{
    if(width <= 150) return ;
    this->setFixedWidth(width);
}

void FlickWindow::showEvent(QShowEvent *event)
{
    Q_UNUSED(event);
    if(ShowAnimation!=nullptr)
    {
        ShowAnimation->start();
    }
}

void FlickWindow::hideEvent(QHideEvent *event)
{
    Q_UNUSED(event);
    if(HideAnimation!=nullptr)
    {
        HideAnimation->start();
    }
}

void FlickWindow::Slot_timeout()
{
    continueTime->stop();
    if(HideAnimation!=nullptr)
    {
        HideAnimation->start();
    }
}

void FlickWindow::setFlickType(FLICKTYPE type)
{
    filcktype = type;
    update();
}

void FlickWindow::setFlickText(QString str)
{
    if(!str.isEmpty())
    {
        flicktext = str;
    }
}

void FlickWindow::resizeEvent(QResizeEvent *event)
{
    Q_UNUSED(event);
    update();
}

int FlickWindow::getFontsize(QRectF rect)
{
    int fontSize = 30;
    QFont font("微软雅黑", fontSize);

    QFontMetrics metrics(font);
    QSize textSize = metrics.size(Qt::TextSingleLine, flicktext);

    while (textSize.width() > rect.width() || textSize.height() > rect.height())
    {
        fontSize--;
        if (fontSize <= 1) break;
        font.setPointSize(fontSize);
        metrics = QFontMetrics(font);
        textSize = metrics.size(Qt::TextSingleLine, flicktext);
    }

    return fontSize;
}

void FlickWindow::paintEvent(QPaintEvent *event)
{
    Q_UNUSED(event);

    QFrame::paintEvent(event);
    int btnwidth = this->width() - ui->frameBtn->width() - 10;
    int btnheight = (this->height() - (ui->frameBtn->height())) / 2 ;
    ui->frameBtn->move(btnwidth,btnheight);

    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);

    QRect titleRect = ui->frameTitle->rect();

    qreal textHeight = height() - 20;
    qreal textwidth = ui->frameText->width() - ui->frameBtn->width() - 10;
    QRectF textRect(ui->frameText->x()+15,ui->frameTitle->y()+10, textwidth, textHeight);
    int fontsize = getFontsize(textRect);

    QRect btnRect(ui->frameBtn->x()+10,(ui->frameBtn->height()-20)/2,20,20);

    switch (filcktype)
    {
        case FLICKTYPE::SUCCESS:
        {
            //绘制整体背景
            painter.setPen(Qt::NoPen);
            painter.setBrush(QColor(243,246,243));
            painter.drawRect(this->rect());

            //绘制标题区域背景
            painter.setBrush(QColor(51,170,127));
            painter.drawRect(titleRect);

            //绘制标题区图案
            QPen titlepen;
            titlepen.setStyle(Qt::SolidLine);
            titlepen.setColor(Qt::white);
            titlepen.setWidth(3);
            painter.setPen(titlepen);

            QPointF pointStart(10.0,25.0),pointCenter(20.0,35.0),pointEnd(titleRect.width()-10.0,10.0);
            painter.drawLine(pointStart,pointCenter);
            painter.drawLine(pointCenter,pointEnd);
            //绘制文字区
            painter.setPen(QPen(QColor(88,201,184)));
            painter.setFont(QFont("微软雅黑",fontsize));
            painter.drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, flicktext);

            //绘制按钮
            QPen pen;
            pen.setWidth(3);
            pen.setColor(QColor(45,128,96));
            pen.setStyle(Qt::SolidLine);
            painter.setPen(pen);

            QPoint topLeft = btnRect.topLeft();
            QPoint bottomRight = btnRect.bottomRight();
            QPoint topRight = btnRect.topRight();
            QPoint bottomLeft = btnRect.bottomLeft();

            painter.drawLine(topLeft,bottomRight);
            painter.drawLine(topRight,bottomLeft);

            break;
        }
        case FLICKTYPE::FAILD:
        {
            //绘制背景
            painter.setPen(Qt::NoPen);
            painter.setBrush(QColor(236,221,231));
            painter.drawRect(this->rect());

            //绘制标题区域背景
            painter.setBrush(QColor(255,88,102));
            painter.drawRect(titleRect);

            //绘制标题区域图标
            QPen titlepen;
            titlepen.setStyle(Qt::SolidLine);
            titlepen.setColor(Qt::white);
            titlepen.setWidth(3);
            painter.setPen(titlepen);
            //绘制圆形
            qreal radius = titleRect.width() - 14.0;
            qreal TopLeftX = (titleRect.width()-radius)/2.0;
            qreal TopLeftY = (titleRect.width()-radius)/2.0;
            painter.drawEllipse(QRectF(TopLeftX,TopLeftY,radius,radius));
            //绘制斜线
            QPointF start(TopLeftX+(radius-radius*qCos(M_PI/4.0))/2.0, TopLeftY+(radius+radius*qSin(M_PI/4.0))/2.0);
            QPointF end(TopLeftX+(radius+radius*qCos(M_PI/4.0))/2.0, TopLeftY+(radius-radius*qSin(M_PI/4.0))/2.0);
            painter.drawLine(start,end);

            //绘制文字区
            painter.setPen(QPen(QColor(237,73,103)));
            painter.setFont(QFont("微软雅黑",fontsize));
            painter.drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, flicktext);

            //绘制按钮
            QPen pen;
            pen.setWidth(3);
            pen.setColor(QColor(204,44,51));
            pen.setStyle(Qt::SolidLine);
            painter.setPen(pen);

            QPoint topLeft = btnRect.topLeft();
            QPoint bottomRight = btnRect.bottomRight();
            QPoint topRight = btnRect.topRight();
            QPoint bottomLeft = btnRect.bottomLeft();

            painter.drawLine(topLeft,bottomRight);
            painter.drawLine(topRight,bottomLeft);

            break;
        }
        case FLICKTYPE::WARNING:
        {
            //绘制整体背景
            painter.setPen(Qt::NoPen);
            painter.setBrush(QColor(237,240,229));
            painter.drawRect(this->rect());

            //绘制标题区域背景
            painter.setBrush(QColor(199,160,0));
            painter.drawRect(titleRect);

            //绘制标题区域图标
            painter.setBrush(Qt::white);
            // 计算感叹号的圆圈和直线部分的尺寸
            int length = qMin(ui->frameTitle->width(), ui->frameTitle->height());

            // 计算感叹号的圆圈和直线部分的尺寸
            qreal topMargin = 7.0; // 上边距
            qreal linetoradius = 3.0; //直线和圆形之间的距离
            qreal circleRadius = length / 12.0;//圆所占据矩形大小
            qreal lineWidth = length / 16.0; //竖线的宽度
            qreal lineHeight = length - topMargin*2 - circleRadius - linetoradius;

            // 直线的起点
            qreal lineX = (length - lineWidth)/ 2.0;
            qreal lineY = topMargin;
            // 圆圈所占矩形的起始位置
            qreal circleX = (length - circleRadius)/ 2.0;
            qreal circleY = topMargin + lineHeight + linetoradius;
            // 绘制感叹号的直线部分
            painter.drawRect(QRectF(lineX, lineY, lineWidth, lineHeight));
            // 绘制感叹号的圆圈部分
            painter.drawEllipse(QRectF(circleX, circleY, circleRadius, circleRadius));

            //绘制文字区
            painter.setPen(QPen(QColor(223,212,192)));
            painter.setFont(QFont("微软雅黑",fontsize));
            painter.drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, flicktext);

            //绘制按钮
            QPen pen;
            pen.setWidth(3);
            pen.setColor(QColor(147,123,114));
            pen.setStyle(Qt::SolidLine);
            painter.setPen(pen);

            QPoint topLeft = btnRect.topLeft();
            QPoint bottomRight = btnRect.bottomRight();
            QPoint topRight = btnRect.topRight();
            QPoint bottomLeft = btnRect.bottomLeft();

            painter.drawLine(topLeft,bottomRight);
            painter.drawLine(topRight,bottomLeft);

            break;
        }
        default:
            break;
    }

    //QWidget::paintEvent(event);
}

bool FlickWindow::eventFilter(QObject *watched, QEvent *event)
{
    if(watched == ui->frameBtn)
    {
        if(event->type() == QEvent::MouseButtonRelease)
        {
            //this->close();
            HideAnimation->start();
        }
    }
    return QObject::eventFilter(watched, event);
}

FlickWindow::~FlickWindow()
{
    delete ui;
}
/*
 *弹窗功能
*/

#ifndef FLICKWINDOW_H
#define FLICKWINDOW_H

#include <QWidget>
#include <QTimer>
#include <QPropertyAnimation>
#include <QFrame>

#include "globaldef.hpp"

namespace Ui {
class FlickWindow;
}

class FlickWindow : public QFrame
{
    Q_OBJECT

public:
    explicit FlickWindow(QWidget *parent = nullptr,FLICKTYPE type = FLICKTYPE::FAILD);
    ~FlickWindow();
    void setFlickType(FLICKTYPE type);
    void setFlickText(QString str);
    void setFlickWidth(int width);
    int getFontsize(QRectF rect);
    void Init();

private:
    virtual void paintEvent(QPaintEvent *event);
    virtual void resizeEvent(QResizeEvent *event);
    virtual bool eventFilter(QObject *watched, QEvent *event);
    virtual void showEvent(QShowEvent *event);
    virtual void hideEvent(QHideEvent *event);

private slots:
    void Slot_timeout();

private:
    FLICKTYPE filcktype;
    QString flicktext = "THB ^0^";
    QTimer *continueTime = nullptr;
    QPropertyAnimation * ShowAnimation = nullptr;
    QPropertyAnimation * HideAnimation = nullptr;

private:
    Ui::FlickWindow *ui;
};

#endif // FLICKWINDOW_H

关于使用FLICKTYPE是一个枚举类,在自己的代码中调用时补充即可

//弹窗规范
enum FLICKTYPE{
    WARNING,
    SUCCESS,
    FAILD,
};

//调用方法
void Cood::slot_flickwindow(const QString str, const FLICKTYPE type)
{
    flickwindow->setFlickText(str);
    flickwindow->setFlickType(type);
    flickwindow->show();
}

### 回答1: 要实现在Qt Widget中添加控件,可以按照以下步骤进行操作。 1. 首先,在Qt项目中打开你想要添加控件Widget文件,一般为.ui文件。 2. 在Qt Designer中选择你想要添加控件的位置,比如一个按钮。 3. 在Qt Designer的左侧工具栏中,选择你要添加的控件的类型,比如QLineEdit(文本输入框)。 4. 将该控件拖拽到你在第二步中选择的位置。 5. 可以通过右键单击控件,在弹出的选项中选择“布局”来调整控件的位置和大小。 6. 在Qt Widget的头文件(.h文件)中,添加一个成员变量来引用新添加的控件,以便在代码中访问并操作它。 7. 在Qt Widget的源文件(.cpp文件)中,找到Widget的构造函数(或其他初始化函数),在其中实例化新添加的控件。 ```cpp QLineEdit *lineEdit = new QLineEdit(this); // 创建一个新的QLineEdit控件 // 可以设置控件的一些属性,比如位置和大小 lineEdit->setGeometry(100, 100, 200, 30); // 添加控件事件的监听器,比如按下按钮后的行为 connect(lineEdit, SIGNAL(textChanged(const QString &)), this, SLOT(onTextChanged(const QString &))); ``` 8. 在Qt Widget的源文件中,实现你在第7步中连接的槽函数。这将定义控件与其他部分的交互逻辑。 ```cpp void Widget::onTextChanged(const QString &text) { // 在文本改变时执行的代码 qDebug() << "Text changed: " << text; } ``` 通过这些步骤,你就可以在Qt Widget中添加控件并实现相应的功能了。当你运行应用程序时,新添加的控件将出现在GUI中,并响应用户的操作。 ### 回答2: Qt是一个跨平台的C++应用程序开发框架,可以用于开发各种GUI界面程序。在Qt中,可以使用控件来构建用户界面,如按钮、文本框、标签等。 要在Qt Widget中添加一个控件,需要进行以下步骤: 1. 创建一个新的Qt Widget项目,打开Qt Creator软件并选择新建项目。 2. 在项目向导中选择Qt Widgets Application,并输入项目名称和存储位置。 3. 在项目构建界面中选择默认配置,然后点击下一步。 4. 在类创建界面中,选择基类为QWidget,并输入类名称和包含的头文件的名称,然后点击下一步。 5. 在界面设计器中,可以看到一个空白的QWidget,我们可以在此基础上添加控件。 6. 在设计器中,选择左侧的控件库,如QToolBox,然后选择要添加的控件,如按钮。 7. 在窗口上单击并拖动鼠标来创建按钮的大小。 8. 可以在属性编辑器中修改控件的属性,如按钮的文本、大小、位置等。 9. 为按钮添加信号和槽函数,以便在按钮被点击时执行相应的操作。 10. 保存并编译项目,然后运行程序,即可在窗口上看到添加的控件。 以上是一个简单的Qt Widget添加控件的步骤,通过使用Qt Creator提供的界面设计器和属性编辑器,可以方便地添加和配置各种控件来构建用户界面。在实际的应用程序开发中,可以根据需要添加不同类型的控件,并通过信号和槽机制来实现控件之间的交互和响应。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值