Qt 之 模仿 QQ登陆界面——旋转窗口篇

2023-05-16

#一、简述
今天是新的一年第一篇博客,有大半个月没有更新博客了。我想是时候,打开电脑、拿起键盘、开始在我的代码之路上披荆斩棘,斩杀恶龙。

今天就继续来分享QQ登录界面的那些事。QQ登录界面的标题栏有一个小三角的按钮,一般情况下,大家可能并不会点击这个按钮,因为正常情况下大家登录QQ都不需要进行网络设置,只有在网络有限制的情况下,我们需要设置一些代理来登录QQ。

当我们点击这个小三角按钮,我们会发现QQ的有一个旋转动画从登录界面跳转到网络设置界面。仔细看其实会发现登录界面和网络设置界面不是同一个窗口,而且两个界面的宽高各不相等,也就是差不多在旋转到90度时切换了窗口。

那么是不是可以用Qt实现类似的效果呢?万能的Qt告诉你,当然可以。下面就来看一看如何实现。


###QQ登录界面点击小三角旋转到网络设置界面:
这里写图片描述


###我的效果
这里写图片描述


#二、代码之路

###rotatewidget.h

#ifndef ROTATEWIDGET_H
#define ROTATEWIDGET_H

#include <QStackedWidget>

class LoginWindow;
class LoginNetSetWindow;
class RotateWidget : public QStackedWidget
{
	Q_OBJECT

public:
	RotateWidget(QWidget *parent = NULL);
	~RotateWidget();

private:
	// 初始化旋转的窗口;
	void initRotateWindow();
	// 绘制旋转效果;
	void paintEvent(QPaintEvent* event);

private slots:
	// 开始旋转窗口;
	void onRotateWindow();
	// 窗口旋转结束;
	void onRotateFinished();

private:
	// 当前窗口是否正在旋转;
	bool m_isRoratingWindow;
	// 登录界面;
	LoginWindow* m_loginWindow;
	// 网络设置界面;
	LoginNetSetWindow* m_loginNetSetWindow;
	int m_nextPageIndex;
};

#endif // ROTATEWIDGET_H


###rotatewidget.cpp

#include "rotatewidget.h"
#include <QPropertyAnimation>
#include "loginwindow.h"
#include "loginnetsetwindow.h"

RotateWidget::RotateWidget(QWidget *parent)
	: QStackedWidget(parent)
	, m_isRoratingWindow(false)
	, m_nextPageIndex(0)
{
	this->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint| Qt::WindowMinimizeButtonHint);
	this->setAttribute(Qt::WA_TranslucentBackground);
	// 给窗口设置rotateValue属性;
	this->setProperty("rotateValue", 0);
	initRotateWindow();
}

RotateWidget::~RotateWidget()
{

}

// 初始化旋转的窗口;
void RotateWidget::initRotateWindow()
{
	m_loginWindow = new LoginWindow(this);
	// 这里定义了两个信号,需要自己去发送信号;
	connect(m_loginWindow, SIGNAL(rotateWindow()), this, SLOT(onRotateWindow()));
	connect(m_loginWindow, SIGNAL(closeWindow()), this, SLOT(close()));

	m_loginNetSetWindow = new LoginNetSetWindow(this);
	connect(m_loginNetSetWindow, SIGNAL(rotateWindow()), this, SLOT(onRotateWindow()));
	connect(m_loginNetSetWindow, SIGNAL(closeWindow()), this, SLOT(close()));

	this->addWidget(m_loginWindow);
	this->addWidget(m_loginNetSetWindow);

	// 这里宽和高都增加,是因为在旋转过程中窗口宽和高都会变化;
	this->setFixedSize(QSize(m_loginWindow->width() + 20, m_loginWindow->height() + 100));
}

// 开始旋转窗口;
void RotateWidget::onRotateWindow()
{
	// 如果窗口正在旋转,直接返回;
	if (m_isRoratingWindow)
	{
		return;
	}
	m_isRoratingWindow = true;
	m_nextPageIndex = (currentIndex() + 1) >= count() ? 0 : (currentIndex() + 1);
	QPropertyAnimation *rotateAnimation = new QPropertyAnimation(this, "rotateValue");
	// 设置旋转持续时间;
	rotateAnimation->setDuration(600);
	// 设置旋转角度变化趋势;
	rotateAnimation->setEasingCurve(QEasingCurve::InCubic);
	// 设置旋转角度范围;
	rotateAnimation->setStartValue(0);
	rotateAnimation->setEndValue(180);
	connect(rotateAnimation, SIGNAL(valueChanged(QVariant)), this, SLOT(repaint()));
	connect(rotateAnimation, SIGNAL(finished()), this, SLOT(onRotateFinished()));
	// 隐藏当前窗口,通过不同角度的绘制来达到旋转的效果;
	currentWidget()->hide();
	rotateAnimation->start();
}

