QWidget是甚于2维坐标的,所以要实现像qq那样的翻转效果,必须要能够绕y轴在3维空间旋转。看了一些网上教程参考博客
http://www.th7.cn/Program/Python/201504/430277.shtml
用到的是QGraphics框架,所以也就用它做了。
注意看的话,上面好像有点bug;不要怀疑,那是因为GIF播放结束,重新播放时的重置效果。代码如下
#include <QApplication>
#include <QWidget>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QGraphicsProxyWidget>
#include <QGraphicsView>
#include <QGraphicsScene>
#include <QTimer>
#include <QDebug>
#include <QTimeLine>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
//新建登录窗体控件
QWidget *wid1 = new QWidget;
QLabel *user = new QLabel(QStringLiteral("用户名:"));
QLabel *password = new QLabel(QStringLiteral("密 码:"));
QLineEdit *userEdit = new QLineEdit;
userEdit->setPlaceholderText(QStringLiteral("请输入用户名"));
QLineEdit *passwordEdit = new QLineEdit;
passwordEdit->setPlaceholderText(QStringLiteral("请输入密码"));
//输入窗体布局
QHBoxLayout *usrHBoxLay = new QHBoxLayout;
usrHBoxLay->addWidget(user);
usrHBoxLay->addWidget(userEdit);
QHBoxLayout *passwordHBoxLay = new QHBoxLayout;
passwordHBoxLay->addWidget(password);
passwordHBoxLay->addWidget(passwordEdit);
QVBoxLayout *vBoxLay1 = new QVBoxLayout;
vBoxLay1->addLayout(usrHBoxLay);
vBoxLay1->addLayout(passwordHBoxLay);
wid1->setLayout(vBoxLay1);
//新建设置窗体控件
QWidget *wid2 = new QWidget;
QLabel *ip = new QLabel(QStringLiteral("IP地址"));
QLabel *port = new QLabel(QStringLiteral("端口号"));
QLineEdit *ipEdit = new QLineEdit;
ipEdit->setPlaceholderText(QStringLiteral("请输入IP地址"));
QLineEdit *portEdit = new QLineEdit;
portEdit->setPlaceholderText(QStringLiteral("请输入端口号"));
//设置窗体布局
QHBoxLayout *ipHBoxLay = new QHBoxLayout;
ipHBoxLay->addWidget(ip);
ipHBoxLay->addWidget(ipEdit);
QHBoxLayout *portHBoxLay = new QHBoxLayout;
portHBoxLay->addWidget(port);
portHBoxLay->addWidget(portEdit);
QVBoxLayout *vBoxLay2 = new QVBoxLayout;
vBoxLay2->addLayout(ipHBoxLay);
vBoxLay2->addLayout(portHBoxLay);
wid2->setLayout(vBoxLay2);
//新建View和Scene
QGraphicsView *view = new QGraphicsView;
QGraphicsScene *scene = new QGraphicsScene;
view->setScene(scene);
//加入登录和设置窗体
QGraphicsProxyWidget *graphicsWid1 = scene->addWidget(wid1);
QGraphicsProxyWidget *graphicsWid2 = scene->addWidget(wid2);
//设置窗体旋转-180度,并隐藏
graphicsWid2->setTransform(QTransform().translate(graphicsWid2->boundingRect().width()/2,graphicsWid2->boundingRect().height()/2)
.rotate(-180,Qt::YAxis)
.translate(-graphicsWid2->boundingRect().width()/2,-graphicsWid2->boundingRect().height()/2));
graphicsWid2->setVisible(false);
//新建线型值闹钟
QTimeLine *timeLine = new QTimeLine(1500,scene);
timeLine->setStartFrame(0);
timeLine->setEndFrame(180);
//每次值发生变化,旋转一定角度
QObject::connect(timeLine,&QTimeLine::frameChanged,[timeLine,graphicsWid1,graphicsWid2](const int frame){
//对于登录窗体正常旋转
graphicsWid1->setTransform(QTransform().translate(graphicsWid1->boundingRect().width()/2,graphicsWid1->boundingRect().height()/2)
.rotate(frame,Qt::YAxis)
.translate(-graphicsWid1->boundingRect().width()/2,-graphicsWid1->boundingRect().height()/2));
//对于设置窗体由于开始旋转到了-180度,所以现在应该是-179,-176,-170....,0,这里应该是frame-180;也就是加上起点为-180度啦
graphicsWid2->setTransform(QTransform().translate(graphicsWid2->boundingRect().width()/2,graphicsWid2->boundingRect().height()/2)
.rotate(frame - 180,Qt::YAxis)
.translate(-graphicsWid2->boundingRect().width()/2,-graphicsWid2->boundingRect().height()/2));
switch (timeLine->direction()) {
case QTimeLine::Forward: //前面向后面转,frame从0到180,当frame大于或等于90度时,显示设置窗体,登录窗体隐藏
if(frame > 90 || frame == 90){
graphicsWid1->setVisible(false);
graphicsWid2->setVisible(true);
}
break;
case QTimeLine::Backward: //后面向前面转,frame从180到0,当frame小于或等于90度时,显示登录窗体,设置窗体隐藏
if(frame < 90 || frame == 90){
graphicsWid1->setVisible(true);
graphicsWid2->setVisible(false);
}
break;
}
});
//旋转结束后,设置线形闹钟值的方向
QObject::connect(timeLine,&QTimeLine::finished,[timeLine]{
timeLine->toggleDirection();
});
//启用闹钟,每过一段时间,启动一次线型闹钟
QTimer *timer = new QTimer;
timer->setInterval(3000);
QObject::connect(timer,&QTimer::timeout,[timeLine]{timeLine->start();});
view->show();
timer->start();
return a.exec();
}
QTimeLine 是一个线形值定时器
它可以附带一个值的变化,对应的信号是valueChanged和frameChanged。valueChanged是0-1之间,frameChanged是startFrame()和endFrame()之间,对应值
是从小到大方向,还是从大到小方向;这个取决于direction()属性值。
setTransform是一个设置旋转的函数,函数执行结束直接旋转到指定位置
在QGraphicsScene中的图元或者QWidget通过QGraphicsScene通过addWidget返回的QGraphicsProxyWidget都可以通过该函数旋转,并且可以指定旋转轴。
在开始窗体的角度为0度,初始化后背面的窗体变为-180度;在闹钟驱动旋转时,此时背面窗体要与前面窗体一起旋转,而且角度应该是-180度到0度,线形闹钟反向,然后又是0度到-180度这点很关键。而前面的窗体开始是0度,旋转一次后变180,线型闹钟反向,再转一次又回到0就不需要额外操作。第一次做就是没有注意到这里,所以没有解决,这次终于搞定。另外就是根据旋转方向设置其中一个隐藏,一个显示以90度为界限,这个大家都懂吧。
其它方法
也就是在今晚发面这篇博客的同时,我突然搜到了一个解决这个问题的另一种方案,为什么在今晚写博客之前,从未找到过,真草蛋。
方法类似,主要还是我对类还不够全面的熟悉呀。原来QPainter也有setTransform方法,这样就可以直接在QWidget的paint函数中直接旋转了就用不着QGraphics框架了
。同时也谢谢搜到的那篇博主。