qt自定义控件-模拟Android toast提示窗口

一、前言

 

好久没写博客了,最近一直写材料,很难受,在家做点小东西,正好遇到了想做的效果,在桌面程序实现Android的toast效果

二、环境

目标机linux,测试机window10

qt5.7

本文参考连接

我的Android toast效果实现方法

三、正文

我需求的和心目中的toast有两种效果:

第一种是比较常规的Androidtoast效果,也是比较简单实现,主要参考以上连接,操作部分稍加修改,可以无限连续点击,不会造成内存堆积。下面是实现效果和方法。

cpp 

#include "mytoast.h"
 #include <QGuiApplication>
#include <QScreen>
Mytoast::Mytoast(QWidget*parent):QLabel(parent)
{
    //设置样式
    this->setStyleSheet("background-color: rgba(40, 40, 40, 140);color: rgb(255, 255, 255);border-radius:4px");
    //居中对齐
    this->setAlignment(Qt::AlignCenter);
    //隐藏
    this->hide();
    //信号和槽
    connect(this->timer,&QTimer::timeout,this,&Mytoast::time_toast);
}
//第一个参数为弹窗内容
//第二个参数为持续时间ms,默认-1不消失,需调用stop关闭或重新start
void Mytoast::start(QString str, int time)
{
    //关闭上次弹窗的定时器
    if(timer->isActive())timer->stop();
    //计算字体的宽度和高度,字体可以自己更换
    QFontMetrics metrics(QFont("黑体",16));
    int text_width = metrics.width(str);
    int text_height = metrics.height();
    //设置弹窗大小,增加一些像素更美观一点
    this->resize(text_width+16,text_height+12);
    //设置弹窗内容
    this->setText(str);
    //设置弹窗字体,注意一定要和上面的相同
    this->setFont(QFont("黑体",16));
    //设置位置居中父级窗体
    int p_x = int((this->parentWidget()->width()-this->width())/2);
    int p_y = int((this->parentWidget()->height()-this->height())/2);
    this->move(p_x,p_y);
 
    //time为-1时不关闭
    if(time == -1){
        this->show();
    }
    //启动定时器
    else{
        this->show();
        this->timer->start(time);
    }
}
 
//主动调用关闭弹窗,用于time=-1的情况
void Mytoast::stop()
{
    this->timer->stop();
    this->close();
}
 
//定时关闭函数
void Mytoast::time_toast()
{
    this->timer->stop();
    this->close();
}

#ifndef MYTOAST_H
#define MYTOAST_H
 
#include <QLabel>
#include <QTimer>
 #include "main.h"
//继承QLabel类,父级窗体为QWidget类及派生类
class Mytoast:public QLabel
{
    Q_OBJECT
public:
    Mytoast(QWidget*parent);
    void start(QString str ,int time =-1);
    void stop();

private slots:
    void time_toast();
private:
    QTimer *timer = new QTimer;
    QPixmap pic;

};
 
#endif // MYTOAST_H

调用cpp

///显示三级提示框toast(暂时未实现渐变效果、界面外显示、变更长条背景)
void MessageBox2::showtoast(QString str,int time)
{
    //删除上次toast
    QList<Mytoast*> List = this->findChildren<Mytoast*>();
    for(int i=0;i<List.size();i++)delete List[i];
    //新建toast
    Mytoast * box = new Mytoast(this);
    box->setAttribute(Qt::WA_DeleteOnClose);//若是关闭界面,则彻底释放资源
    box->start(str,time);
}

方式一的实现比较简单,没加动画效果,不能界面外显示,背景单一,方式二会升级

第二种方式就是我需要的在第一种方式基础上升级,将其升级为可以在 界面任意地方设置显示,包括在小界面的外部,界面背景可以自定义为渐变色或者图片的形式,并且具有逐渐消失的动画效果,再次有新的toast弹出时,会瞬间高亮,然后重新开始逐渐消失,新的提示出来,杀掉之前的toast界面,不会覆盖显示,并且界面会一直保持在顶层,不会被新聚焦的底层界面覆盖。下面是实现效果和方法。

