【QT】《Qt5.9 C++开发指南》在桌面上放个伊芙利特

前言

就是像QQ宠物一样,在电脑屏幕上设计一个“智能点”的窗口或者就放一个可交互的GIF……(提前准备一批透明背景的GIF图和分解出来的透明背景的PNG图)


无边框&透明背景窗口

建一个集成QMainWindow或者QWidget的QT项目。UI编辑里删除状态栏、工具栏、菜单栏。放入一个QLablel,我们就是用QLabelsetMovie方法来显示图片。把label设置为右键设置为栅格布局,并且记得右下角的布局属性设置为0
在这里插入图片描述
接着设置窗口透明、无边框、始终置于前面。这样运行会得到一个透明窗口,因为是透明的所以看不到,需要在任务栏关闭。

//widget.cpp
Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);


    //无边框//保证窗口一直在前面
    setWindowFlags(Qt::FramelessWindowHint|Qt::WindowStaysOnTopHint);
    //透明背景
    setAttribute(Qt::WA_TranslucentBackground);

}

实现窗口可拖动

首先需要填充一下背景,只有被填充的窗口部分才能接受到鼠标点击的信号——到后面我们播放透明背景的GIF图就明白了,透明的部分的窗口是可以穿过的,只有不透明的地方才能交互。

//widget.cpp
void Widget::paintEvent(QPaintEvent *event){
	QPainter p(this);
	//颜色填充
    p.fillRect(6,6,width()-12,height()-12,QColor(232, 236, 247));

	//图片填充
	 //位图填充
    //QPixmap backBmp("../window_try_2/Background.bmp");
    //  p.drawPixmap(6,6,width()-12,height()-12,backBmp,0,0,backBmp.width(),backBmp.height());

}

在这里插入图片描述
可以重写一下mouseMoveEvent输出鼠标座标,来看看是否接受到了鼠标消息。

接受到了鼠标消息,拖动就是靠这个消息来手动移动窗口。

//widget.h
protected:
    void mouseMoveEvent(QMouseEvent *event);
    void mousePressEvent(QMouseEvent *event);
    void paintEvent(QPaintEvent *event);
    void mouseReleaseEvent(QMouseEvent *event);

private:
    bool    flag_clicked;        //左鼠标点击实现移动
    QPoint  currentPos;   //屏幕上点击的座标点
//widget.cpp
void Widget::mouseMoveEvent(QMouseEvent *event){

    //移动窗口
    if(flag_clicked){
        QPoint tempPos = event->globalPos() - currentPos;
        move(pos() + tempPos);
        currentPos = event->globalPos();
    }

}
void Widget::mousePressEvent(QMouseEvent *event){
    if(event->buttons() == Qt::LeftButton){
        //qDebug()<<"flag_clicked=true";
        flag_clicked = true;
        currentPos = event->globalPos();
    }
}

void Widget::mouseReleaseEvent(QMouseEvent *event){

    //qDebug()<<"flag_clicked=false";
    flag_clicked = false;

}

在这里插入图片描述

播放GIF

在这里插入图片描述
文件太大了,只能放截图了。官方公布的两个GIF图,找不到透明背景的,所以只有自己处理了(这个之后讲)

先播放试试效果。使用QMovie类来加载GIF图,再使用QLabel的setMovie方法来显示。

//widget.cpp
    //这个添加到构造函数里
    //播放GIF
    movie=new QMovie("../window_try_4/1.gif");
    movie->setScaledSize(QSize(200,200));//设置GIF大小
    //movie->setSpeed(100);//默认100%原始动画速度
    ui->label->setMovie(movie);
    movie->start();

保存为JPG

为了更好的操作,必须要PNG图。用在线的GIF转JPG没用,因为文件太大,转换出来的都坏了,所以还是自己来转换。
通过获取QMovie对象的当前图像,可以保存为JPG图片。另外每次QMovie对象的帧变化时会发射frameChanged信号,所以我们需要自定义一个槽函数on_saveAsJPG来关联一下。
通过这种方法,可以发现第一个GIF图有111帧,第二个GIF图有158帧……