// 旋转结束;
void RotateWidget::onRotateFinished()
{
	m_isRoratingWindow = false;
	setCurrentWidget(widget(m_nextPageIndex));
	repaint();
}

// 绘制旋转效果;
void RotateWidget::paintEvent(QPaintEvent* event)
{
	if (m_isRoratingWindow)
	{
		// 小于90度时;
		int rotateValue = this->property("rotateValue").toInt();
		if (rotateValue <= 90)
		{
			QPixmap rotatePixmap(currentWidget()->size());
			currentWidget()->render(&rotatePixmap);
			QPainter painter(this);
			painter.setRenderHint(QPainter::Antialiasing);
			QTransform transform;
			transform.translate(width() / 2, 0);
			transform.rotate(rotateValue, Qt::YAxis);
			painter.setTransform(transform);
			painter.drawPixmap(-1 * width() / 2, 0, rotatePixmap);
		}
		// 大于90度时
		else
		{
			QPixmap rotatePixmap(widget(m_nextPageIndex)->size());
			widget(m_nextPageIndex)->render(&rotatePixmap);
			QPainter painter(this);
			painter.setRenderHint(QPainter::Antialiasing);
			QTransform transform;
			transform.translate(width() / 2, 0);
			transform.rotate(rotateValue + 180, Qt::YAxis);
			painter.setTransform(transform);
			painter.drawPixmap(-1 * width() / 2, 0, rotatePixmap);
		}
	}
	else
	{
		return __super::paintEvent(event);
	}
}

####在LoginWindow和LoginNetSetWindow中实现鼠标拖拽窗口移动。
####本窗口不需要移动,只需通知父窗口移动即可

void LoginNetSetWindow::mousePressEvent(QMouseEvent *event)
{
	if (event->button() == Qt::LeftButton)
	{
		m_isPressed = true;
		m_startMovePos = event->globalPos();
	}

	return QWidget::mousePressEvent(event);
}

void LoginNetSetWindow::mouseMoveEvent(QMouseEvent *event)
{
	if (m_isPressed)
	{
		QPoint movePoint = event->globalPos() - m_startMovePos;
		QPoint widgetPos = this->parentWidget()->pos() + movePoint;
		m_startMovePos = event->globalPos();
		this->parentWidget()->move(widgetPos.x(), widgetPos.y());
	}
	return QWidget::mouseMoveEvent(event);
}

void LoginNetSetWindow::mouseReleaseEvent(QMouseEvent *event)
{
	m_isPressed = false;
	return QWidget::mouseReleaseEvent(event);
}

// 在子窗口关闭时通知关闭父窗口;
void LoginNetSetWindow::closeEvent(QCloseEvent *event)
{
	emit closeWindow();
	return __super::closeEvent(event);
}

###注意:
在设置窗口宽高时添加了如下代码,至于为什么?请看下面图片效果。

// 这里宽和高都增加,是因为在旋转过程中窗口宽和高都会变化;
this->setFixedSize(QSize(m_loginWindow->width() + 20, m_loginWindow->height() + 100));

这里写图片描述

我们知道使用QQ截图,在鼠标移动到某个窗口上时,QQ会自动将当前截图区域设置为这个窗口的大小,我们看到用QQ进行截图时,将鼠标放在QQ登录界面上选取的区域要大于实际的界面,所以QQ的登录界面并不是一个单独的窗口,而是后面那个透明窗口的子窗口,其实也就类似于我们将登录界面放在一个Widget 上,然后将这个Widget背景置为透明,至于为什么要加大宽高,是因为在旋转的过程中窗口的宽高发生了变化,然后不加大宽高,窗口将会被遮挡。

###加长宽高用QQ截图显示效果:
这里写图片描述

###不加长宽高的下方被遮挡:
这里写图片描述

