对于这个效果的实现,其实方法应该还是很多的,这里的实现简单的原理只是一种,可能还不是很好,做个借鉴吧。
大概就是需要两个的计时器,第一个是用来判断窗口是不是在边缘附近,我们要把它吸附上去;第二个是用来判断是不是满足了隐藏,或者显示的效果的条件。然后利用动画来进行这些显示的过度,在过程中先中断一下事件处理,让窗口动画先走玩(很短,而且被事件中断的话,用户交互也不太友好)。其实原理就很简单的,还是上一下简单的代码了。
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()<x()<y();
//y方向的判断,这里EdgeAttachMargin是自定义的一个你想要让他吸附的距离,就是靠边缘多近要吸附上去,enableMove是用来最后判断是否需要动画的一个标志位
if(this->y()y()!=0){
targety = 0;
enableMove = 1;
}
else
targety = this->y();
//x方向和y差别不大,就是需要多判断一下左右的两种情况,y只需要上方一种情况。
if(this->x()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)
{//还未隐藏
//这里判断一下鼠标的位置是否不在窗体上,不在才需要进行隐藏的操作
if(mouP.x()x() || (mouP.x()-this->x())>this->width() || mouP.y()y() || (mouP.y()-this->y())>this->height())
{
oldpos.setX(this->x());
oldpos.setY(this->y());
//在上方的情况(如果在左右方,但是还是优先往上缩)
if(0==this->y()) { //缩起 target.setX(oldpos.x()); target.setY(EdgeShowWidth-this->height()); enableHS = true; winHide =winHideType::y; }else {
//在左方的情况
if(0==this->x())
{
target.setX(EdgeShowWidth-this->width());
target.setY(oldpos.y());
enableHS = true;
winHide =winHideType::xleft;
}else
//在右方的情况
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()x() || (mouP.x()-this->x())>this->width() || mouP.y()y() || (mouP.y()-this->y())>this->height()) )
{
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()<<"hide show action..."<
然后是调用的动画:
//隐藏动画
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"<type() == QEvent::MouseButtonRelease) && mousePress)
{
timer_edgeMove->start();
mousePress= false;
// qDebug()<<"MouseButtonRelease"<
就大致是这样的了,其实想法还是很简单的。
最后有一个就是,如果你想通过点击托盘,然后让窗口动画显示出来,那就在托盘双击的事件添加一个调用函数咯:
//点击还原时的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..."<
其实就是show出来而已,就先只有这样了。