C++ Qt5学习笔记 2020-12-2(在窗口外区域点击时隐藏窗口,实现切换qq登录状态。鼠标悬停显示悬浮窗口,离开区域过一段时间后消失 + 鼠标停留在悬窗时就不消失,以此实现qq天气的悬浮窗口)

44 篇文章 8 订阅

1、在窗口外的区域点击时隐藏窗口

在该窗口的事件过滤器中添加:

//安装过滤器
installEventFilter(this);
//窗口不隐藏
bool login_condition::eventFilter(QObject *target, QEvent *e)
{
    if(QEvent::WindowDeactivate == e->type())
       {
            this->hide();  
            //这里我是隐藏,由于我初始化写在一开始的ui中,所以如果关了可能就打不开了
            //也可以关闭,不过注意把窗口的初始化也写到调起窗口的方法中
          }
    return QDialog::eventFilter(target, e);
}

但是,光是这样,调起这个窗口以后,必须先点击一下窗口中的区域,才能开始这个事件的监听。

所以,在显示这个窗口的时候(比如按钮触发显示时),还需要激活窗口。

激活窗口只要使用activateWindow();就行了,比如,在呼出该窗口的按钮的功能中添加:

//登录状态下拉框
void qqchat_main_window::log_condition_func()
{
    log_condition_btn = ui->log_condition->mapToGlobal(ui->log_condition->pos());
    log_condition->move(log_condition_btn.x()-70,log_condition_btn.y()-70);
    log_condition->show();
    log_condition->activateWindow();
}

运行结果:
在这里插入图片描述

这样就不需要在窗口中点一下来激活窗口了!
在这里插入图片描述

2、实现切换qq登录状态:

由于在登录状态的悬浮窗中无法直接控制主界面的界面,所以还是采用老方法:类与类之间使用信号来通信。

以上面已完成的操作为前提,首先把悬浮窗的7个切换登陆状态的按钮的功能写好并绑定信号:

//login_condition.h中创建的信号
//信号
signals:
    void login_em();   //在线
    void chat_with_em();   //Q我吧
    void leave_em();   //离开
    void busy_em();    //忙碌
    void avoid_em();   //请勿打扰
    void hide_em();    //隐身
    void logout();    //离线
//槽函数
public slots:
    void login_em_fnc();    //在线按钮
    void chat_with_em_fnc();  //Q我吧按钮
    void leave_em_fnc();
    void busy_em_fnc();
    void avoid_em_fnc();
    void hide_em_fnc();
    void logout_fnc();

//login_condition.cpp中绑定按钮槽函数和槽函数的功能
//绑定槽函数
connect(ui->pushButton,SIGNAL(clicked()),this,SLOT(login_em_fnc()));
connect(ui->pushButton_2,SIGNAL(clicked()),this,SLOT(chat_with_em_fnc()));
connect(ui->pushButton_3,SIGNAL(clicked()),this,SLOT(leave_em_fnc()));
connect(ui->pushButton_4,SIGNAL(clicked()),this,SLOT(busy_em_fnc()));
connect(ui->pushButton_5,SIGNAL(clicked()),this,SLOT(avoid_em_fnc()));
connect(ui->pushButton_6,SIGNAL(clicked()),this,SLOT(hide_em_fnc()));
connect(ui->pushButton_7,SIGNAL(clicked()),this,SLOT(logout_fnc()));
//槽函数功能
void login_condition::login_em_fnc()
{
    this->hide();    //隐藏状态切换悬浮窗
    emit login_em();   //提交信号,表示状态在线
}
void login_condition::chat_with_em_fnc()
{
    this->hide(); 
    emit chat_with_em();    //提交信号,表示状态Q我吧
}
void login_condition::leave_em_fnc()
{
    this->hide();
    emit leave_em();
}
void login_condition::busy_em_fnc()
{
    this->hide();
    emit busy_em();
}
void login_condition::avoid_em_fnc()
{
    this->hide();
    emit avoid_em();
}
void login_condition::hide_em_fnc()
{
    this->hide();
    emit hide_em();
}
void login_condition::logout_fnc()
{
    this->hide();
    emit logout();
}

然后回到主界面:
在主界面的.h中创建信号的槽函数:

void login_change();
void chat_me_change();
void leave_change();
void busy_change();
void avoid_change();
void hide_change();
void logout_change();

在主界面中.cpp中绑定状态切换悬浮窗的信号和主界面的槽函数:
说明一下,login_condition按钮的初始状态为:

ui->log_condition->setStyleSheet("QPushButton#log_condition{border-radius:7px;background-color:rgb(0,255,0);}QPushButton#log_condition:pressed{border-radius:7px;background-color:rgb(9,241,117);}");
ui->log_condition->setToolTip(u8"在线状态菜单\n 当前状态:我在线上\n 声音:开启\n 消息提醒框:关闭\n 会话消息:任务栏头像闪动");

//怕不明白,在这里放一下之前就完成初始化的login_condition对象
log_condition = new login_condition;
//信号连接槽函数
connect(log_condition,SIGNAL(login_em()),this,SLOT(login_change()));
connect(log_condition,SIGNAL(chat_with_em()),this,SLOT(chat_me_change()));
connect(log_condition,SIGNAL(leave_em()),this,SLOT(leave_change()));
connect(log_condition,SIGNAL(busy_em()),this,SLOT(busy_change()));
connect(log_condition,SIGNAL(avoid_em()),this,SLOT(avoid_change()));
connect(log_condition,SIGNAL(hide_em()),this,SLOT(hide_change()));
connect(log_condition,SIGNAL(logout()),this,SLOT(logout_change()));
//槽函数来修改qq的登录状态
void qqchat_main_window::login_change()  //我在线上
{
    QIcon button_ico_log_condition("");   //去除按钮图标
    ui->log_condition->setIcon(button_ico_log_condition);
    ui->log_condition->setStyleSheet("QPushButton#log_condition{border-radius:7px;background-color:rgb(0,255,0);}QPushButton#log_condition:pressed{border-radius:7px;background-color:rgb(9,241,117);}");
    ui->log_condition->setToolTip(u8"在线状态菜单\n 当前状态:我在线上\n 声音:开启\n 消息提醒框:关闭\n 会话消息:任务栏头像闪动");
}
void qqchat_main_window::chat_me_change()   //Q我吧
{
    QIcon button_ico_log_condition(":/new/prefix1/source/smile_face.png");
    ui->log_condition->setIcon(button_ico_log_condition);
    ui->log_condition->setIconSize(QSize(14,14));
    ui->log_condition->setStyleSheet("QPushButton#log_condition{border-radius:7px;}");
    ui->log_condition->setToolTip(u8"在线状态菜单\n 当前状态:Q我吧\n 声音:开启\n 消息提醒框:关闭\n 会话消息:自动弹出会话窗口");
}
void qqchat_main_window::leave_change()   //离开
{
    QIcon button_ico_log_condition(":/new/prefix1/source/leave.png");
    ui->log_condition->setIcon(button_ico_log_condition);
    ui->log_condition->setIconSize(QSize(14,14));
    ui->log_condition->setStyleSheet("QPushButton#log_condition{border-radius:7px;}");
    ui->log_condition->setToolTip(u8"在线状态菜单\n 当前状态:离开\n 声音:开启\n 消息提醒框:关闭\n 会话消息:任务栏头像闪动");
}
void qqchat_main_window::busy_change()     //忙碌
{
    QIcon button_ico_log_condition(":/new/prefix1/source/busy.png");
    ui->log_condition->setIcon(button_ico_log_condition);
    ui->log_condition->setIconSize(QSize(14,14));
    ui->log_condition->setStyleSheet("QPushButton#log_condition{border-radius:7px;}");
    ui->log_condition->setToolTip(u8"在线状态菜单\n 当前状态:忙碌\n 声音:开启\n 消息提醒框:关闭\n 会话消息:任务栏显示气泡");
}
void qqchat_main_window::avoid_change()     //请勿打扰
{
    QIcon button_ico_log_condition(":/new/prefix1/source/avoid.png");
    ui->log_condition->setIcon(button_ico_log_condition);
    ui->log_condition->setIconSize(QSize(14,14));
    ui->log_condition->setStyleSheet("QPushButton#log_condition{border-radius:7px;}");
    ui->log_condition->setToolTip(u8"在线状态菜单\n 当前状态:请勿打扰\n 声音:开启\n 消息提醒框:关闭\n 会话消息:任务栏显示气泡");
}
void qqchat_main_window::hide_change()     //隐身
{
    QIcon button_ico_log_condition(":/new/prefix1/source/hide.png");
    ui->log_condition->setIcon(button_ico_log_condition);
    ui->log_condition->setIconSize(QSize(14,14));
    ui->log_condition->setStyleSheet("QPushButton#log_condition{border-radius:7px;}QPushButton#log_condition:pressed{border-radius:7px;background-color:rgb(9,241,117);}");
    ui->log_condition->setToolTip(u8"在线状态菜单\n 当前状态:隐身\n 声音:开启\n 消息提醒框:关闭\n 会话消息:任务栏头像闪动");
}
void qqchat_main_window::logout_change()     //离线
{
    QIcon button_ico_log_condition(":/new/prefix1/source/logout.png");
    ui->log_condition->setIcon(button_ico_log_condition);
    ui->log_condition->setIconSize(QSize(14,14));
    ui->log_condition->setStyleSheet("QPushButton#log_condition{border-radius:7px;}QPushButton#log_condition:pressed{border-radius:7px;background-color:rgb(9,241,117);}");
    ui->log_condition->setToolTip("");    //离线时清空提示信息
}

