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);
}