我们发现窗口下方会被遮挡,这就是为什么要加长宽高了。至于为什么QQ窗口四周都会有多余空间,而我这里只有右方和下方是因为旋转效果不一样所以设置的不一样罢了。


#尾
通过QPropertyAnimation类来改变旋转角度值,在paintEvent不断绘制不同角度下的窗口来达到旋转的效果。在旋转到90度时切换窗口,将登陆窗口切换至网络设置窗口。但是在旋转绘制过程中会发现有界面的线条会弯曲,在视觉上会有一点小遗憾,这个问题暂时没有解决,后期如果能够解决将会更新代码。


###完整代码下载
模仿QQ登录窗口(Qt实例)

更新于2017年7月20日

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Qt 之 模仿 QQ登陆界面——旋转窗口篇 的相关文章

  • 使用python将数据导出excel表格

    python可用于数据分析 xff0c 有时候获得了数据需要导出以作其他作用 本文就介绍python导出excel表格的方法 导出excel表格 xff0c python提供了两个库 xff1a xlwt xlrd 本文只讨论下大致框架 s
  • matlab制作散点图及颜色调配

    散点图也是比较常用的数据分析图 xff0c 今天来聊聊用matlab如何画一个散点图出来 xff01 在matlab中 xff0c 对应散点图的函数是scatter 参数形式为scatter 横坐标 xff0c 纵坐标 xff0c 颜色 x
  • matlab——修改图中字体

    在画图的时候 xff0c 我们可以使用xlabel命名x轴的名字 xff0c 使用ylabel命名y轴的名字 xff0c 使用legend命名变量的名字 xff0c 使用title命名图片的标题 但标题的字体 xff0c 大小都是默认的 其
  • python绘制热力图

    在python中绘制热力图大致有两种方法通过matplotlib库的imshow函数以及seaborn库的heatmap函数 xff0c 通过笔者尝试 xff0c seaborn库更加灵活 xff0c 本篇以seaborn为准 源代码如下
  • 基址寻址和变址寻址区别(白话版)

    在寻址方式里面 xff0c 基址寻址和变址寻址是比较常用的两种寻址方式 但因为两种太像了 xff0c 总是搞不清楚 上网查到的描述太过专业看起来特别吃力 写这篇 xff0c 希望能用一种通俗易懂的方式对二者做个区分 为什么总容易搞混呢 xf
  • ROS修改pkg名和node名教程

    修改pkg名 有的时候最开始起了一个功能包package名 xff0c 但后来要进行修改 修改package名 xff0c 需要改两步然后重新catkin make即可 操作如下 xff1a 再回到工作空间执行catkin make即可 参
  • ROS-TCP-Connector and ROS-TCP-Endpoint

    Unity官方提供了和ROS交互的接口 xff1a ROS TCP Connector and ROS TCP Endpoint 有了这两个Unity就能够更好的和真实机器人做交互 两个接口的实现基于ROS ros bridge xff0c
  • Python 使用can模块(记录稿)

    直接安装 xff1a pip install python can 如果报这个错 更新一下pip pip3 install upgrade pip 或者是 pip install upgrade pip 再安装wrapt pip insta
  • Android Studio报错:W/System.err: java.net.SocketException: socket failed: EPERM (Operation not permitt

    解决方案 xff1a 在AndroidManifest xml中增加 xff1a span class token operator lt span uses span class token operator span permissio
  • C++简单实现http服务端客户端传输实例

    使用本代码有两个注意事项 xff1a 代码使用到了httplib库 xff0c 需要下载然后把 h文件放到自己的目录下 httplib下载地址 xff1a https gitcode net mirrors yhirose cpp http
  • VSCODE连接vmware虚拟机

    有时候想用VSOCDE中的ssh连接虚拟机 桥接模式 的终端进行操作 xff0c 但是执行ssh命令后总是报错 xff1a Could not connect to span class token number 192 168 span
  • 字符串加密工具

    可用于密码加密 xff0c 代码上阵 xff1a package com util import java security MessageDigest import java security NoSuchAlgorithmExcepti
  • 【RPLIDAR】ubuntu18.04安装cartographer源码并使用RPLIDAR A2M8 - R4建图

    1 创建工作空间 mkdir cartographer ws cd cartographer ws wstool init src 2 下载cartographer源码包 wstool merge t src https raw githu
  • 《C++ Primer Plus》学习笔记——第一章 介绍C++

    C 43 43 在C语言的基础上添加了面向对象编程和泛型编程 C 43 43 继承了C语言高效 简洁 快速和可移植性的传统 C 43 43 比C多了两样编程方法 xff0c 这使得它功能强大 xff0c 同样也意味着使用者需要学习更多的内容
  • 【转载】理解SIP的认证

    理解SIP的认证 From http blog sina com cn s blog 4b839a1b01000bqq html 1 认证和加密 认证 xff08 Authorization xff09 的作用在于表明自己是谁 xff0c
  • 尝试使用绕线法制作数字电路

    最近在学习电路制作的过程中 xff0c 发现使用洞洞板 xff0c 很难处理好具有很多复杂引脚的集成电路 用 锡接走线法 的话 xff0c 集成电路不能太多太复杂 xff0c 否则板子上很难排开 也可以用比较细的导线 xff0c 飞线焊接
  • 用C语言实现一个简单的HTTP客户端(HTTP Client)

    用C语言实现一个简单的HTTP Client xff08 HTTP客户端 xff09 作者 xff1a gobitan xff08 雨水 xff09 日期 xff1a 2007 04 03 转载请注明出处 http blog csdn ne
  • C语言常见的自定义数据类型(1)—— 结构体

    目录 1 结构体 1 1 结构体的定义 1 2 结构体的自引用 1 3 结构体类型的重命名 1 4 结构体的嵌套 2 结构体大小的计算 2 1 结构体内存对齐 2 2 嵌套结构体大小的计算 2 3 offsetof函数 2 4 修改默认对齐
  • 一篇解决!小白迷惑:Go mod本地包导入

    最近在学习go xff0c 在导入本都包遇到一个问题 xff0c 根据网上许多教程来都走不通 xff0c 最后在官网得到了最正确的答案 官网教程 xff1a Call your code from another module The Go
  • Linux nf_conntrack连接跟踪的实现

    连接跟踪 xff0c 顾名思义 xff0c 就是识别一个连接上双方向的数据包 xff0c 同时记录状态 下面看一下它的数据结构 xff1a struct nf conn Usage count in here is 1 for hash t

随机推荐

  • 组播MAC地址和各类IP地址

    MAC地址是以太网二层使用的一个48bit xff08 6字节十六进制数 xff09 的地址 xff0c 用来标识设备位置 MAC地址分成两部分 xff0c 前24位是组织唯一标识符 xff08 OUI Organizationally u
  • Linux内核中的软中断、tasklet和工作队列详解

    TOC 本文基于Linux2 6 32内核版本 引言 软中断 tasklet和工作队列并不是Linux内核中一直存在的机制 xff0c 而是由更早版本的内核中的 下半部 xff08 bottom half xff09 演变而来 下半部的机制
  • Linux内核中的各种锁

    Linux内核中的各种锁 在现代操作系统里 xff0c 同一时间可能有多个内核执行流在执行 xff0c 因此内核其实象多进程多线程编程一样也需要一些同步机制来同步各执行单元对共享数据的访问 尤其是在多处理器系统上 xff0c 更需要一些同步
  • Linux进程间通信方式

    进程与进程通信的概念进程通信的应用场景进程通信的几种方式 管道 管道简介管道原理 管道如何通信管道如何创建管道读写实现 管道api与用法 普通管道流管道命名管道 实现原理api与应用 匿名管道和有名管道总结 信号 信号来源信号生命周期和处理
  • C语言字节对齐问题详解

    引言 考虑下面的结构体定义 xff1a span class hljs keyword typedef span span class hljs keyword struct span span class hljs built in ch
  • git使用

    git使用 git clone时报如下错误 原因解决方法 TortoiseGit clone时报错 问题原因解决方法 git log使用git回归代码 git使用 本文记录的是工作中git是使用问题 xff0c 无脑模式 xff0c 遇到什
  • 内存对齐算法

    字节对齐是在分配内存时需要考虑的问题 xff0c 两个小算法 xff1a 1 最容易想到的算法 unsigned int calc align unsigned int n unsigned align if n align align 6
  • vscode快捷键整理

    1 注释 xff08 1 xff09 方式 注释 取消注释 xff1a Ctrl 43 xff08 2 xff09 方式 注释 xff1a Ctrl 43 Shift 43 取消注释 xff1a Ctrl 43 Shift 43 2 代码排
  • Qt之实现移动的方块(蚂蚁线)

    一 简介 移动的小方块或者说是类似移动的蚂蚁线 xff0c 从一篇文章看到的 xff0c 挺有趣的就自己做了一个 xff0c 可以自由添加方块的个数 xff0c 起始位置 xff0c 方块的宽度 xff0c 方块移动速度等待参数 xff0c
  • Docker 突然挂掉 failed to create shim task: OCI runtime create failed: container_linux.go:345: ...

    目录 问题描述 xff1a 参考 解决方案 最佳方案 xff1a 问题描述 xff1a docker Error response from daemon failed to create shim task OCI runtime cre
  • Qt之事件过滤器(eventFilter)详解

    1 2 1 Qt中事件是如何进行传递 1 2 2 Qt中的事件过滤器 xff08 eventFilter xff09 1 2 3 如何自己模拟发送事件消息 一 Qt中事件过滤器详解 我们先看下另外两个相关的方法 xff0c 一个是给对象安装
  • Qt实现微信截图功能(一)

    简述 Qt 之 简单截图功能 xff08 一 xff09 实现鼠标选中区域截图Qt 之 简单截图功能 xff08 二 xff09 实现可移动选中区域Qt 之 简单截图功能 xff08 三 xff09 实现可拖拽选中区域 在之前的文章中有带大
  • Qt之QMenu菜单去除投影效果(阴影)

    一 简述 我们使用Qt中的菜单 xff0c 正常情况下样式是跟随当前系统菜单的样式 xff0c 我们可以使用样式表进行修饰 xff0c 改变原有风格 xff0c 但是window系统上菜单边框四周会附带阴影的效果 xff0c 样式是无法取消
  • Qt 之 设置窗口边框的圆角

    Qt技术学习班开始了 xff0c 更多精彩 好玩的内容等着你 xff0c 赶紧报名吧 群号 xff1a 655815739 Qt在设置窗口边框圆角时有两种方式 xff0c 一种是设置样式 xff0c 另一种是在paintEvent事件中绘制
  • Qt 之 HTTP 请求下载(支持断点续传)

    简述 最近在研究了一下用Qt 的方法来实现http下载 xff0c Qt 中的Http请求主要用到了QNetworkAccessManager QNetworkReply QNetworkRequest 这三块 本篇文章主要叙述如何用Qt
  • Qt之实现录音播放及raw(pcm)转wav格式

    简述 在上一篇 Qt 之 WAV文件解析 中详细地分析了wav格式文件的文件头信息 通过QAudioInput实现录音功能 xff0c 但是录音生成的文件并不能用播放器打开 xff0c 就算更改后缀名也无法识别 xff08 有时候下载的一些
  • C++中 Unicode 与 UTF-8 编码互转

    1 简述 最近在发送网络请求时遇到了中文字符乱码的问题 xff0c 在代码中调试字符正常 xff0c 用抓包工具抓的包中文字符显示正常 xff0c 就是发送到服务器就显示乱码了 xff0c 那就要将客户端和服务器设置统一的编码 xff08
  • Qt 之 自定义按钮 在鼠标 悬浮、按下、松开后的效果

    Qt技术学习班开始了 xff0c 更多精彩 好玩的内容等着你 xff0c 赶紧报名吧 群号 xff1a 655815739 一 简述 在上一篇 Qt 之 去除窗口部件被选中后的焦点虚线框 中 xff0c 我们为了去除焦点虚线框 xff0c
  • Qt 之 自定义窗口标题栏

    Qt训练营开始了 xff0c 更多精彩 好玩的内容等着你 xff0c 赶紧报名吧 群号 xff1a 861353824 一 简述 今天晚上就如何用Qt自定义窗口标题栏 xff0c 写了一个小例子 xff0c 比较基础 xff0c 实用 在此
  • Qt 之 模仿 QQ登陆界面——旋转窗口篇

    一 简述 今天是新的一年第一篇博客 xff0c 有大半个月没有更新博客了 我想是时候 xff0c 打开电脑 拿起键盘 开始在我的代码之路上披荆斩棘 xff0c 斩杀恶龙 今天就继续来分享QQ登录界面的那些事 QQ登录界面的标题栏有一个小三角