运行结果:
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

还有几个我就不放辣!

3、鼠标悬浮显示浮动窗口,过一段时间后消失 + 鼠标停留在悬窗时就不消失

(1)鼠标悬停在label上显示浮窗:

与之前的设置的悬浮窗类似。不过由于显示的区域在窗口的外部,所以不能使用之前的方法。

实现方案: 使用定时器任务,使得鼠标移出窗口的时候,过个1秒再消失,不过我不需要定时器一直运行,所以设置定时器属性singleShottrue来使定时任务只运行一次。

先创建定时器和定时任务:

//.h中声明定时器指针
QTimer *pTimer;

//.cpp中绑定定时任务
qqweather = new weather;  //初始化弹窗界面类
pTimer = new QTimer(this);   //初始化定时器
pTimer->setSingleShot(true);    //只执行一次,所以不需要stop来结束定时任务
connect(pTimer, SIGNAL(timeout()), qqweather, SLOT(hide())); 
//定时任务绑定qqweather弹窗的隐藏事件,定时器执行结束时触发qqweather的隐藏任务

接着在事件过滤器中写悬浮显示窗口的功能,以及启动定时器:

//修改事件过滤器来启动定时任务
     if (target==ui->cloud )
     {
         if(e->type() == QEvent::Enter)
         {
                cloud_move = ui->cloud->mapToGlobal(ui->cloud->pos());
                qqweather->move(cloud_move.x()-160,cloud_move.y()-110);
                qqweather->show();
         }
         else if (e->type() == QEvent::Leave)
         {
             //qqweather->hide();
             pTimer->start(1000);   //鼠标离开事件,修改为定时任务,定时器延时长度为1秒
         }
         else{return QDialog::eventFilter(target, e);}
         }

运行结果:
在这里插入图片描述

(2)当鼠标悬停时就不消失:

但是上面的代码只是实现我鼠标悬停在天气的label中时显示天气弹窗,移出label就过1秒消失,我还要对这个窗口进行操作。经过一些实验,使用上一篇博客中的方法是不行的,原因是:鼠标移出label时启动定时器,在1秒后窗口就会执行定时器任务将窗口隐藏,这相当于一个线程,我写一个事件过滤器把鼠标移动到天气弹窗中,让其显示,但是定时器时间到了还是会触发槽函数,让其隐藏,所以行不通。

解决方法:
在鼠标移入窗口中时,对定时器进行阻塞,使用stop阻断定时器任务,移开鼠标时再启动定时器任务。

实现代码:
与上一篇博客不同,由于qqweather已经在主界面中完成了初始化,所以这次我把两个界面类的事件过滤器写到一起。

//为qqweather安装事件过滤器
qqweather->installEventFilter(this);
//修改事件过滤器
if (target==ui->cloud )
     {
         if(e->type() == QEvent::Enter)
         {
                cloud_move = ui->cloud->mapToGlobal(ui->cloud->pos());
                qqweather->move(cloud_move.x()-160,cloud_move.y()-110);
                qqweather->show();
         }
         else if (e->type() == QEvent::Leave)
         {
             pTimer->start(1000);
         }
         else{return QDialog::eventFilter(target, e);}
         }
if (target==qqweather)     //新增qqweather的事件过滤器
     {
         if(e->type() == QEvent::Enter)
         {
                cloud_move = ui->cloud->mapToGlobal(ui->cloud->pos());
                qqweather->move(cloud_move.x()-160,cloud_move.y()-110);
                qqweather->show();
                pTimer->stop();    //阻塞定时任务的执行
         }
         else if (e->type() == QEvent::Leave)
         {
             pTimer->start(1000);  //离开qqweather窗口时也开始定时器任务,即1秒后隐藏窗口
         }
         else{return QDialog::eventFilter(target, e);}
     }

运行结果:
在这里插入图片描述

3、类似qq天气的悬浮窗口:

其实悬窗功能上面已经做好了,由于暂时不考虑除界面以外的功能,所以直接把按钮去边并透明,然后截图腾讯的天气悬窗做背景图,然后再做一些鼠标悬浮效果。

结果展示:
在这里插入图片描述
在这里插入图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值