C++ Qt5学习笔记2020-12-8(实现三连弹出窗口)

44 篇文章 8 订阅

三连弹出窗口:

在这里插入图片描述
下面是我苦思冥想做的方法,如果大佬有更好的方法,希望能够指教。

基本思路:
三个界面类 A,B,C

在A中初始化并显示B,在B中初始化并显示C。

由于观察到QQ中,选择主菜单时,每一列都是延时出现和延时消失,所以根据之前的做一下修改,分别初始化两个单次定时器,分别对应界面类的显示和隐藏,即A.cpp中两个定时器,定时任务为界面B的显示与隐藏,B.cpp中两个定时器,定时任务为界面C的显示与隐藏,当然还有主界面显示界面A,不过由于是按钮触发的,所以就不讲了。分别在A.cppB.cpp中初始化下一个界面类后,并在它们的事件过滤器中创建对应按钮的Enter事件和Leave事件,Enter则触发显示窗口的定时任务,Leave则触发隐藏窗口的定时任务。然后分别在A和B的界面类中再安装过滤器来打断定时任务,使得当鼠标从AEnter到A中初始化完的B区域时,打断定时任务并让B一直显示,当鼠标从BEnter到B中初始化完的C区域中时,打断定时任务并让C一直显示。

这样看似差不多了,但实际运行时会有一个问题,鼠标离开B区域,进入C区域,C区域会一直显示,但是同时也触发了A中隐藏B的定时任务,而且鼠标当前不处于B区域,所以定时器结束时,B窗口会消失,就形成了只显示A窗口和C窗口的画面。

为了解决这一问题,试了好久,想在C中对B进行控制,让其显示,但是在一个类中控制另一个类中的UI是不可行的,之前在使用线程时就遇到过,说到线程,就想起了之前是通过传递信号来控制主界面的UI的,所以使用信号来做。具体实现就是在B中鼠标Enter到C区域时,打断定时任务并让C一直显示的代码中,打断并显示C的同时,提交一个C_show()的信号给A,A接收到B发来的信号后,信号绑定槽函数打断B的隐藏定时器,并让B一直显示。当鼠标触发Leave移出C区域时,提交一个C_hide信号给A,A再次启动隐藏B的定时任务,将B隐藏。那么,由此可以联想到,即使不是三连弹出窗口,哪怕有100个下拉菜单,100个弹出窗口,只要保持顺序,前一个点定时任务调起下一个的同时向上一级发送信号,一级一级信号往前传,让它一直显示,都可以解决,只是代码实现上可能会很混乱,毕竟又是定时器,又是过滤器,又是信号的。

最后还要写鼠标点击功能,鼠标点击既要将当前窗口隐藏,还要把上一级的弹出窗口隐藏,前者直接this->hide()就可以,后者则可以用事件过滤器或者重新创建一个信号,然后发送信号来将界面B隐藏即可,同样也要一级一级往前推导。

大致流程:
在这里插入图片描述

具体实现代码:
界面A的头文件和cpp:

//******************mainwindow.cpp中***********************************************
//初始化界面A
qq_main_menu1 = new qq_main_menu;
//显示界面A的按钮
void qqchat_main_window::show_main_menu()
{
    qq_main_menu_btn = ui->main_menu->mapToGlobal(ui->main_menu->pos());
    qq_main_menu1->move(qq_main_menu_btn.x()-27,qq_main_menu_btn.y()-392);
    qq_main_menu1->show();
    qq_main_menu1->activateWindow();
}

//****************界面A的menu.h中****************************************************
public:
    vip_settings *vip_settings1;
    QTimer *timer1;      //定时器1 用于显示界面B
    QTimer *timer2;      //定时器2 用于隐藏界面B
    QPoint time1_btn;   //QPoint 存储控件的点位,用来让窗口显示在固定位置
public slots:
    bool eventFilter(QObject *target, QEvent *e);    //事件过滤器
    void vip_setting_show();               //界面B传来的信号绑定的槽函数来让界面B显示
    void vip_setting_hide();               //界面B传来的信号绑定的槽函数来让界面B隐藏
    
//****************界面A的menu.cpp中**************************************************
//界面B:vip_settings初始化
vip_settings1=new vip_settings;
//两个定时器初始化即绑定界面B的显示与隐藏
timer1=new QTimer(this);
timer2=new QTimer(this);
timer1->setSingleShot(true);
timer2->setSingleShot(true);
connect(timer1, SIGNAL(timeout()), vip_settings1, SLOT(show()));   //显示界面B定时器1
connect(timer2, SIGNAL(timeout()), vip_settings1, SLOT(hide()));   //隐藏界面B定时器2

//界面B 安装事件过滤器
vip_settings1->installEventFilter(this);

//事件过滤器内容
//鼠标点击弹窗外,界面A 隐藏
if(QEvent::WindowDeactivate == e->type())//窗口停用
       {
            this->hide();
          }

//鼠标移入窗口时,打断定时器,并使界面B一直显示,移出界面则重新调起定时器隐藏
if (target==vip_settings1)
    {
        if(e->type() == QEvent::Enter)
        {
            timer2->stop();  //打断定时器2,使界面B不隐藏
            ui->pushButton->setStyleSheet("QPushButton#pushButton{border:0px;background-color:rgb(235,235,235,90%);padding-right: 100;}");   //按钮效果
            vip_settings1->show();    //显示界面B
        }
        else if (e->type() == QEvent::Leave)
        {
            ui->pushButton->setStyleSheet("QPushButton#pushButton{border:0px;background-color:rgb(255,255,255,0%);padding-right: 100;}");   //按钮效果
            timer2->start(400);     //开启定时器2,隐藏窗口
        }
        else{return QDialog::eventFilter(target, e);}
    }

