基于PyQt5实现仿QQ-第二章-用户登录
基于PyQt5实现仿QQ-第二章-用户登录
Author: Daydreamer
项目简介
本项目基于PyQt5仿照目前流行的即时通信软件QQ,实现了新用户注册、用户登录、自动登录、记住多用户账号、用户搜索、添加好友、好友间聊天(消息持久化、同步化)等功能。
项目技术栈
- PyQt5: 本项目界面基于PyQt5实现。
- MySQL: 项目中的用户个人信息表、好友聊天记录表、好友表均由MySQL实现。
- SQLite: 使用SQLite将用户的账号密码存储于本地,实现了自动登录功能。
- WebSocket: 项目聊天功能基于WebSocket实现。
- FastAPI: 使用FastAPI将WebSocket服务部署到服务器,实现了任意IP间的通信。
- RabbitMQ: 基于RabbitMQ消息队列实现了消息真正的持久化(不存在好友离线接收不到消息),当用户一上线立刻会收到新消息。
- Minio: 基于Minio云存储服务器存储用户的头像、聊天记录中的图片、问价、视频等资源。
登录功能的实现
登录逻辑
接收界面用户输入的账号密码,点击登录按钮进行用户登录。通过用户的账号用户表中查询用户的相关信息(加密后的密码、用户头像url等),对数据表中的密码解密并与用户输入的密码进行比对,如果一样则登录成功,否则登录失败。
记住密码逻辑
用户可以在登录界面勾选记住密码选择项,在用户点击登录按钮后,系统会根据用户是否勾选记住密码选择项来将用户的账号密码(加密后)保存到SQLite数据库中。这样当用户下次启动QQ时,系统会自动加载SQLite本地的用户数据到界面。
自动登录逻辑
用户可以在登录界面勾选自动登录选择项,当用户下次启动QQ时,系统会自动获取界面上首个记住密码的账号相关信息,然后自动进行用户登录。
数据库表结构
用户信息表–MySQL
本地用户信息表–SQLite
登录UI界面代码
# -*- coding: utf-8 -*-# Form implementation generated from reading ui file '.\login_ui.ui'
#
# Created by: PyQt5 UI code generator 5.15.6
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.from PyQt5 import QtCore, QtGui, QtWidgetsclass Ui_Form(object):def setupUi(self, Form):Form.setObjectName("Form")Form.resize(502, 384)self.frame = QtWidgets.QFrame(Form)self.frame.setGeometry(QtCore.QRect(10, 10, 481, 361))self.frame.setStyleSheet("background-color: rgb(254,254,254);\n"
"border:none;")self.frame.setFrameShape(QtWidgets.QFrame.StyledPanel)self.frame.setFrameShadow(QtWidgets.QFrame.Raised)self.frame.setObjectName("frame")self.label = QtWidgets.QLabel(self.frame)self.label.setGeometry(QtCore.QRect(0, 0, 481, 141))self.label.setStyleSheet("border-image: url(:/img/bg.webp);\n"
"border-radius:0px;")self.label.setText("")self.label.setObjectName("label")self.logo_label = QtWidgets.QLabel(self.frame)self.logo_label.setGeometry(QtCore.QRect(200, 80, 81, 81))self.logo_label.setStyleSheet("border-radius: 40px;\n"
"border:3px solid white;\n"
"border-image: url(:/img/WechatIMG228.png);")self.logo_label.setText("")self.logo_label.setObjectName("logo_label")self.pwd_edit = QtWidgets.QLineEdit(self.frame)self.pwd_edit.setGeometry(QtCore.QRect(120, 230, 251, 31))self.pwd_edit.setFocusPolicy(QtCore.Qt.ClickFocus)self.pwd_edit.setStyleSheet("border-bottom: 2px solid #eee;padding-left:35px;")self.pwd_edit.setEchoMode(QtWidgets.QLineEdit.Password)self.pwd_edit.setObjectName("pwd_edit")self.label_3 = QtWidgets.QLabel(self.frame)self.label_3.setGeometry(QtCore.QRect(126, 184, 20, 20))self.label_3.setStyleSheet("border-image: url(:/img/qq.png);")self.label_3.setText("")self.label_3.setObjectName("label_3")self.label_4 = QtWidgets.QLabel(self.frame)self.label_4.setGeometry(QtCore.QRect(126, 233, 20, 20))self.label_4.setStyleSheet("border-image: url(:/img/lock.png);")self.label_4.setText("")self.label_4.setObjectName("label_4")self.login_btn = QtWidgets.QPushButton(self.frame)self.login_btn.setGeometry(QtCore.QRect(140, 300, 221, 41))self.login_btn.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))self.login_btn.setStyleSheet("background-color: qlineargradient(spread:pad, x1:0.492611, y1:0, x2:0.482759, y2:1, stop:0 rgba(67, 182, 253, 255), stop:1 rgba(0, 147, 238, 255));\n"
"color: rgb(255, 255, 255);\n"
"border-radius:4px;")self.login_btn.setObjectName("login_btn")self.auto_login = QtWidgets.QCheckBox(self.frame)self.auto_login.setGeometry(QtCore.QRect(120, 270, 87, 20))self.auto_login.setStyleSheet("color:rgb(214,214,214);")self.auto_login.setObjectName("auto_login")self.remember_pwd = QtWidgets.QCheckBox(self.frame)self.remember_pwd.setGeometry(QtCore.QRect(217, 270, 87, 20))self.remember_pwd.setStyleSheet("color:rgb(214,214,214);")self.remember_pwd.setObjectName("remember_pwd")self.find_pwd = QtWidgets.QPushButton(self.frame)self.find_pwd.setGeometry(QtCore.QRect(306, 270, 81, 21))self.find_pwd.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))self.find_pwd.setStyleSheet("color:rgb(214,214,214);")self.find_pwd.setObjectName("find_pwd")self.regi_id = QtWidgets.QPushButton(self.frame)self.regi_id.setGeometry(QtCore.QRect(0, 330, 81, 31))self.regi_id.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))self.regi_id.setStyleSheet("color:rgb(214,214,214);")self.regi_id.setObjectName("regi_id")self.close_btn = QtWidgets.QPushButton(self.frame)self.close_btn.setGeometry(QtCore.QRect(450, 0, 31, 31))self.close_btn.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))self.close_btn.setStyleSheet(".QPushButton{\n"
"border-image: url(:/img/close.png);\n"
"background-color: rgba(255, 255, 255, 0);\n"
"margin:7px;\n"
"}\n"
"")self.close_btn.setText("")self.close_btn.setObjectName("close_btn")self.label_5 = QtWidgets.QLabel(self.frame)self.label_5.setGeometry(QtCore.QRect(10, 10, 31, 31))self.label_5.setStyleSheet("border-image: url(:/img/qq_white.png);\n"
"background-color: rgba(255, 255, 255, 0);")self.label_5.setText("")self.label_5.setObjectName("label_5")self.label_6 = QtWidgets.QLabel(self.frame)self.label_6.setGeometry(QtCore.QRect(40, 10, 51, 31))self.label_6.setStyleSheet("font: 20px \".AppleSystemUIFont\";\n"
"color: rgb(255, 255, 255);\n"
"background-color: rgba(255, 255, 255, 0);")self.label_6.setObjectName("label_6")self.id_comboBox = QtWidgets.QComboBox(self.frame)self.id_comboBox.setGeometry(QtCore.QRect(120, 180, 251, 31))self.id_comboBox.setStyleSheet(".QComboBox{\n"
" border-bottom: 2px solid #eee;\n"
" padding-left:35px; \n"
"}\n"
"\n"
"\n"
"QComboBox:editable {\n"
" background: white;\n"
"}\n"
"\n"
"\n"
"/* QComboBox gets the \"on\" state when the popup is open */\n"
"QComboBox:!editable:on, QComboBox::drop-down:editable:on {\n"
"\n"
"}\n"
"\n"
"QComboBox:on { /* shift the text when the popup opens */\n"
" padding-top: 3px;\n"
" padding-left: 4px;\n"
"}\n"
"\n"
"QComboBox::drop-down {\n"
" width: 25px;\n"
" \n"
" border-image: url(:/img/down.png);\n"
"\n"
"}\n"
"\n"
"QComboBox::down-arrow {\n"
" image: url(../res/arrow.ico);\n"
"}\n"
"\n"
"QComboBox::down-arrow:on { /* shift the arrow when popup is open */\n"
" top: 1px;\n"
" left: 1px;\n"
"}\n"
"\n"
"QComboBox QAbstractItemView::item{\n"
" min-height: 70px;\n"
" min-width: 70px;\n"
" outline:0px;\n"
"}\n"
"\n"
"QComboBox::placeholder{\n"
" color:gray;\n"
"}\n"
"\n"
"QComboBox QAbstractItemView::item:hover {\n"
"}\n"
"\n"
"QComboBox QAbstractItemView::item:selected:active{\n"
"}\n"
"\n"
"QComboBox QAbstractItemView::item:selected:!active{\n"
"}")self.id_comboBox.setEditable(True)self.id_comboBox.setCurrentText("")self.id_comboBox.setDuplicatesEnabled(False)self.id_comboBox.setFrame(True)self.id_comboBox.setObjectName("id_comboBox")self.id_comboBox.raise_()self.label.raise_()self.logo_label.raise_()self.pwd_edit.raise_()self.label_3.raise_()self.label_4.raise_()self.login_btn.raise_()self.auto_login.raise_()self.remember_pwd.raise_()self.find_pwd.raise_()self.regi_id.raise_()self.close_btn.raise_()self.label_5.raise_()self.label_6.raise_()self.retranslateUi(Form)QtCore.QMetaObject.connectSlotsByName(Form)def retranslateUi(self, Form):_translate = QtCore.QCoreApplication.translateForm.setWindowTitle(_translate("Form", "Form"))self.pwd_edit.setPlaceholderText(_translate("Form", "密码"))self.login_btn.setText(_translate("Form", "安全登录"))self.auto_login.setText(_translate("Form", "自动登录"))self.remember_pwd.setText(_translate("Form", "记住密码"))self.find_pwd.setText(_translate("Form", "找回密码"))self.regi_id.setText(_translate("Form", "注册账号"))self.label_6.setText(_translate("Form", "QQ"))
import ui.img_rc
用户下拉框组件代码
这里因为官方提供的QComboBox不能实现用户头像显示的效果,所以这里基于QWidget重写了QComboBox组件。
from PyQt5.QtWidgets import QWidget, QLabel, QHBoxLayout, QVBoxLayout, QApplication, QToolButton, QPushButton
from PyQt5.QtGui import QPixmap, QIcon
from PyQt5.QtCore import QEvent, QObject, pyqtSignal
from PyQt5 import QtCore
import ui.img_rcclass ComboBoxItem(QWidget):"""重写comboBoxAuthor: Daydreamer"""itemOpSignal = pyqtSignal(str)def __init__(self, user_id, user_name, user_icon):super().__init__()self.user_name = user_nameself.user_id = user_idself.user_icon = user_iconself. initUi()def initUi(self):lb_user_name = QLabel(self.user_name, self) # 创建一个用户名labellb_user_id = QLabel(self.user_id, self) # 创建一个用户id labellb_user_name.setStyleSheet("""color: black;background-color: rgba(255,255,255,0);""")lb_user_id.setStyleSheet("""color: black;background-color: rgba(255,255,255,0);""")lb_user_icon = QLabel(self) # 创建一个用户头像labellb_user_icon.setPixmap(QPixmap(self.user_icon))lb_user_icon.setMaximumSize(QtCore.QSize(60, 60))lb_user_icon.setMinimumSize(QtCore.QSize(60, 60))lb_user_icon.setScaledContents(True)self.bt_close = QPushButton(self) # 创建一个关闭按钮self.bt_close.setMaximumSize(QtCore.QSize(20, 20))self.bt_close.setMinimumSize(QtCore.QSize(20, 20))self.bt_close.setStyleSheet("""QPushButton {border-radius: 10px;background-color: rgba(255, 255, 255, 0);border-image: url(:/img/close_2.png);}QPushButton:hover {background-color: #fe5439;}""")# 创建一个垂直布局vlayout = QVBoxLayout()# 将用户名label和用户id label添加到垂直布局vlayout.addWidget(lb_user_name)vlayout.addWidget(lb_user_id)# 创建一个水平布局hlayout = QHBoxLayout()# 将用户头像label和垂直布局和关闭按钮添加到水平布局hlayout.addWidget(lb_user_icon)hlayout.addLayout(vlayout)hlayout.addStretch(1)hlayout.addWidget(self.bt_close)hlayout.setContentsMargins(5, 5, 5, 5)hlayout.setSpacing(5)# 设置布局self.setLayout(hlayout)# 在按钮上安装事件过滤器self.bt_close.installEventFilter(self)# 在窗口上安装事件过滤器self.installEventFilter(self)def eventFilter(self, object, event):"""重写事件过滤器方法:param obj: 事件发送对象:param event: 事件对象:return: bool"""if object is self:if event.type() == QEvent.Enter:self.setStyleSheet("QWidget{color:white}")elif event.type() == QEvent.Leave:self.setStyleSheet("QWidget{color:black}")elif object is self.bt_close:if event.type() == QEvent.MouseButtonPress:self.itemOpSignal.emit(self.user_id)return QWidget.eventFilter(self, object, event)
登录逻辑代码
这里的用户登录相关的SQL操作我是基于ORM的,大家可以自己实现。代码对用户体验进行了一些细小的优化,这里不进行介绍。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
@Project :socket_pyqt
@File :login.py
@Author :SCC
@Date :2023/5/30 13:54
This program is good and not any bug. If you find Bug, it must be your problem.
"""
import sys
import timefrom PyQt5 import QtCore
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QColor
from PyQt5.QtWidgets import QWidget, QGraphicsDropShadowEffect, QMessageBox, QListWidget, QListWidgetItem, QApplication
from Assets.ComboBoxItem import ComboBoxItem
import lib.sql_command as sql_command
import db.mysql_orm.crud as mysql_crud
import db.sqlite_orm.crud as sqlite_crud
from threading import Thread
from page.main_test import QQMainPage
from page.registered import registered_ui
from ui.login_ui import Ui_Formclass login_ui(QWidget, Ui_Form):# login_window = QtCore.pyqtSignal() # 跳转信号flag = 0def __init__(self):super(login_ui, self).__init__()self.history_data = [] # 用户历史数据self.info_id = []self.setupUi(self)self.update_timer = QtCore.QTimer()self.update_timer.start(1000)self.init_ui() # 初始化Ui函数self.init_slots()self.init_data() # 初始化部分数据def init_data(self):"""初始化用户记录Author: SCCLast_Author: Daydreamer:return: 无"""self.history_data = sqlite_crud.get_info() # 获取历史数据if self.history_data is False: # 如果得到的用户记录为空则直接返回returnelse:# 遍历用户数据,将用户数据添加到comboBox中for info in self.history_data:# 创建一个ComboBoxItem对象,并设置好用户信息item = ComboBoxItem(info.user_id, info.user_name, 'ui/WechatIMG228.png')listwitem = QListWidgetItem(self.listw)self.listw.setItemWidget(listwitem, item)self.info_id.append(info.user_id)item.itemOpSignal.connect(self.itemOp) # 连接删除用户记录槽函数,将comboBox的索引传到槽函数self.show_data(0) # 打开QQ界面默认显示comboBox中的第一个用户记录self.id_comboBox.activated[int].connect(self.show_data) # 连接显示用户密码槽函数# if self.auto_login.isChecked():# print("自动登录")# self.auto_login_fun()def comboBoxTextChanged(self, text):"""Author: Daydreamer:param text::return: 无"""if text == "":self.pwd_edit.clear()def itemOp(self, qq):"""删除comboBox和sqlite中的用户Author: Daydreamer传入参数: 需要删除的QQ号"""sqlite_crud.remove_history(qq) # 调用crud中的方法删除sqlite中的用户记录index_qq = self.info_id.index(qq) # 得到需要删除qq号所在comboBox中的索引位置self.listw.takeItem(index_qq) # 删除comboBox中的用户记录if self.id_comboBox.currentText() == "": # 如果comboBox中的用户记录被删除,则密码行中的数据同样清空self.pwd_edit.clear()def auto_login_fun(self):"""自动登录功能Author: Daydreamer:return: 无"""if self.pwd_edit.text() == '': # 判断是有密码returnelse: # 有密码就进行自动登录self.login() # 调用登录函数def show_data(self, int):"""显示用户账号密码(下拉框选择显示)Author: Daydreamer:return: 无"""self.id_comboBox.setEditText(self.history_data[int].user_id)self.pwd_edit.setText(self.history_data[int].user_pwd)self.pwd_edit.setFocus() # 将光标锁定在密码输入框if self.pwd_edit.text() != "": # 密码不为空的话就是默认勾选记住密码self.remember_pwd.setChecked(True) # 设置记住密码勾选if self.history_data[int].is_auto_login == '1': # 判断是否自动登录self.auto_login.setChecked(True) # 设置自动登录勾选else:self.remember_pwd.setChecked(False) # 取消记住密码勾选self.auto_login.setChecked(False) # 如果没有密则取消自动登录def init_ui(self):# Author: SCC# 初始化UI的函数self.setAttribute(Qt.WA_TranslucentBackground) # 窗体背景透明self.setWindowFlags(Qt.WindowStaysOnTopHint | Qt.FramelessWindowHint | Qt.Tool) # 窗口置顶,无边框,在任务栏不显示图标shadow = QGraphicsDropShadowEffect() # 设定一个阴影,半径为10,颜色为#444444,定位为0,0shadow.setBlurRadius(10)shadow.setColor(QColor("#444444"))shadow.setOffset(0, 0)self.frame.setGraphicsEffect(shadow) # 为frame设定阴影效果self.listw = QListWidget() # 实例化一个列表框self.id_comboBox.setModel(self.listw.model())self.id_comboBox.setView(self.listw)self.id_comboBox.setCurrentIndex(-1)self.id_comboBox.lineEdit().setPlaceholderText("账号/邮箱/电话号")self.id_comboBox.currentTextChanged.connect(self.comboBoxTextChanged)def init_slots(self):# Author: SCC# 初始化信号和槽的函数self.update_timer.timeout.connect(self.close_page_test) # 定时器槽函数,用于判断是否自动登录成功,自动登录成功则关闭登录界面self.close_btn.clicked.connect(lambda: self.closeEvent(self))self.login_btn.clicked.connect(self.login) # 连接登录槽函数self.pwd_edit.returnPressed.connect(self.Enter_to_login) # 连接回车登录槽函数(用户输入完密码以后支持回车登录))self.regi_id.clicked.connect(self.register_id) # 连接注册账号槽函数def close_page_test(self):"""# Auther: Daydreamer# 自动登录成功后隐藏QQ登录界面:return:"""if login_ui.flag == 0:if self.auto_login.isChecked():print("自动登录")# self.auto_login_fun()self.update_timer.start(1)if login_ui.flag == 1:# print('hide')# time.sleep(0)self.update_timer.stop()self.hide()def register_id(self):"""#Author: Daydreamer#打开注册账号界面关闭登录界面:return: 无"""self.register_page = registered_ui(self) # 打开注册界面# selfself.login_window.emit()self.register_page.show()self.hide() # 关闭登录界面def Enter_to_login(self):"""回车登录功能Author: SCC:return: 无"""if self.pwd_edit.text() == '':print("请输入密码!!!")QMessageBox.about(self, "Error", "请输入密码在进行登录!!!")returnelse:self.login() # 调用登录函数def login(self):"""登陆的函数Author: SCCLast_Author: Daydreamer:return: 无"""id = self.id_comboBox.currentText() # 获取账户输入账号pwd = self.pwd_edit.text() # 获取密码输入ret = sql_command.pwd_eval(id, pwd) # 账号密码验证函数,返回一个布尔值if ret:print("登陆成功")info = mysql_crud.get_user_info(id)# 进行登陆历史记录存储,要根据是否勾选记住密码来进行数据库的存储if self.remember_pwd.isChecked(): # 判断是否记住密码if self.auto_login.isChecked(): # 判断是否自动登录print("记住密码和自动登录")sqlite_crud.add_history_info(str(id), info["name"], info["logo"], str(1), str(pwd)) # 记住密码并且自动登录login_ui.flag = 1self.qqmain_page = QQMainPage(id, info["logo"], info["name"])self.qqmain_page.center() # 调用center方法将窗口显示在屏幕中心self.qqmain_page.show()self.hide() # 隐藏登录界面else:print("记住密码但不自动登录")sqlite_crud.add_history_info(str(id), info["name"], info["logo"], str(0),str(pwd)) # 记住密码但是不自动登录login_ui.flag = 1# TODO:跳转到用户的主界面self.qqmain_page = QQMainPage(id, info["logo"], info["name"])self.qqmain_page.center() # 调用center方法将窗口显示在屏幕中心self.qqmain_page.show()self.hide() # 隐藏登录界面else:print("没有记住密码")sqlite_crud.add_history_info(str(id), info["name"], info["logo"], str(0)) # 没有记住密码就不能login_ui.flag = 1# TODO:跳转到用户的主界面self.qqmain_page = QQMainPage(id, info["logo"], info["name"])self.qqmain_page.center() # 调用center方法将窗口显示在屏幕中心self.qqmain_page.show()self.hide() # 隐藏登录界面else:QMessageBox.about(self, "Error", "账号密码错误,请重新输入")login_ui.flag = 1"""下方为鼠标左键拖动重写事件"""def mousePressEvent(self, event): # 鼠标左键按下时获取鼠标坐标,按下右键取消if event.button() == Qt.LeftButton:self.m_flag = Trueself.m_Position = event.globalPos() - self.pos()event.accept()elif event.button() == Qt.RightButton:self.m_flag = Falsedef mouseMoveEvent(self, QMouseEvent): # 鼠标在按下左键的情况下移动时,根据坐标移动界面try:if Qt.LeftButton and self.m_flag:self.move(QMouseEvent.globalPos() - self.m_Position)QMouseEvent.accept()except BaseException as e:passdef mouseReleaseEvent(self, QMouseEvent): # 鼠标按键释放时,取消移动self.m_flag = Falsedef closeEvent(self, QCloseEvent):# Author: SCC# 界面关闭函数,并手动退出进程self.close() # 关闭界面sys.exit()
最终效果
项目源码在这里,可以的话就给个小星星吧!QQ源码
特别鸣谢:LoadingCreate ҈҉҈҉҈҉҈ 对我的帮助!
相关文章:
基于PyQt5实现仿QQ-第二章-用户登录
基于PyQt5实现仿QQ-第二章-用户登录 Author: Daydreamer 项目简介 本项目基于PyQt5仿照目前流行的即时通信软件QQ,实现了新用户注册、用户登录、自动登录、记住多用户账号、用户搜索、添加好友、好友间聊天(消息持久化、同步化)等功能。 …...
[OS_8] 终端和 UNIX Shell | 会话和进程组 | sigaction | dash
我们已经知道如何用 “文件描述符” 相关的系统调用访问操作系统中的对象:open, read, write, lseek, close。操作系统也提供了 mount, pipe, mkfifo 这些系统调用能 “创建” 操作系统中的对象。 当然,我们也知道操作系统中的对象远不止于此࿰…...
IP查询专业版:支持IPv4/IPv6自动识别并切换解析的API接口使用指南
以下是根据您提供的网页内容编辑的符合CSDN内容发布要求的Markdown格式文本: 一、API概述 在开发过程中,我们常常需要对IP地址进行查询,以获取其详细信息,如地理位置、运营商等。万维易源的“IP查询专业版”API接口能够提供丰富…...
ESG跨境电商如何为国内的跨境电商企业打开国外的市场
现在不管是国内还是国外,做电商的企业都非常的多,那么既然有这么多大电商公司,就要有为这些电商公司提供服务的公司,这就是ESG,它是专门为跨境电商服务的公司,那么这家公司的主要业务是什么呢?它…...
建筑节能成发展焦点,楼宇自控应用范围持续扩大
在全球能源危机日益严峻、环保意识不断增强的大环境下,建筑节能已成为建筑行业发展的核心议题。从大型商业综合体到普通住宅,从公共建筑到工业厂房,节能需求贯穿建筑全生命周期。而楼宇自控系统凭借其对建筑设备的智能化管理和精准调控能力&a…...
中国矿业大学iGMAS分析中心介绍
一、关于GNSS和iGMAS 在浩瀚的太空中,全球卫星导航系统(GNSS)构建起精准定位的时空基准。IGMAS——国际GNSS监测评估系统,是由中国倡导并主导建设的全球GNSS监测网络,旨在提供高精度、高可靠的导航、定位与授时服务。 …...
python如何取消word中的缩进
在python-docx中,取消缩进可以通过将相应的缩进属性设置为None或0来实现。以下是取消不同类型缩进的方法: 取消左缩进 from docx import Documentdoc Document(existing_document.docx)for paragraph in doc.paragraphs:# 取消左缩进paragraph.paragr…...
Lesar: 面向 Lustre/Scade 语言的形式化模型检测工具
在《同步反应式系统》的第一课中,介绍了同步数据流语言 Lustre 生态中的形式化模型检查器 Lesar 的用法。Lesar 可对 lustre v4 语言以及 Scade 语言中部分数据流核心特性进行模型检查。 Lesar 介绍 Lesar 是 Verimag 研发维护的形式化方法模型检查工具。该工具的理…...
YOLOv12 改进有效系列目录 - 包含卷积、主干、检测头、注意力机制、Neck上百种创新机制 - 针对多尺度、小目标、遮挡、复杂环境、噪声等问题!
🔥 在 YOLO 系列一路狂飙之后,YOLOv12 带来了令人耳目一新的范式转变——它不再以 CNN 为绝对核心,而是首次 围绕注意力机制构建 YOLO 框架,在保证实时性的前提下,将检测精度再次推向新高度! 为了进一步探…...
STM32 I2C总线通信协议
引言 在嵌入式系统开发领域,I2C(Inter-Integrated Circuit)总线作为经典的双线制串行通信协议,凭借其简洁的物理层设计和灵活的通信机制,在传感器互联、存储设备控制、显示模块驱动等场景中占据重要地位。本文将深入剖…...
多物理场耦合低温等离子体装置求解器PASSKEy2
文章目录 PASSKEy2简介PASSKEY2计算流程PASSKEy2 中求解的物理方程电路模型等离子体模型燃烧模型 PASSKEy2的使用 PASSKEy2简介 PASSKEy2 是在 PASSKEy1 的基础上重新编写的等离子体数值模拟程序。 相较于 PASSKEy1, PASSKEy2 在具备解决低温等离子体模拟问题的能力…...
【Harmony_Bug】forEach + asyncawait 的异步陷阱
一、问题描述 今天在做一个RDB的小项目时,遇到一个问题,因为没报错其实也是不算是BUG,以下描述时我就直接说关键点,其他代码忽略。 我的数据模型初始化有六条数据如图 在持久化层,通过initUserData这个方法执行插入。…...
智慧医院建设的三大关键领域
智慧医院建设是医疗行业数字化转型的核心载体,其本质是通过新一代信息技术重构医疗服务模式、优化管理流程、提升患者体验。在当前医疗资源供需矛盾突出的背景下,智慧医院建设已从单纯的设备智能化向系统性变革演进,主要集中在以下三大关键领…...
雷电模拟器怎么更改IP地址
游戏搬砖会使用雷电模拟器多开窗口,若模拟器窗口开多了,IP地址是一样的就怕有限制,很容易被游戏后台检测到。在雷电模拟器中更改IP地址可以通过以下方法实现: 方法一:通过模拟器内设置代理 1. 打开雷电模拟器 启动雷…...
软件编程命名规范
编程命名规范是保证代码可读性、可维护性和团队协作效率的重要基础。以下是涵盖主流编程语言的通用命名规范,结合行业最佳实践和常见规范(如Google、Microsoft、Airbnb等风格指南): 一、通用命名原则 清晰优先:名称应…...
#什么是爬虫?——从技术原理到现实应用的全面解析 VI
什么是爬虫?——从技术原理到现实应用的全面解析 V 二十六、异构数据采集技术突破 26.1 PDF文本与表格提取 import pdfplumber import pandas as pddef extract_pdf_data(pdf_path):"""从PDF中提取文本和表格数据:param pdf_path: PDF文件路径:return: 包含…...
芯岭技术XL32F003单片机 32位Cortex M0+ MCU简单介绍 性能优异
XL32F003单片机是深圳市芯岭技术有限公司的一款基于 32 位 ARM Cortex-M0 内核的高性能微控制器,提供SOP8/SOP14/SOP16/TSSOP20/SSOP24/QFN20/QFN32多种封装可选,可满足不同设计需求。XL32F003可用于工业控制、手持设备、PC 外设、传感器节点等应用场景&…...
使用浏览器的Clipboard API实现前端复制copy功能
在前端开发中,复制文本到剪贴板的功能通常使用浏览器的 Clipboard API 实现。比如 navigator.clipboard.writeText 方法。以下是一个简单的案例,展示如何使用 Clipboard API 实现复制文本的功能。 基本用法 首先,你需要创建一个按钮&#x…...
Struts2框架学习
文章目录 基础实战配置文件NameSpaces 基础 实战 配置文件 文件1: <?xml version"1.0" encoding"UTF-8"?> // 声明这是一个 XML 文件,且使用 UTF - 8 编码 <!DOCTYPE struts PUBLIC"-//Apache Software Foundat…...
React 实现爱心花园动画
主页: import React, { useEffect, useRef, useState } from react; import /assets/css/Love.less; import { Garden } from /utils/GardenClasses;// 组件属性接口 interface LoveAnimationProps {startDate?: Date; // 可选的开始日期messages?: { // 可…...
CAPL编程_03
1_文件操作的相关函数: 读文本文件内容 读取文本文件操作的三部曲 1)打开文件 —— openFileRead ( ) 2)逐行读取 —— fileGetString ( ) 、fileGetStringSZ ( ) 3)关闭文件 —— fileClose ( ) char content[100];…...
网络准入控制系统:2025年网络安全的坚固防线
在当今数字化时代,网络安全已成为至关重要的议题。阳途网络准入控制系统作为保障网络安全的关键机制,发挥着不可替代的作用。 阳途网络准入控制系统核心目的在于确保只有合法、合规的设备与用户能够接入网络。从本质上讲,它通过一系列技术手段…...
【音视频】⾳频处理基本概念及⾳频重采样
一、重采样 1.1 什么是重采样 所谓的重采样,就是改变⾳频的采样率、sample format、声道数等参数,使之按照我们期望的参数输出。 1.2 为什么要重采样 为什么要重采样? 当然是原有的⾳频参数不满⾜我们的需求,⽐如在FFmpeg解码⾳频的时候…...
自然语言处理将如何颠覆未来教育?个性化学习新纪元
教育领域正经历着自印刷术发明以来最深刻的变革。自然语言处理(NLP)技术突破传统教育框架的桎梏,正在重塑人类知识传递的基本范式。这场变革的实质不在于教学工具的数字化升级,而在于重新定义了"教"与"学"的本…...
4月25日星期五今日早报简报微语报早读
4月25日星期五,农历三月廿八,早报#微语早读。 1、祝贺!神舟二十号载人飞船发射取得圆满成功; 2、文旅部:今年一季度国内出游人次17.94亿,同比增长26.4%; 3、2025五一档新片预售票房破1000万&…...
秒级到毫秒:BFD的速度革命
一、BFD技术概述 双向转发检测(BFD)是一种轻量级的网络协议,专门用于快速检测、监控网络链路或IP路由的连通性状态。作为网络领域的"心跳检测器",BFD通过毫秒级(默认1000ms)的快速探测机…...
systemctl 命令详解与常见问题解决
在 Linux 系统中,service 命令和 chkconfig 命令一直用于管理服务,但随着 systemd 的引入,systemctl 命令逐渐成为主流。systemctl 命令不仅功能强大,而且使用简单。本文将详细介绍 systemctl 命令的作用以及常见问题的解决方法。…...
5.6 Microsoft Semantic Kernel:专注于将LLM集成到现有应用中的框架
5.6.1 Semantic Kernel概述 Microsoft Semantic Kernel(以下简称SK)是一个开源的软件开发工具包(SDK),旨在帮助开发者将大型语言模型(LLM)无缝集成到现有的应用程序中。它支持C#、Python和Java…...
vite+vue构建的网站项目localhost:5173打不开
原因:关掉了cmd命令提示符,那个端口就没有被配置上,打开就是这样的。 解决方法:重新在工作目录下打开cmd,输入npm run dev重新启动项目。 重新出现这样的界面说明已经成功启动项目,再次在浏览器中刷新并输入…...
电脑屏幕录制软件Captura源码编译(Win10,VS2022)
屏幕录像的意义: 教育教学方面 制作教学资源:教师可以通过录制屏幕来制作教学视频,演示软件操作、讲解复杂的知识点等。学生可以随时观看这些视频,便于复习和巩固知识,尤其对于一些抽象的概念或难以在课堂上一次性掌握…...
【版本控制】SVN + TortoiseSVN版本管理实用教程(附安装+开发常用操作)
摘要: 本文将带你从零开始掌握 SVN 版本控制系统,结合 TortoiseSVN 图形客户端工具,深入学习包括安装、检出、提交、更新、回滚、冲突解决等常用开发操作,快速上手团队协作! 🧩 什么是 SVN? SV…...
常见网络安全攻击类型深度剖析(二):SQL注入攻击——原理、漏洞利用演示与代码加固方法
常见网络安全攻击类型深度剖析(二):SQL注入攻击——原理、漏洞利用演示与代码加固方法 在Web应用安全领域,SQL注入(SQL Injection)是历史最悠久、危害最广泛的攻击类型之一。据OWASP(开放式Web应用安全项目)统计,SQL注入连续多年稳居“OWASP Top 10”漏洞榜单前列,每…...
DeepSeek智能时空数据分析(三):专业级地理数据可视化赏析-《杭州市国土空间总体规划(2021-2035年)》
序言:时空数据分析很有用,但是GIS/时空数据库技术门槛太高 时空数据分析在优化业务运营中至关重要,然而,三大挑战仍制约其发展:技术门槛高,需融合GIS理论、SQL开发与时空数据库等多领域知识;空…...
day49—双指针+贪心—验证回文串(LeetCode-680)
题目描述 给你一个字符串 s,最多 可以从中删除一个字符。 请你判断 s 是否能成为回文字符串:如果能,返回 true ;否则,返回 false 。 示例 1: 输入:s "aba" 输出:true…...
AI电视里的达摩
2025年,所有电视都搭载了AI功能,所有电视厂商都在宣传AI能力。但问题是,消费者依旧没有对AI电视做出什么积极的回应。“AI电视是鸡肋”“AI只是电视的又一轮泡沫”等观点层出不穷。 为什么明明AI技术能够解决电视的很多问题,但AI电…...
算力网络(CFN)在跨校联合科研中的应用:安全性挑战与联邦调度实践
引言:科研协作的算力困境 上海交通大学与麻省理工学院联合开展的高能物理模拟实验,因算力资源分配不均导致部分节点连续72小时处于空转状态。这个典型案例揭示了当前跨机构科研协作的痛点:算力资源无法实现安全可信的细粒度共享。算力网…...
面向对象编程核心:封装、继承、多态与 static 关键字深度解析
面向对象编程核心:封装、继承、多态与 static 关键字深度解析 一、封装:数据安全与接口规范 1. 封装的本质与作用 核心定义:将数据(属性)与操作数据的方法(行为)绑定在类中,隐藏内…...
c++进阶——类与继承
文章目录 继承继承的基本概念继承的基本定义继承方式继承的一些注意事项 继承类模板 基类和派生类之间的转换继承中的作用域派生类的默认成员函数默认构造函数拷贝构造赋值重载析构函数默认成员函数总结 不能被继承的类继承和友元继承与静态成员多继承及其菱形继承问题继承模型…...
【CODEMATE】进制转换(transform) 粤港澳青少年信息学创新大赛 C/C++/Python 解题思路
目录 问题描述做题思路,解决过程思路:踩过的坑:核心代码C 语言 / C 切片:C 语言 / C 判断 ‘A’ 数量:Python 切片:Python 判断 ‘A’ 数量: 完整代码C 语言 完整代码C 完整代码Python 完整代码…...
window和ubuntu自签证书
window下 以管理员身份 运行 Windows PowerShell # CN192.168.0.100 (换成自己的IP或者域名) # O(组织) OU(组织单位) # Cert:\LocalMachine\My:证书存储位置 # test_10:自定义证书名称 .AddYears(10): 证书过期时间 10 年 $cert New-SelfSi…...
ES历史版本下载
下载地址 Past Releases of Elastic Stack Software | Elastic 安装步骤参考 windows 安装 Elasticsearch_windows安装elasticsearch-CSDN博客...
技术面试一面标准流程
0. 自我介绍 ...... 1. 拷打项目 项目干了啥? 难点是啥? 问项目中用到的东西? 扩展? ...... 2. 基础知识 数据结构、C基础、设计模式 数据结构: 堆? unordered_map 和 布隆过滤器 都是用于查找…...
第14篇:Linux设备驱动程序入门<一>
Q:如何简单的理解DE1-SoC-UP Linux系统的设备驱动程序? A:设备驱动程序(Device Driver),简称驱动程序(Driver)。DE1-SoC-UP Linux系统中的设备驱动程序允许系统软件与DE1-SoC开发板…...
软件设计模式与体系结构:基于Java实现管道-过滤器架构
软件设计模式与体系结构:基于Java实现管道-过滤器架构 前言 在软件架构中,数据流风格是一种常见的架构模式,特别适用于需要对数据进行一系列处理的场景。管道-过滤器(Pipe and Filter)*架构是数据流风格的典型代表&a…...
Node.js 包管理工具介绍
Node.js 包管理工具介绍 Node.js 是一个基于 Chrome V8 JavaScript 引擎的服务器端运行环境,它允许开发者使用 JavaScript 进行后端开发。为了方便管理和维护项目中使用的第三方库和模块,Node.js 提供了多种包管理工具。本文将详细介绍几种常用的 Node.…...
Node.js 应用场景
Node.js 应用场景 引言 Node.js 是一个基于 Chrome V8 JavaScript 引擎的开源、跨平台 JavaScript 运行环境。它主要用于服务器端开发,通过非阻塞 I/O 模型实现了高并发处理能力。本文将详细介绍 Node.js 的应用场景,帮助你了解其在实际项目中的应用。…...
C/C++线程详解
一、C语言线程创建(POSIX线程) 1. 基本创建方法 POSIX线程(pthread)是C语言中创建线程的标准API: #include <pthread.h> #include <stdio.h>void* thread_func(void* arg) {printf("Thread runnin…...
动态ip与静态ip的概念、区别、应用场景
动态ip与静态ip的区别 前言 一、IP地址的概念和作用 1.1、IP地址的定义 1.2、IP地址的作用 二、动态IP和静态IP的区别 2.1、动态IP和静态IP的定义 2.2、动态IP和静态IP的特点 2.3、动态IP和静态IP的优缺点比较 三、动态IP和静态IP的应用场景 3.1. 动态IP的应用场景 3.2. 静态IP…...
P12167 [蓝桥杯 2025 省 C/Python A] 倒水
P12167 [蓝桥杯 2025 省 C/Python A] 倒水 题目描述 小蓝有 n n n 个装了水的瓶子,从左到右摆放,第 i i i 个瓶子里装有 a i a_i ai 单位的水。为了美观,小蓝将水循环染成了 k k k 种颜色,也就是说,第 i i i …...
Appium自动化开发环境搭建
自动化 文章目录 自动化前言 前言 Appium是一款开源工具,用于自动化iOS、Android和Windows桌面平台上的本地、移动web和混合应用程序。原生应用是指那些使用iOS、Android或Windows sdk编写的应用。移动网页应用是通过移动浏览器访问的网页应用(appum支持iOS和Chrom…...