qt 完全实现qq翻转登录界面

如何用qt实现qq登录界面翻转效果,这个问题已经纠结我很久了。在一段时间后,再次重新回到这个问题,终于解决了                                                                                                          

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框架了
。同时也谢谢搜到的那篇博主。




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值