//鼠标移入按钮时,调起界面B,移出则隐藏
if(target == ui->pushButton)
    {
        if (e->type() == QEvent::Enter){
            ui->pushButton->setStyleSheet("QPushButton#pushButton{border:0px;background-color:rgb(235,235,235,90%);padding-right: 100;}");    //按钮效果
            time1_btn = ui->pushButton->mapToGlobal(ui->pushButton->pos());
            vip_settings1->move(time1_btn.x()+220,time1_btn.y()-20);
            timer1->start(400);    //移入按钮定时器1显示界面B
        }
        else if(e->type()==QEvent::Leave){
            ui->pushButton->setStyleSheet("QPushButton#pushButton{border:0px;background-color:rgb(255,255,255,0%);padding-right: 100;}");
            timer2->start(400);     //移出按钮定时器2隐藏界面B
        }
    }

//信号界面B 的显示和隐藏信号
connect(vip_settings1,SIGNAL(vip_setting_show()),this,SLOT(vip_setting_show()));
connect(vip_settings1,SIGNAL(vip_setting_hide()),this,SLOT(vip_setting_hide()));
//信号绑定槽函数 显示界面B 和 隐藏界面B
void qq_main_menu::vip_setting_hide()
{
    timer2->start(400);   //启动定时器,隐藏界面B
}
void qq_main_menu::vip_setting_show()
{
    timer2->stop();         //打断定时器2
    vip_settings1->show();  //显示界面B
    ui->pushButton->setStyleSheet("QPushButton#pushButton{border:0px;background-color:rgb(235,235,235,90%);padding-right: 100;}");   //改变按钮显示效果
}

界面B的头文件和cpp:
(同样,界面B 使用同样的代码调起和控制界面C)

//*************界面B的vip_settings.h中************************************************
    hot_uses *hot_uses1;     //界面C的界面类对象
    QTimer *timer1;          //定时器1,用于显示界面C
    QTimer *timer2;          //定时器2,用于隐藏界面C
    QPoint time1_btn;        //存储位点,用于让界面C出现在指定位置
//*************界面B的vip_settings.cpp中**********************************************
//界面C的初始化,并安装事件过滤器
hot_uses1 = new hot_uses;
hot_uses1->installEventFilter(this);
//两个定时器
timer1 = new QTimer(this);  //定时器1 用于显示
timer2 = new QTimer(this);  //定时器2 用于隐藏
timer1->setSingleShot(true);
timer2->setSingleShot(true);
connect(timer1,SIGNAL(timeout()),hot_uses1,SLOT(show()));    //定时器1任务显示
connect(timer2,SIGNAL(timeout()),hot_uses1,SLOT(hide()));    //定时器2任务隐藏

//事件过滤器
//鼠标移入按钮,显示界面C,移出则隐藏
if(target==ui->label)
    {
        if(e->type()==QEvent::Enter)
        {
            ui->pushButton_3->setStyleSheet("QPushButton#pushButton_3{border:0px;background-color:rgb(235,235,235,90%);padding-right: 0;}");    //按钮效果
            time1_btn = ui->pushButton_3->mapToGlobal(ui->pushButton_3->pos());
            hot_uses1->move(time1_btn.x()+160,time1_btn.y()-465);
            timer1->start(400);   //定时器1,显示界面C
        }
        else if(e->type()==QEvent::Leave)
        {
            ui->pushButton_3->setStyleSheet("QPushButton#pushButton_3{border:0px;background-color:rgb(255,255,255,0%);padding-right: 0;}");    //按钮效果
            timer2->start(400);    //定时器2,隐藏界面C
        }
    }

//在界面C中的事件过滤器
//鼠标移入界面C的窗口中时,打断隐藏定时器,并让窗口显示,移出窗口时,再调起定时器隐藏
if(target==hot_uses1)
    {
        if(e->type()==QEvent::Enter)
        {
           timer2->stop();       //打断定时器2的执行
           hot_uses1->show();     //显示界面C
           emit vip_setting_show();    //提交信号,表示鼠标进入界面C区域,该信号会让界面B保持显示
           ui->pushButton_3->setStyleSheet("QPushButton#pushButton_3{border:0px;background-color:rgb(235,235,235,90%);padding-right: 0;}");
        }
        else if(e->type()==QEvent::Leave)
        {
            timer2->start(400);     //启动定时器2,该定时器会让界面C在400ms后隐藏
            emit vip_setting_hide();     //提交信号,表示鼠标离开界面C区域,该信号会让界面B启动隐藏定时器2
        }
    }

这样,三个连着的弹出窗口就实现的差不多了,看一下效果:
在这里插入图片描述
然后再来优化按钮的点击,按钮的作用性功能先不写,先来写ui,即点击按钮以后,把三个窗口隐藏。

点击按钮隐藏窗口C:

//只要用this->hide()即可
void hot_uses::btn1_sig()
{    this->hide();
}

隐藏界面B有两种方法:
第一种是设置界面B的事件过滤器,当窗口状态为deactivate,即在窗口B外点击时,将窗口B隐藏:

if(QEvent::WindowDeactivate == e->type())//窗口停用
       {
            this->hide();
          }

第二种就是提交信号来隐藏窗口了。

第一个简单,所以第二个代码我就不写了,照搬就好,至于要添加其他功能,在按钮功能中自行添加即可。

看一下效果:
在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值