//widget.cpp
void Widget::on_saveAsJPG(){

    static int i=0;
    if(i<movie->frameCount()){ //避免保存太多
        qDebug()<<"save>"<<i;
        QImage p = movie->currentImage();
        p.save(QString::asprintf("E:/干员1_JPG/1_%d.jpg",i++),"JPG",100);//100表示未压缩
    }
}

抠图变成PNG

无论你是想直接播放几个GIF(下面那步)还是想逐帧播放(下下面那步),都需要抠图(如果有现成的该多好)……

用PS打开一张JPG图片,用多边形套索选择出来。新建一个图层,把选择的内容复制到新的图层中,再把旧的图层删除,保存到PNG文件夹。

[抠图中]

合成几个GIF

拿第一个GIF分开的PNG图做成两个GIF,一个普通播放的,一个特殊交互的。

在鼠标点击后,设置特殊GIF播放标记,关掉普通GIF播放。在特殊GIF播放完前,再次点击不会再触发播放特殊的。通过记录帧数来判断是否播放完,播放完特殊的后,再次初始化标记,并且关掉特殊GIF,开启普通GIF。
——这里还需要关联一下frameChanged信号与paintEvent,因为这个函数并不是每次都会被执行。

//widget.cpp

void Widget::mousePressEvent(QMouseEvent *event){


    if(event->buttons() == Qt::LeftButton){
        //qDebug()<<"flag_clicked=true";
        flag_clicked = true;
        currentPos = event->globalPos();

        if(!flag_special){ //如果之前播放的是普通GIF
            qDebug()<<"special gif";
            flag_special=true;
            movie->stop();
            delete movie;
            movie=new QMovie("../window_try_4/yifulite2.gif");
            movie->setScaledSize(QSize(200,200));//设置GIF大小
            movie->setSpeed(200);//2倍速
            ui->label->setMovie(movie);
            movie->start();
        }

    }
}
void Widget::paintEvent(QPaintEvent *event){

    static int i=0;
    if(flag_special&&i++>=movie->frameCount()){//在播放特殊GIF,并且放完了
        qDebug()<<"normal gif";
        flag_special=false;
        movie->stop();
        delete movie;
        movie=new QMovie("../window_try_4/yifulite1.gif");
        movie->setScaledSize(QSize(200,200));//设置GIF大小
        movie->setSpeed(200);
        ui->label->setMovie(movie);
        movie->start();
        i=0;
    }

}

有点难受。。。抠了一天,抠了快12个小时,做的效果并不好。。。
由于是一张张的托过来做成GIF,所以伊芙利特的位置就不定。比起播放GIF,还是一帧帧的播放比较靠谱

在这里插入图片描述

(手很痛,以后再搞)

与任务栏交互

让伊芙利特落在桌面底下,踩在任务栏上,根据任务栏的高低而起伏。
这是与其他窗口交互的第一步,先与任务栏交互。需要调用windows api,获取窗口信息。

使用Microsoft spy++ 工具来查找窗口,为了得到一个窗口信息,首先需要知道该窗口的类名和标题。任务栏的类名是Shell_TrayWnd,标题没有。
比如下面是使用这个工具来查找伊芙利特窗口(设置窗口名:this->setWindowTitle("伊芙利特");
在这里插入图片描述

在pro文件中添加LIBS += user32.lib
添加头文件#include <Windows.h>

//widget.cpp
	//添加到paintEvent里
 	 if(!flag_clicked){//鼠标松手
        RECT rect;
        ::GetWindowRect(::FindWindow(TEXT("Shell_TrayWnd"), NULL), &rect);
        if(rect.top>500)//保证任务栏在桌面底下,不在其他位置
            move(QPoint(pos().x(),rect.top-225));
    }

在这里插入图片描述

与其他窗口碰撞

双击后可放缩、关闭

添加其他功能

参考:

QT学习之路之Movie动画

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章