本源码来自于州的先生基于 Python 的 PyQt5 库制作的新版 TIM 登录界面。
有关具体的代码实现思路和方式,详见下面的文章:
除了还原 TIM 登录界面样式之外,还实现了如下的交互:
- QQ/微信登录方式切换;
- 二维码扫码登陆切换;
- 用户名密码输入;
这份源码一共包含 1 个 Python 文件、1 个 JPG 图片文件和 15 个 svg 图片文件:
引入的模块
# coding:utf-8
# @文件: pyqt_tim_login_gui.py
# @创建者:州的先生
# #日期:2020/9/17
# 博客地址:zmister.com
# 公众号:zmister2016
from PyQt5 import QtWidgets,QtCore,QtGui
import sys
import qrcode
import io
主窗口类
class TimLogin(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.setFixedSize(680,520)
self.setObjectName('body')
self.setStyleSheet('''
QMainWindow#body{
background-color:white;
}
QToolButton,QPushButton{
border:none;
}
QPushButton:hover{
color:#333;
}
QCheckBox::indicator {
border: 1px solid #9FA3A9;
}
QWidget#acount_group,#pwd_gourp{
border-bottom:1px solid #E0E0E0;
}
QCheckBox,QLabel{
color:#9FA3A9;
}
QToolButton#wx_icon{
color:#9FA3A9;
}
QToolButton#wx_icon:hover{
color:#1ABB0E;
}
QToolButton#qq_icon{
color:#378AFE;
}
QToolButton#qq_icon:hover{
color:#378AFE;
}
QPushButton#setting_icon{
border-image: url("./setting.svg");
}
QPushButton#setting_icon:hover {
border-image: url("./setting_hover.svg");
}
QPushButton#close_icon{
border-image: url("./close.svg");
}
QPushButton#close_icon:hover {
border-image: url("./close_hover.svg");
}
QPushButton#acount_icon{
border-image: url("./lower.svg");
}
QPushButton#acount_icon:hover {
border-image: url("./lower_hover.svg");
}
QPushButton#forward_icon{
border-image: url("./forward.svg");
}
QPushButton#forward_icon:hover {
border-image: url("./forward_hover.svg");
}
QPushButton#qrcode_icon{
border-image: url("./qrcode.svg");
}
QPushButton#qrcode_icon:hover {
border-image: url("./qrcode_hover.svg");
}
QPushButton#close_icon{
border-image: url("./close.svg");
}
QPushButton#close_icon:hover {
border-image: url("./close_hover.svg");
}
''')
self.current_login = 'qq'
# 主控件
self.main_widget = QtWidgets.QWidget()
# 主布局
self.main_layout = QtWidgets.QGridLayout()
self.main_layout.setContentsMargins(0,0,0,0)
self.main_widget.setLayout(self.main_layout)
# 左侧背景控件
self.left_widget = QtWidgets.QWidget()
self.left_widget.setStyleSheet('''
background-image:url(./bg.jpg)
''')
# 顶部控制按钮组
self.top_btn_group = QtWidgets.QWidget()
self.top_btn_group_layout = QtWidgets.QHBoxLayout()
self.top_btn_group_layout.setAlignment(QtCore.Qt.AlignTop|QtCore.Qt.AlignRight) # 联合顶部对齐和右对齐
self.top_btn_group.setLayout(self.top_btn_group_layout)
self.top_setting_btn = QtWidgets.QPushButton()
self.top_setting_btn.setObjectName('setting_icon')
# self.top_setting_btn.setIcon(QtGui.QIcon('./setting.svg'))
self.top_setting_btn.setFixedSize(20,20)
self.top_setting_btn.setIconSize(QtCore.QSize(20,20))
self.top_setting_btn.setToolTip("设置")
self.top_close_btn = QtWidgets.QPushButton()
self.top_close_btn.setObjectName('close_icon')
# self.top_close_btn.setIcon(QtGui.QIcon('./close.svg'))
self.top_close_btn.setFixedSize(20,20)
self.top_close_btn.setIconSize(QtCore.QSize(20,20))
self.top_close_btn.setToolTip("关闭")
self.top_close_btn.clicked.connect(self.close_btn_slot)
# self.top_setting_btn.installEventFilter(self)
self.top_btn_group_layout.addWidget(self.top_setting_btn)
self.top_btn_group_layout.addWidget(self.top_close_btn)
# QQ 图标按钮
self.qq_icon = QtWidgets.QToolButton()
self.qq_icon.setObjectName('qq_icon')
self.qq_icon.setText("QQ 登录")
self.qq_icon.setIcon(QtGui.QIcon("./qq_hover.svg"))
self.qq_icon.setIconSize(QtCore.QSize(60,60))
self.qq_icon.setToolButtonStyle(QtCore.Qt.ToolButtonTextUnderIcon)
self.qq_icon.clicked.connect(self.switch_to_qq_login)
self.qq_icon.installEventFilter(self)
# 微信图标按钮
self.wx_icon = QtWidgets.QToolButton()
self.wx_icon.setObjectName('wx_icon')
self.wx_icon.setText("微信登录")
self.wx_icon.setIcon(QtGui.QIcon("./wx.svg"))
self.wx_icon.setIconSize(QtCore.QSize(60, 60))
self.wx_icon.setToolButtonStyle(QtCore.Qt.ToolButtonTextUnderIcon)
self.wx_icon.installEventFilter(self)
self.wx_icon.clicked.connect(self.switch_to_wx_login)
# 图标按钮组
self.icon_btn_group = QtWidgets.QWidget()
self.icon_btn_group_layout = QtWidgets.QHBoxLayout()
self.icon_btn_group.setLayout(self.icon_btn_group_layout)
self.icon_btn_group_layout.addWidget(self.qq_icon)
self.icon_btn_group_layout.addWidget(self.wx_icon)
# 微信二维码扫码登陆
self.wx_qrcode = QtWidgets.QLabel()
self.wx_qrcode.setObjectName('wx_qrcode')
self.genera_qrcode()
self.wx_qrcode.setContentsMargins(8,5,0,10)
self.wx_qrcode_label = QtWidgets.QLabel("请使用微信扫描二维码登录")
self.wx_qrcode_group = QtWidgets.QWidget()
self.wx_qrcode_group.setContentsMargins(0,0,0,100)
self.wx_qrcode_group.setFixedHeight(313)
self.wx_qrcode_group_layout = QtWidgets.QVBoxLayout()
self.wx_qrcode_group_layout.setAlignment(QtCore.Qt.AlignCenter)
self.wx_qrcode_group.setLayout(self.wx_qrcode_group_layout)
self.wx_qrcode_group_layout.addWidget(self.wx_qrcode)
self.wx_qrcode_group_layout.addWidget(self.wx_qrcode_label)
# 表单输入
self.acount_input = QtWidgets.QLineEdit()
font = self.acount_input.font()
font.setPointSize(16)
self.acount_input.setFont(font)
self.acount_input.setStyleSheet('''
border: dashed 1px #9FA3A9;
''')
self.acount_icon = QtWidgets.QPushButton()
self.acount_icon.setObjectName('acount_icon')
# self.acount_icon.setIcon(QtGui.QIcon('./lower.svg'))
self.acount_icon.setIconSize(QtCore.QSize(20,20))
self.acount_icon.setFixedSize(20,20)
self.acount_gourp = QtWidgets.QWidget()
self.acount_gourp.setObjectName('acount_group')
self.acount_gourp_layout = QtWidgets.QHBoxLayout()
self.acount_gourp.setLayout(self.acount_gourp_layout)
self.acount_gourp_layout.addWidget(self.acount_input)
self.acount_gourp_layout.addWidget(self.acount_icon)
self.pwd_input = QtWidgets.QLineEdit()
self.pwd_input.setEchoMode(QtWidgets.QLineEdit.Password)
self.pwd_input.setFont(font)
self.pwd_input.setStyleSheet('''
border: dashed 1px #9FA3A9;
''')
self.pwd_icon = QtWidgets.QPushButton()
self.pwd_icon.setObjectName('forward_icon')
self.pwd_icon.setIconSize(QtCore.QSize(20, 20))
self.pwd_icon.setFixedSize(20,20)
self.pwd_gourp = QtWidgets.QWidget()
self.pwd_gourp.setObjectName('pwd_gourp')
self.pwd_gourp_layout = QtWidgets.QHBoxLayout()
self.pwd_gourp.setLayout(self.pwd_gourp_layout)
self.pwd_gourp_layout.addWidget(self.pwd_input)
self.pwd_gourp_layout.addWidget(self.pwd_icon)
self.qrcode_icon = QtWidgets.QPushButton()
self.qrcode_icon.setObjectName('qrcode_icon')
self.qrcode_icon.setIconSize(QtCore.QSize(16, 16))
self.qrcode_icon.setFixedSize(16, 16)
self.qrcode_widget = QtWidgets.QWidget()
self.qrcode_widget_layout = QtWidgets.QHBoxLayout()
self.qrcode_widget_layout.setAlignment(QtCore.Qt.AlignRight)
self.qrcode_widget.setLayout(self.qrcode_widget_layout)
self.qrcode_widget_layout.addWidget(self.qrcode_icon)
self.qrcode_icon.clicked.connect(self.switch_to_tim_qrcode_login)
self.form_group = QtWidgets.QWidget()
self.form_group_layout = QtWidgets.QVBoxLayout()
self.form_group.setLayout(self.form_group_layout)
self.form_group_layout.addWidget(self.acount_gourp)
self.form_group_layout.addWidget(self.pwd_gourp)
self.form_group_layout.addWidget(self.qrcode_widget)
# 选项
self.option_group = QtWidgets.QWidget()
self.option_group_layout = QtWidgets.QGridLayout()
self.option_group_layout.setContentsMargins(50,0,0,0)
self.option_group.setLayout(self.option_group_layout)
# 记住密码
self.remunber_pwd = QtWidgets.QCheckBox("记住密码")
self.find_pwd = QtWidgets.QLabel("找回密码")
self.auto_login = QtWidgets.QCheckBox("自动登录")
self.register = QtWidgets.QLabel("注册账号")
self.option_group_layout.addWidget(self.remunber_pwd,0,0,1,1)
self.option_group_layout.addWidget(self.find_pwd,0,1,1,1)
self.option_group_layout.addWidget(self.auto_login,1,0,1,1)
self.option_group_layout.addWidget(self.register,1,1,1,1)
# 右侧表单控件
self.right_widget = QtWidgets.QWidget()
self.right_layout = QtWidgets.QGridLayout()
self.right_widget.setLayout(self.right_layout)
self.right_layout.addWidget(self.top_btn_group,0,0,1,2)
self.right_layout.addWidget(self.icon_btn_group,1,0,1,2)
self.right_layout.addWidget(self.form_group,2,0,1,2)
self.right_layout.addWidget(self.option_group,3,0,2,2)
# 右侧 TIm 二维码控件 - 初始隐藏
self.right_qrcode_ui()
# 添加到主布局层
self.main_layout.addWidget(self.left_widget,0,0,5,3) #
self.main_layout.addWidget(self.right_widget,0,3,5,2)
self.main_layout.setSpacing(0) # 设置网格布局层中部件的间隙
self.setCentralWidget(self.main_widget)
self.setWindowFlag(QtCore.Qt.FramelessWindowHint)
def right_qrcode_ui(self):
# 顶部控制按钮组
self.control_btn_group = QtWidgets.QWidget()
self.control_btn_group_layout = QtWidgets.QHBoxLayout()
self.control_btn_group_layout.setAlignment(QtCore.Qt.AlignTop | QtCore.Qt.AlignRight) # 联合顶部对齐和右对齐
self.control_btn_group.setLayout(self.control_btn_group_layout)
self.control_back_btn = QtWidgets.QPushButton()
self.control_back_btn.setIcon(QtGui.QIcon('./back.svg'))
self.control_back_btn.setFixedSize(20,20)
self.control_back_btn.setIconSize(QtCore.QSize(20,20))
self.control_back_btn.setToolTip('返回')
self.control_back_btn.clicked.connect(self.switch_to_normal_login)
self.control_setting_btn = QtWidgets.QPushButton()
self.control_setting_btn.setObjectName('setting_icon')
self.control_setting_btn.setFixedSize(20, 20)
self.control_setting_btn.setIconSize(QtCore.QSize(20, 20))
self.control_setting_btn.setToolTip("设置")
self.control_close_btn = QtWidgets.QPushButton()
self.control_close_btn.setObjectName('close_icon')
self.control_close_btn.setFixedSize(20, 20)
self.control_close_btn.setIconSize(QtCore.QSize(20, 20))
self.control_close_btn.setToolTip("关闭")
self.control_close_btn.clicked.connect(self.close_btn_slot)
self.control_btn_group_layout.addWidget(self.control_back_btn)
self.control_btn_group_layout.addWidget(self.control_setting_btn)
self.control_btn_group_layout.addWidget(self.control_close_btn)
# 二维码
self.tim_qrcode = QtWidgets.QLabel()
self.tim_qrcode.setObjectName('wx_qrcode')
self.tim_qrcode.setPixmap(self.genera_qrcode())
self.tim_qrcode.setContentsMargins(8, 5, 0, 10)
self.tim_qrcode_label = QtWidgets.QLabel("用 <a href='https://office.qq.com/'>TIM 手机版 </a> 扫描二维码登录")
self.tim_qrcode_label.setOpenExternalLinks(True)
self.tim_qrcode_group = QtWidgets.QWidget()
self.tim_qrcode_group.setContentsMargins(0, 0, 0, 100)
self.tim_qrcode_group.setFixedHeight(300)
self.tim_qrcode_group_layout = QtWidgets.QVBoxLayout()
self.tim_qrcode_group_layout.setAlignment(QtCore.Qt.AlignCenter)
self.tim_qrcode_group.setLayout(self.tim_qrcode_group_layout)
self.tim_qrcode_group_layout.addWidget(self.tim_qrcode)
self.tim_qrcode_group_layout.addWidget(self.tim_qrcode_label)
self.right_qrcode_widget = QtWidgets.QWidget()
self.right_qrcode_widget_layout = QtWidgets.QGridLayout()
self.right_qrcode_widget.setLayout(self.right_qrcode_widget_layout)
self.right_qrcode_widget_layout.addWidget(self.control_btn_group)
self.right_qrcode_widget_layout.addWidget(self.tim_qrcode_group)
# 窗口关闭信号
def close_btn_slot(self):
# self.close()
self.parent().close()
# 事件过滤器
def eventFilter(self, QObject, QEvent):
# print(QObject)
# 修改微信图标
if QObject is self.wx_icon:
if self.current_login == 'qq':
if QEvent.type() == QtCore.QEvent.HoverEnter:
self.wx_icon.setIcon(QtGui.QIcon('./wx_hover.svg'))
elif QEvent.type() == QtCore.QEvent.HoverLeave:
self.wx_icon.setIcon(QtGui.QIcon('./wx.svg'))
if QObject is self.qq_icon:
if self.current_login == 'wx':
if QEvent.type() == QtCore.QEvent.HoverEnter:
self.qq_icon.setIcon(QtGui.QIcon('./qq_hover.svg'))
elif QEvent.type() == QtCore.QEvent.HoverLeave:
self.qq_icon.setIcon(QtGui.QIcon('./qq.svg'))
return False
# 切换到微信登录
def switch_to_wx_login(self):
if self.current_login == 'qq':
# 移除表单和选项控件
self.right_layout.removeWidget(self.form_group)
self.right_layout.removeWidget(self.option_group)
self.form_group.hide()
self.option_group.hide()
# 添加二维码控件
self.right_layout.addWidget(self.wx_qrcode_group,2,0,3,2)
self.wx_qrcode_group.show()
# 设置微信图标状态
self.wx_icon.setIcon(QtGui.QIcon('./wx_hover.svg'))
self.current_login = 'wx'
# 设置 QQ 图标状态
self.qq_icon.setIcon(QtGui.QIcon('./qq.svg'))
self.wx_icon.setStyleSheet('''
QToolButton#wx_icon{
color:#1ABB0E;
}
QToolButton#wx_icon:hover{
color:#1ABB0E;
}
''')
self.qq_icon.setStyleSheet('''
QToolButton#qq_icon{
color:#9FA3A9;
}
QToolButton#qq_icon:hover{
color:#378AFE;
}
''')
# 切换到 QQ 登录
def switch_to_qq_login(self):
if self.current_login == 'wx':
# 移除二维码控件
self.right_layout.removeWidget(self.wx_qrcode_group)
self.wx_qrcode_group.hide()
# 添加表单控件
self.right_layout.addWidget(self.form_group, 2, 0, 1, 2)
self.right_layout.addWidget(self.option_group,3,0,2,2)
self.option_group.show()
self.form_group.show()
# 设置微信图标状态
self.wx_icon.setIcon(QtGui.QIcon('./wx.svg'))
self.current_login = 'qq'
# 设置 QQ 图标状态
self.qq_icon.setIcon(QtGui.QIcon('./qq_hover.svg'))
self.wx_icon.setStyleSheet('''
QToolButton#wx_icon{
color:#9FA3A9;
}
QToolButton#wx_icon:hover{
color:#1ABB0E;
}
''')
self.qq_icon.setStyleSheet('''
QToolButton#qq_icon{
color:#378AFE;
}
QToolButton#qq_icon:hover{
color:#378AFE;
}
''')
# 切换到 TIM 手机扫码登陆
def switch_to_tim_qrcode_login(self):
# 移除右侧控件
self.main_layout.removeWidget(self.right_widget)
self.right_widget.hide()
# 添加 TIM 扫码登陆控件
self.main_layout.addWidget(self.right_qrcode_widget,0,3,5,2)
self.right_qrcode_widget.show()
# 切换到常规登录
def switch_to_normal_login(self):
# 移除右侧控件
self.main_layout.removeWidget(self.right_qrcode_widget)
self.right_qrcode_widget.hide()
# 添加常规登录控件
self.main_layout.addWidget(self.right_widget,0,3,5,2)
self.right_widget.show()
# 生成一个二维码
def genera_qrcode(self,qr_text="https://zmister.com"):
qr = qrcode.QRCode(
version=1,
box_size=5,
border=0
)
qr.add_data(qr_text)
self.qr_img = qr.make_image()
fp = io.BytesIO()
self.qr_img.save(fp, "BMP")
image = QtGui.QImage()
image.loadFromData(fp.getvalue(), "BMP")
qr_pixmap = QtGui.QPixmap.fromImage(image)
self.wx_qrcode.setPixmap(qr_pixmap)
return qr_pixmap
容器类
class Container(QtWidgets.QWidget):
def __init__(self, window):
super().__init__()
self.setWindowFlags(QtCore.Qt.FramelessWindowHint)
self.setAttribute(QtCore.Qt.WA_TranslucentBackground)
lay = QtWidgets.QVBoxLayout(self)
lay.addWidget(window)
lay.setContentsMargins(10, 10, 10, 10)
shadow = QtWidgets.QGraphicsDropShadowEffect(self,
blurRadius=9.0,
color=QtGui.QColor(116, 116, 116),
offset=QtCore.QPointF(0, 0)
)
window.setGraphicsEffect(shadow)
# 重写三个方法使我们的窗口支持拖动,上面参数 window 就是拖动对象
def mousePressEvent(self, event): # 鼠标长按事件
if event.button() == QtCore.Qt.LeftButton:
self.m_drag = True
self.m_DragPosition = event.globalPos() - self.pos()
event.accept()
self.setCursor(QtGui.QCursor(QtCore.Qt.OpenHandCursor))
def mouseMoveEvent(self, QMouseEvent): # 鼠标移动事件
if QtCore.Qt.LeftButton and self.m_drag:
self.move(QMouseEvent.globalPos() - self.m_DragPosition)
QMouseEvent.accept()
def mouseReleaseEvent(self, QMouseEvent): # 鼠标释放事件
self.m_drag = False
self.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor))
运行方法
def main():
app = QtWidgets.QApplication(sys.argv)
gui = TimLogin()
container = Container(gui)
container.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
资源图片
州的先生微信公众号回复“0022”获取所需的图片文件资源。
文章版权所有:州的先生博客,转载必须保留出处及原文链接