原理倒是没什么复杂的,就是遇到一些问题卡住了,最终是如愿实现了效果,无论是toast显示在此界面还是界面外,都会有信息保持在顶层显示,直到显示完毕自动隐藏,两种方式的源码资源可下载 

下面贴关键代码,很简单的

mytoast_form.cpp

#include "mytoast_form.h"
#include "ui_mytoast_form.h"
#include <qDebug>
mytoast_form::mytoast_form(QString name, int time,QWidget *parent) :
    QWidget(parent),
    ui(new Ui::mytoast_form)
{
    ui->setupUi(this);
//    this->setWindowModality(Qt::ApplicationModal);//设置一直保持在顶端,不可切换其他界面,除非被新界面带此属性覆盖
    this->setWindowFlags(Qt::FramelessWindowHint);//设置窗体无边框
    this->setAttribute(Qt::WA_TranslucentBackground);//设置背景透明
    this->setWindowFlags(this->windowFlags() | Qt::WindowStaysOnTopHint);//界面在最前方,覆盖其他界面

    ui->label->setText(name);
    this->move(800,1200);
    QPropertyAnimation *animation = new QPropertyAnimation(this,"windowOpacity");
    animation->setDuration(time);
    animation->setStartValue(1);
    animation->setEndValue(0);
    animation->start();
    timer->start(time);
    connect(timer,&QTimer::timeout,[=](){
        timer->stop();
        this->close();
    });
}
mytoast_form::~mytoast_form()
{
    delete ui;
}

mytoast_form.h

#ifndef MYTOAST_FORM_H
#define MYTOAST_FORM_H

#include <QWidget>
#include <QPropertyAnimation>
#include <QLabel>
#include <QTimer>
namespace Ui {
class mytoast_form;
}

class mytoast_form : public QWidget
{
    Q_OBJECT

public:
    explicit mytoast_form(QString name, int time, QWidget *parent = 0);
    ~mytoast_form();

private:
    Ui::mytoast_form *ui;
    QTimer *timer = new QTimer;
};

#endif // MYTOAST_FORM_H

执行cpp

    //删除上次toast,不能直接删除界面会崩溃,先隐藏,之后等待时间结束自动删除
    QWidgetList aaa=QApplication::allWidgets();
//    qDebug()<<QString::number(aaa.size());
    for(int i=0;i<aaa.size();i++){
        if(aaa.at(i)->objectName()=="mytoast_form"){
            aaa.at(i)->hide();
        }
    }
    //新建toast
    mytoast_form * box = new mytoast_form("这是一个测试文本!!!",2000);
    box->show();
    box->setAttribute(Qt::WA_DeleteOnClose);//若是关闭界面,则彻底释放资源

 20220430更新,第二种方式将程序移植到arm开发板上运行没有渐变效果,后来做一下修改就可以了,在mytoast_form.cpp添加以下代码即可。

    QTimer *ttt=new QTimer(this);
    ttt->start(100);
    connect(ttt,&QTimer::timeout,[=](){//更新界面,否则在Linux中没有渐变消失效果
        this->update();
    });

20220510更新,在linux下若toast没显示完退出界面后,在点击上一界面,会卡死,在当前界面的销毁程序前加入如下代码即可

MessageBox2::~MessageBox2()
{
    QWidgetList aaa=QApplication::allWidgets();//退出界面时关闭所有toast
    for(int i=0;i<aaa.size();i++){
        if(aaa.at(i)->objectName()=="mytoast_form"){
            aaa.at(i)->hide();
        }
        else if(aaa.at(i)->objectName()=="mytoast_form1"){
            aaa.at(i)->hide();
        }
    }
    delete ui;
}

四、结语

学而时习之,不亦说乎

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大桶矿泉水

你的鼓励是我创作最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值