QT--实现滑动切换界面
一、前言
之前用QT写的多界面,基本上都是触发按钮来实现,存在一些问题。一来界面切换生硬,毫无美感;二来随着触摸屏的大众化,用户在潜移默化中已经习惯了类似于滑动这样的手势操作。于是我就突发奇想,想实现这样的效果,这种滑动切换效果在工业开发板上是很实用的,因为工业开发板屏幕尺寸往往偏小,直接点击按钮不太方便。
在这里提供了下载地址。
二、效果展示
图一:初步开发的效果
图二:改进之后的效果
三、原理详解
滑动切换,我们把它理解为两个动作,分别是:滑动和切换。
首先,讲解滑动的实现原理:
滑动是用Qt的鼠标事件来实现的。可以直接采用
mousePressEvent
配合mouseReleaseMove
来实现,也可以采用事件监听器来实现(我抱着学习的心态采用的这个,因为之前没接触过)。事件监听怎么用,可以参考我的博文:Qt事件。
当鼠标点下的时候,记录一下鼠标的起始位置;当鼠标松开的时候,记录一下鼠标的当前位置;然后根据两个坐标去判断,鼠标是否发生了移动,如果移动了,那就执行滑动之后要发生的事件。滑动又分为左滑和右滑,而且移动了多少算是滑动,这需要定一个标准,当移动距离超过了设定的标准,则判定为产生了滑动。
其次,讲解切换的原理:
widget的切换,其实就直接用show()和hide就可以实现,或者是QStackWidget的setCurrentIndex()。但是这样切换界面是瞬间的,没有一个过渡动画,显然这不是我想要的效果(模拟手机界面滑动)。为了实现这样的效果,我们可以截图当前界面,然后画到Label上,然后先切换完界面,再把Label平移出去,这样就实现了图一的效果。
但是这还是没有完全模拟到滑动界面切换(手机的界面切换是一个界面滑出去,一个界面滑进来),所以继续进行改进。要实现一个界面滑出去,接着一个界面滑出来,这就有两个动作了,所以我们需要把两个动画(QPropertyAnimation)放在一个动画容器(QParallelAnimationGroup)里,然后一起播放。画面1是滑出去,画面2是滑进来,连贯起来就实现了图二的效果。
四、具体实现
bool Widget::eventFilter(QObject *watch, QEvent *evn)
{
static int press_x; //鼠标按下时的位置
static int press_y;
static int relea_x; //鼠标释放时的位置
static int relea_y;
QMouseEvent *event = static_cast<QMouseEvent *>(evn); //将之转换为鼠标事件
if(event->type()==QEvent::MouseButtonPress) //如果鼠标按下
{
press_x = event->globalX();
press_y = event->globalY();
}
if(event->type()==QEvent::MouseButtonRelease) //如果鼠标释放
{
relea_x = event->globalX();
relea_y = event->globalY();
}
//判断滑动方向(右滑)
if((relea_x - press_x)>20 && event->type()==QEvent::MouseButtonRelease && qAbs(relea_y-press_y)<50)
{
int current_page = ui->stackedWidget->currentIndex();
if(current_page<=2)
{
ui->label->setPixmap(ui->stackedWidget->currentWidget()->grab()); //捕获当前界面并绘制到label上
QPropertyAnimation *animation1 = new QPropertyAnimation(ui->label,"geometry");
animation1->setDuration(1000); //设置动画时间为1秒
animation1->setStartValue(QRect(0,0,this->width(),this->height()));
animation1->setEndValue(QRect(this->width()*2,0,this->width(),this->height()));
ui->stackedWidget->setCurrentIndex(current_page+1); //切换界面
QPropertyAnimation *animation2 = new QPropertyAnimation(ui->stackedWidget->currentWidget(),"geometry");
animation2->setDuration(1000);
animation2->setStartValue(QRect(-this->width()*2,0,this->width(),this->height()));
animation2->setEndValue(QRect(0,0,this->width(),this->height()));
QParallelAnimationGroup *group = new QParallelAnimationGroup; //动画容器
group->addAnimation(animation1);
group->addAnimation(animation2);
group->start();
}
}
//判断滑动方向(左滑)
if((press_x - relea_x)>20 && event->type()==QEvent::MouseButtonRelease && qAbs(relea_y-press_y)<50)
{
int current_page = ui->stackedWidget->currentIndex();
if(current_page>=0)
{
ui->label->setPixmap(ui->stackedWidget->currentWidget()->grab());
QPropertyAnimation *animation1 = new QPropertyAnimation(ui->label,"geometry");
animation1->setDuration(1000);
animation1->setStartValue(QRect(0,0,this->width(),this->height()));
animation1->setEndValue(QRect(-this->width(),0,this->width(),this->height()));
ui->stackedWidget->setCurrentIndex(current_page-1);
QPropertyAnimation *animation2 = new QPropertyAnimation(ui->stackedWidget->currentWidget(),"geometry");
animation2->setDuration(1000);
animation2->setStartValue(QRect(this->width()*2,0,this->width(),this->height()));
animation2->setEndValue(QRect(0,0,this->width(),this->height()));
QParallelAnimationGroup *group = new QParallelAnimationGroup;
group->addAnimation(animation1);
group->addAnimation(animation2);
group->start();
}
}
return QWidget::eventFilter(watch,evn);
}