qt实现的窗口吸附屏幕边缘,动画隐藏显示的效果,类似于qq主窗口 吸附 隐藏的效果

对于这个效果的实现,其实方法应该还是很多的,这里的实现简单的原理只是一种,可能还不是很好,做个借鉴吧。

大概就是需要两个的计时器,第一个是用来判断窗口是不是在边缘附近,我们要把它吸附上去;第二个是用来判断是不是满足了隐藏,或者显示的效果的条件。然后利用动画来进行这些显示的过度,在过程中先中断一下事件处理,让窗口动画先走玩(很短,而且被事件中断的话,用户交互也不太友好)。其实原理就很简单的,还是上一下简单的代码了。

timer_edgeMove = new QTimer(this);
timer_edgeMove->setSingleShot(false);
timer_edgeMove->setInterval(EdgeMoveTime);//自己设定一个间断的时间
timer_edgeHide = new QTimer(this);
timer_edgeHide->setSingleShot(false);
timer_edgeHide->setInterval(EdgeHideTime);//自己设定一个间断的时间
connect(timer_edgeMove,&QTimer::timeout,this,&MainWindow::updateEdgeMove);//这里是定时器触发的两个函数,做判断以及实现,具体实现在后面
connect(timer_edgeHide,&QTimer::timeout,this,&MainWindow::updateEdgeHide);
timer_edgeMove->start();
timer_edgeHide->start();
mousePress = false;//鼠标的按键状态,判断定时器开关
winHide = winHideType::none;//当前需要的隐藏的状态
blockAll = false;//主要是根据动画的状态来设置,来判断是否在动画过程中忽略一下鼠标的事件等。
edgeMoveAnimation = new QPropertyAnimation(this,"pos",this);//参数分别为目标,属性,和父元素。
//动画完成后的回复响应
connect(edgeMoveAnimation,&QPropertyAnimation::finished,[=](){
blockAll = false;
timer_edgeMove->start();
timer_edgeHide->start();
});
初始化就是这样了,然后就是吸附的计时器触发的函数:

//处理吸附的计时
void MainWindow::updateEdgeMove()
{
    int targetx,targety;
    //这里要判断一下是不是鼠标按着,或者是已经隐藏,都不需要做处理。
    if(mousePress == true || winHide!=winHideType::none)
        return;
    int enableMove = 0;
//    qDebug()<<this->x()<<this->y();
    //y方向的判断,这里<span style="font-family: Arial, Helvetica, sans-serif;">EdgeAttachMargin是自定义的一个你想要让他吸附的距离,就是靠边缘多近要吸附上去,enableMove是用来最后判断是否需要动画的一个标志位</span>
    if(this->y()<EdgeAttachMargin&&this->y()!=0){
        targety = 0;
        enableMove = 1;
    }
    else
        targety = this->y();
    //x方向和y差别不大,就是需要多判断一下左右的两种情况,y只需要上方一种情况。
    if(this->x()<EdgeAttachMargin&&this->x()!=0){
        enableMove = 1;
        targetx = 0;
    }
    else{
        int rightx = this->x()+this->width();
        if(rightx> (QApplication::desktop()->width()-EdgeAttachMargin)&&rightx!=QApplication::desktop()->width()){
            targetx = QApplication::desktop()->width()-this->width();
            enableMove = 1;
        }
        else
            targetx = this->x();
    }
    if(1==enableMove){
//        qDebug()<<"move action...";
        winAnimation(QPoint(targetx,targety),QPoint(this->x(),this->y()));//这里是调用吸附过去的动画,一个初始值,一个目标值,函数具体在后面
    }
}
注释都大概说了,下面就继续隐藏的计时触发的事件,这个代码可能多一点,其实也是一样的多些判断而已:

//处理隐藏的计时
void MainWindow::updateEdgeHide()
{
    QPoint mouP=QCursor::pos();
    QPoint target;
    QPoint oldpos;
    bool enableHS =false;//也是用做判断是否需要进行动画的标志位。
    if(winHide == winHideType::none&& this->isVisible() == true)
    {//还未隐藏
<span style="white-space:pre">	</span>//这里判断一下鼠标的位置是否不在窗体上,不在才需要进行隐藏的操作
        if(mouP.x()<this->x() || (mouP.x()-this->x())>this->width() || mouP.y()<this->y() || (mouP.y()-this->y())>this->height())
        {
            oldpos.setX(this->x());
            oldpos.setY(this->y());
<pre name="code" class="cpp">            //在上方的情况(如果在左右方,但是还是优先往上缩)
if(0==this->y()) { //缩起 target.setX(oldpos.x()); target.setY(EdgeShowWidth-this->height()); enableHS = true; winHide =winHideType::y; }else {
 
<span style="white-space:pre">		</span>//在左方的情况
                if(0==this->x())
                {
                    target.setX(EdgeShowWidth-this->width());
                    target.setY(oldpos.y());
                    enableHS = true;
                    winHide =winHideType::xleft;
                }else
<span style="white-space:pre">		</span>    //在右方的情况
                    if(QApplication::desktop()->width()==(oldpos.x()+this->width()))
                    {
                        target.setX(QApplication::desktop()->width()-EdgeShowWidth);
                        target.setY(oldpos.y());
                        enableHS = true;
                        winHide =winHideType::xright;
                    }
            }
        }
    }else
    {//已经隐藏,判断是否鼠标进入了屏幕边缘的窗体的区域,是就需要触发显示窗口的动作
        if(! (mouP.x()<this->x() || (mouP.x()-this->x())>this->width() || mouP.y()<this->y() || (mouP.y()-this->y())>this->height()) )
        {
            oldpos.setX(this->x());
            oldpos.setY(this->y());
<span style="white-space:pre">	</span>    //分别也是对应于上,左,右这三个方向。
            if(winHide == winHideType::y)
            {
                target.setX(oldpos.x());
                target.setY(0);
                enableHS = true;
                winHide =winHideType::none;
            }else
            {
                if(winHide == winHideType::xleft)
                {
                    target.setX(0);
                    target.setY(oldpos.y());
                    enableHS = true;
                    winHide =winHideType::none;
                }else
                    if(winHide == winHideType::xright)
                    {
                        target.setX(QApplication::desktop()->width() - this->width());
                        target.setY(oldpos.y());
                        enableHS = true;
                        winHide =winHideType::none;
                    }
            }
        }
    }
    //如果需要显示,就调用动画,同样是传原始和目标的值作为参数。
    if(true==enableHS){
//        qDebug()<<"hide show action..."<<winHide;
        winAnimation(target,oldpos);
    }
}
然后是调用的动画:

//隐藏动画
void MainWindow::winAnimation(QPoint target,QPoint oldpos)
{
    edgeMoveAnimation->setDuration(300);
    edgeMoveAnimation->setStartValue(QPoint(oldpos.x(),oldpos.y()));
    edgeMoveAnimation->setEndValue(QPoint(target.x(), target.y()));
    edgeMoveAnimation->setEasingCurve(QEasingCurve::OutCubic);
    edgeMoveAnimation->start();
    timer_edgeMove->stop();
    timer_edgeHide->stop();
    blockAll = true;

}
然后最后就是当动画在进行的时候你可以根据blockAll的状态来忽略一些鼠标的事件:

//处理鼠标的进入时间,用于自动隐藏
bool MainWindow::eventFilter(QObject* obj, QEvent* event)
{
    if(obj== this)
    {
        //播放动画时阻塞操作
        if(blockAll == true && event->type() == QEvent::MouseButtonPress)
            return true;
        if(event->type() == QEvent::MouseButtonPress)
        {
            mousePress = true;
            timer_edgeMove->stop();
//            qDebug()<<"MouseButtonPress"<<mousePress;
        }
        else if((event->type() == QEvent::MouseButtonRelease) && mousePress)
        {
            timer_edgeMove->start();
            mousePress= false;
//            qDebug()<<"MouseButtonRelease"<<mousePress;
        }
    }
    return QObject::eventFilter(obj, event);
}

就大致是这样的了,其实想法还是很简单的。

最后有一个就是,如果你想通过点击托盘,然后让窗口动画显示出来,那就在托盘双击的事件添加一个调用函数咯:

//点击还原时的show
void MainWindow::updateShowNormal()
{
    if(winHide != winHideType::none)
    {
        QPoint target;
        QPoint oldpos;
        bool enableHS;
        oldpos.setX(this->x());
        oldpos.setY(this->y());
        if(winHide == winHideType::y)
        {
            target.setX(oldpos.x());
            target.setY(0);
            enableHS = true;
            winHide =winHideType::none;
        }else
        {
            if(winHide == winHideType::xleft)
            {
                target.setX(0);
                target.setY(oldpos.y());
                enableHS = true;
                winHide =winHideType::none;
            }else
                if(winHide == winHideType::xright)
                {
                    target.setX(QApplication::desktop()->width() - this->width());
                    target.setY(oldpos.y());
                    enableHS = true;
                    winHide =winHideType::none;
                }
        }
        if(true==enableHS){
//            qDebug()<<"show normal action..."<<winHide;
            winAnimation(target,oldpos);
        }
    }
}
其实就是show出来而已,就先只有这样了。

  • 1
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值