找到
90
篇与
寒烟似雪
相关的结果
- 第 3 页
-
PyQt5 对话框控件:QDialog 与标准对话框(附登录实战代码) 第8篇:PyQt5对话框控件:QDialog与标准对话框(完整代码) 哈喽~ 欢迎来到PyQt5系列的第8篇!上一章我们掌握了QTextEdit(富文本)和QTableWidget(表格)的核心用法,今天聚焦对话框控件——对话框是PyQt5界面交互的“重要桥梁”,比如提示信息、选择文件、用户登录验证等场景都离不开它。我们会详细讲解两类对话框:标准对话框(系统预制,如消息框、文件选择框)和自定义对话框(基于QDialog开发专属交互窗口),全程搭配完整可运行代码,新手也能轻松掌握! mjzpc9v3.png图片 一、先明确:对话框的核心概念 在学习具体用法前,先理清对话框的两个核心属性,避免用错场景: 1. 模态(Modal)vs 非模态(Non-Modal) 模态对话框:弹出后阻塞主窗口操作,必须先处理对话框才能回到主窗口(如登录弹窗、确认删除提示),是最常用的类型; 非模态对话框:弹出后不阻塞主窗口,可同时操作主窗口和对话框(如悬浮的工具面板)。 2. 标准对话框 vs 自定义对话框 标准对话框:PyQt5预制的通用对话框(QMessageBox、QFileDialog、QColorDialog等),无需自定义界面,直接调用即可,开发效率高; 自定义对话框:基于QDialog类开发的专属对话框(如登录窗口、高级设置窗口),可自由设计界面和交互逻辑。 二、标准对话框详解:直接调用的通用交互窗口 PyQt5提供了一系列开箱即用的标准对话框,覆盖80%的通用交互场景,重点掌握以下5类: 1. QMessageBox:消息提示对话框(最常用) 用于显示提示、警告、错误、确认等信息,支持自定义按钮和交互逻辑。 效果图 信息提示框 - mjzoqu7y.png图片 警告提示框 - mjzos4d4.png图片 错误提示框 - mjzosqpr.png图片 确认提示框 - mjzot5q2.png图片 自定义提示框 - mjzp1z0h.png图片 完整代码:QMessageBox常用类型 import sys from PyQt5.QtWidgets import ( QApplication, QWidget, QVBoxLayout, QPushButton, QMessageBox ) class MessageBoxDemo(QWidget): def __init__(self): super().__init__() self.init_ui() def init_ui(self): self.setWindowTitle("QMessageBox标准消息框演示") self.resize(400, 300) # 布局与按钮 layout = QVBoxLayout() layout.setSpacing(15) layout.setContentsMargins(50, 50, 50, 50) # 不同类型的消息框按钮 info_btn = QPushButton("信息提示框") warn_btn = QPushButton("警告提示框") error_btn = QPushButton("错误提示框") question_btn = QPushButton("确认对话框") custom_btn = QPushButton("自定义按钮对话框") # 绑定信号 info_btn.clicked.connect(self.show_info) warn_btn.clicked.connect(self.show_warn) error_btn.clicked.connect(self.show_error) question_btn.clicked.connect(self.show_question) custom_btn.clicked.connect(self.show_custom) # 添加到布局 for btn in [info_btn, warn_btn, error_btn, question_btn, custom_btn]: layout.addWidget(btn) self.setLayout(layout) # 1. 信息提示框(仅提示,无返回值) def show_info(self): QMessageBox.information( self, # 父窗口 "信息", # 标题 "操作成功!这是一个信息提示框。", # 内容 QMessageBox.Ok # 按钮(默认Ok) ) # 2. 警告提示框 def show_warn(self): QMessageBox.warning( self, "警告", "数据未保存,关闭窗口将丢失内容!", QMessageBox.Ok | QMessageBox.Cancel # 多个按钮 ) # 3. 错误提示框 def show_error(self): QMessageBox.critical( self, "错误", "文件读取失败,请检查文件路径是否正确!", QMessageBox.Retry | QMessageBox.Abort ) # 4. 确认对话框(带返回值,判断用户选择) def show_question(self): reply = QMessageBox.question( self, "确认", "确定要删除这条数据吗?", QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel, # 按钮组合 QMessageBox.No # 默认选中No按钮 ) # 判断用户点击的按钮 if reply == QMessageBox.Yes: print("用户选择:删除") elif reply == QMessageBox.No: print("用户选择:不删除") else: print("用户选择:取消") # 5. 自定义按钮对话框 def show_custom(self): # 创建自定义消息框 msg_box = QMessageBox(self) msg_box.setWindowTitle("自定义对话框") msg_box.setText("请选择操作:") # 设置自定义按钮 btn1 = msg_box.addButton("导出", QMessageBox.ActionRole) btn2 = msg_box.addButton("导入", QMessageBox.ActionRole) btn3 = msg_box.addButton("取消", QMessageBox.CancelRole) # 显示对话框并获取返回值 msg_box.exec_() # 判断用户点击的按钮 if msg_box.clickedButton() == btn1: print("用户选择:导出") elif msg_box.clickedButton() == btn2: print("用户选择:导入") else: print("用户选择:取消") if __name__ == "__main__": app = QApplication(sys.argv) window = MessageBoxDemo() window.show() sys.exit(app.exec_())QMessageBox核心要点 常用类型:information()(信息)、warning()(警告)、critical()(错误)、question()(确认); 按钮组合:用|拼接(如QMessageBox.Yes | QMessageBox.No); 返回值判断:通过返回的枚举值(如QMessageBox.Yes)判断用户操作; 自定义按钮:创建QMessageBox实例,用addButton()添加自定义按钮。 2. 其他标准对话框:文件/颜色/字体选择 除了消息框,PyQt5还提供了文件、颜色、字体选择的标准对话框,用法统一且简单: 完整代码:文件/颜色/字体对话框 效果如图 mjzp4re8.png图片 import sys from PyQt5.QtWidgets import ( QApplication, QWidget, QVBoxLayout, QPushButton, QFileDialog, QColorDialog, QFontDialog, QLabel ) from PyQt5.QtGui import QColor, QFont from PyQt5.QtCore import Qt class StandardDialogsDemo(QWidget): def __init__(self): super().__init__() self.init_ui() def init_ui(self): self.setWindowTitle("标准对话框(文件/颜色/字体)演示") self.resize(500, 300) # 布局 layout = QVBoxLayout() layout.setSpacing(15) layout.setContentsMargins(50, 50, 50, 50) # 按钮 file_btn = QPushButton("选择文件") color_btn = QPushButton("选择颜色") font_btn = QPushButton("选择字体") # 结果显示标签 self.result_label = QLabel("选择结果将显示在这里...") self.result_label.setAlignment(Qt.AlignCenter) # 绑定信号 file_btn.clicked.connect(self.choose_file) color_btn.clicked.connect(self.choose_color) font_btn.clicked.connect(self.choose_font) # 添加到布局 layout.addWidget(file_btn) layout.addWidget(color_btn) layout.addWidget(font_btn) layout.addWidget(self.result_label) self.setLayout(layout) # 1. 文件选择对话框(打开文件) def choose_file(self): # getOpenFileName:选择单个文件 # getOpenFileNames:选择多个文件 # getSaveFileName:保存文件 file_path, _ = QFileDialog.getOpenFileName( self, # 父窗口 "选择文件", # 标题 "", # 默认路径(当前目录) "Text Files (*.txt);;Image Files (*.png *.jpg);;All Files (*.*)" # 文件筛选器 ) if file_path: self.result_label.setText(f"选中文件:{file_path}") else: self.result_label.setText("未选择任何文件") # 2. 颜色选择对话框 def choose_color(self): # 获取当前标签颜色,作为默认颜色 current_color = self.result_label.textColor() # 弹出颜色选择框 color = QColorDialog.getColor( current_color, # 默认颜色 self, "选择颜色" ) if color.isValid(): # 用户选择了有效颜色 self.result_label.setText(f"选中颜色:{color.name()}") self.result_label.setStyleSheet(f"color: {color.name()}; font-size: 16px;") # 3. 字体选择对话框 def choose_font(self): # 获取当前标签字体,作为默认字体 current_font = self.result_label.font() # 弹出字体选择框 font, ok = QFontDialog.getFont( current_font, # 默认字体 self, "选择字体" ) if ok: # 用户确认选择 self.result_label.setText(f"选中字体:{font.family()},大小:{font.pointSize()}") self.result_label.setFont(font) if __name__ == "__main__": app = QApplication(sys.argv) window = StandardDialogsDemo() window.show() sys.exit(app.exec_())核心方法总结 对话框类型核心方法关键参数/返回值QFileDialoggetOpenFileName()返回(选中路径, 筛选器),支持多文件选择(getOpenFileNames)QColorDialoggetColor()返回QColor对象,isValid()判断是否选择有效颜色QFontDialoggetFont()返回(字体对象, 是否确认),ok为True时表示用户确认选择三、自定义对话框:基于QDialog开发专属交互窗口 当标准对话框无法满足需求时(如登录验证、高级参数设置),需要基于QDialog开发自定义对话框,核心是“设计界面+处理返回值+设置模态”。 1. 自定义对话框基础:登录窗口案例 实现一个带“用户名/密码输入+登录/取消按钮”的登录对话框,支持模态显示和返回值判断: 步骤1:自定义登录对话框类 # login_dialog.py(可单独文件,也可写在主文件) from PyQt5.QtWidgets import ( QDialog, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit, QPushButton, QMessageBox ) from PyQt5.QtCore import Qt class LoginDialog(QDialog): def __init__(self, parent=None): super().__init__(parent) self.init_ui() # 设置模态(默认模态,也可显式设置) self.setModal(True) def init_ui(self): # 对话框基础设置 self.setWindowTitle("用户登录") self.setFixedSize(350, 200) # 固定大小,避免缩放 # 布局 layout = QVBoxLayout() layout.setSpacing(15) layout.setContentsMargins(40, 30, 40, 30) # 用户名输入 user_layout = QHBoxLayout() user_layout.addWidget(QLabel("用户名:")) self.user_edit = QLineEdit() self.user_edit.setPlaceholderText("请输入用户名") user_layout.addWidget(self.user_edit) # 密码输入 pwd_layout = QHBoxLayout() pwd_layout.addWidget(QLabel("密 码:")) self.pwd_edit = QLineEdit() self.pwd_edit.setEchoMode(QLineEdit.Password) # 密码隐藏 self.pwd_edit.setPlaceholderText("请输入密码") pwd_layout.addWidget(self.pwd_edit) # 按钮区 btn_layout = QHBoxLayout() login_btn = QPushButton("登录") cancel_btn = QPushButton("取消") login_btn.clicked.connect(self.check_login) cancel_btn.clicked.connect(self.reject) # 关闭对话框,返回Rejected btn_layout.addWidget(login_btn) btn_layout.addWidget(cancel_btn) # 添加到布局 layout.addLayout(user_layout) layout.addLayout(pwd_layout) layout.addLayout(btn_layout) self.setLayout(layout) def check_login(self): """验证登录信息""" username = self.user_edit.text().strip() password = self.pwd_edit.text().strip() # 简单验证(实际项目中对接数据库/接口) if username == "admin" and password == "123456": # 验证通过,关闭对话框并返回Accepted self.accept() else: QMessageBox.warning( self, "登录失败", "用户名或密码错误!", QMessageBox.Ok ) # 可选:获取用户输入的信息(供主窗口调用) def get_user_info(self): return { "username": self.user_edit.text().strip(), "password": self.pwd_edit.text().strip() }步骤2:主窗口调用自定义登录对话框 import sys from PyQt5.QtWidgets import ( QApplication, QWidget, QVBoxLayout, QPushButton, QLabel ) from login_dialog import LoginDialog # 若在同一文件,无需导入 class MainWindow(QWidget): def __init__(self): super().__init__() self.init_ui() def init_ui(self): self.setWindowTitle("主窗口(调用自定义登录对话框)") self.resize(400, 300) # 布局 layout = QVBoxLayout() layout.setSpacing(20) layout.setContentsMargins(50, 50, 50, 50) # 按钮和标签 login_btn = QPushButton("点击登录") self.status_label = QLabel("当前状态:未登录") self.status_label.setAlignment(Qt.AlignCenter) # 绑定信号 login_btn.clicked.connect(self.show_login_dialog) # 添加到布局 layout.addWidget(login_btn) layout.addWidget(self.status_label) self.setLayout(layout) def show_login_dialog(self): """显示登录对话框并处理返回值""" # 创建登录对话框实例 login_dlg = LoginDialog(self) # 显示对话框并获取返回值 result = login_dlg.exec_() # 判断返回值:Accepted(登录成功)/ Rejected(取消/关闭) if result == login_dlg.Accepted: user_info = login_dlg.get_user_info() self.status_label.setText(f"当前状态:已登录(用户名:{user_info['username']})") else: self.status_label.setText("当前状态:取消登录") if __name__ == "__main__": app = QApplication(sys.argv) window = MainWindow() window.show() sys.exit(app.exec_())2. 自定义对话框核心要点 继承QDialog:自定义对话框必须继承QDialog类; 模态设置:setModal(True)设置模态(默认模态),非模态用setModal(False); 返回值处理: self.accept():关闭对话框,返回QDialog.Accepted(表示操作成功); self.reject():关闭对话框,返回QDialog.Rejected(表示取消/失败); 调用exec_()显示对话框,返回值为Accepted/Rejected; 数据传递:通过自定义方法(如get_user_info())将对话框内的输入数据传递给主窗口; 窗口大小:自定义对话框建议用setFixedSize()固定大小,避免用户缩放导致界面混乱。 四、综合案例:整合标准对话框与自定义对话框 实现一个“简易文本编辑器”,整合: 自定义登录对话框(启动时要求登录); 标准文件对话框(打开/保存文件); 标准颜色/字体对话框(设置文本样式); 标准消息框(提示操作结果)。 完整代码 mjzp8xp5.png图片 mjzp9112.png图片 import sys import os from PyQt5.QtWidgets import ( QApplication, QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QTextEdit, QFileDialog, QColorDialog, QFontDialog, QMessageBox, QDialog, QLabel, QLineEdit ) from PyQt5.QtGui import QColor, QFont from PyQt5.QtCore import Qt # 自定义登录对话框 class LoginDialog(QDialog): def __init__(self, parent=None): super().__init__(parent) self.init_ui() self.setModal(True) def init_ui(self): self.setWindowTitle("用户登录") self.setFixedSize(350, 200) layout = QVBoxLayout() layout.setSpacing(15) layout.setContentsMargins(40, 30, 40, 30) # 用户名 user_layout = QHBoxLayout() user_layout.addWidget(QLabel("用户名:")) self.user_edit = QLineEdit() self.user_edit.setPlaceholderText("admin") user_layout.addWidget(self.user_edit) layout.addLayout(user_layout) # 密码 pwd_layout = QHBoxLayout() pwd_layout.addWidget(QLabel("密 码:")) self.pwd_edit = QLineEdit() self.pwd_edit.setEchoMode(QLineEdit.Password) self.pwd_edit.setPlaceholderText("123456") pwd_layout.addWidget(self.pwd_edit) layout.addLayout(pwd_layout) # 按钮 btn_layout = QHBoxLayout() login_btn = QPushButton("登录") cancel_btn = QPushButton("取消") login_btn.clicked.connect(self.check_login) cancel_btn.clicked.connect(self.reject) btn_layout.addWidget(login_btn) btn_layout.addWidget(cancel_btn) layout.addLayout(btn_layout) self.setLayout(layout) def check_login(self): if self.user_edit.text().strip() == "admin" and self.pwd_edit.text().strip() == "123456": self.accept() else: QMessageBox.warning(self, "失败", "用户名/密码错误!") # 主编辑器窗口 class EditorWindow(QWidget): def __init__(self): super().__init__() # 先显示登录对话框,验证失败则退出 if not self.check_login(): sys.exit() # 初始化主界面 self.init_ui() self.current_file = None def check_login(self): """显示登录对话框,返回是否登录成功""" login_dlg = LoginDialog(self) return login_dlg.exec_() == login_dlg.Accepted def init_ui(self): self.setWindowTitle("简易编辑器(整合对话框)") self.resize(800, 600) # 布局 main_layout = QVBoxLayout() main_layout.setSpacing(10) main_layout.setContentsMargins(15, 15, 15, 15) # 功能按钮区 btn_layout = QHBoxLayout() open_btn = QPushButton("打开文件") save_btn = QPushButton("保存文件") color_btn = QPushButton("字体颜色") font_btn = QPushButton("字体设置") for btn in [open_btn, save_btn, color_btn, font_btn]: btn.setFixedSize(100, 30) btn_layout.addWidget(open_btn) btn_layout.addWidget(save_btn) btn_layout.addStretch() btn_layout.addWidget(color_btn) btn_layout.addWidget(font_btn) # 文本编辑区 self.text_edit = QTextEdit() self.text_edit.setFont(QFont("微软雅黑", 12)) # 添加到布局 main_layout.addLayout(btn_layout) main_layout.addWidget(self.text_edit) self.setLayout(main_layout) # 绑定信号 open_btn.clicked.connect(self.open_file) save_btn.clicked.connect(self.save_file) color_btn.clicked.connect(self.set_font_color) font_btn.clicked.connect(self.set_font) # 打开文件(标准文件对话框) def open_file(self): file_path, _ = QFileDialog.getOpenFileName( self, "打开文件", "", "Text Files (*.txt);;All Files (*.*)" ) if file_path and os.path.exists(file_path): with open(file_path, "r", encoding="utf-8") as f: self.text_edit.setText(f.read()) self.current_file = file_path QMessageBox.information(self, "成功", f"已打开文件:{os.path.basename(file_path)}") # 保存文件(标准文件对话框) def save_file(self): if self.current_file: with open(self.current_file, "w", encoding="utf-8") as f: f.write(self.text_edit.toPlainText()) QMessageBox.information(self, "成功", "文件保存成功!") else: file_path, _ = QFileDialog.getSaveFileName( self, "保存文件", "", "Text Files (*.txt)" ) if file_path: if not file_path.endswith(".txt"): file_path += ".txt" with open(file_path, "w", encoding="utf-8") as f: f.write(self.text_edit.toPlainText()) self.current_file = file_path QMessageBox.information(self, "成功", f"文件已保存到:{file_path}") # 设置字体颜色(标准颜色对话框) def set_font_color(self): color = QColorDialog.getColor(Qt.black, self, "选择字体颜色") if color.isValid(): fmt = self.text_edit.currentCharFormat() fmt.setForeground(color) self.text_edit.mergeCurrentCharFormat(fmt) # 设置字体(标准字体对话框) def set_font(self): font, ok = QFontDialog.getFont(self.text_edit.font(), self, "选择字体") if ok: self.text_edit.setCurrentFont(font) if __name__ == "__main__": app = QApplication(sys.argv) window = EditorWindow() window.show() sys.exit(app.exec_())五、常见问题排查 1. 对话框相关问题 问题1:自定义对话框非模态,主窗口可操作 → 解决:调用setModal(True),或用exec_()显示(show()显示为非模态); 问题2:文件对话框选择中文路径乱码 → 解决:读写文件时指定encoding="utf-8",Windows系统可尝试encoding="gbk"; 问题3:登录对话框关闭后主窗口也退出 → 解决:主窗口初始化时,登录失败调用sys.exit()需确保是在app创建后; 问题4:标准对话框标题/按钮显示英文 → 解决:PyQt5默认是英文,可通过设置Qt的语言环境(需额外配置翻译文件),或使用自定义对话框替换。 2. 模态对话框的坑 exec_():显示模态对话框,阻塞主线程,返回值为Accepted/Rejected; show():显示非模态对话框,不阻塞主线程,无返回值; 自定义对话框若用show()显示,需手动设置setModal(True)才能变为模态。 总结 标准对话框:PyQt5预制的通用交互窗口(消息框、文件选择框等),直接调用即可,覆盖80%通用场景; 自定义对话框:继承QDialog开发专属窗口,核心是setModal()设置模态、accept()/reject()处理返回值; 模态vs非模态:模态对话框阻塞主窗口(常用),非模态不阻塞(适合悬浮面板); 综合应用:实际项目中常结合标准对话框和自定义对话框,比如登录验证+文件操作+消息提示。 下一章我们将学习PyQt5的容器控件(QTabWidget、QGroupBox),实现多标签页、分组管理的复杂界面,进一步提升界面的层次感和实用性。如果在对话框开发中遇到问题,或者想拓展更复杂的自定义对话框(如带验证码的登录窗口),欢迎在评论区留言讨论~ -
PyQt5文本与表格控件:QTextEdit与QTableWidget(附实战代码) 第7篇:PyQt5文本与表格控件:QTextEdit与QTableWidget(完整代码) 哈喽~ 欢迎来到PyQt5系列的第7篇!上一章我们掌握了网格布局和表单布局,解决了复杂界面的排版问题。今天我们聚焦两个高频实用控件:QTextEdit(多行富文本编辑控件)和QTableWidget(表格控件)——这两个控件是处理“大段文本”和“结构化数据”的核心,比如文本编辑器、数据管理系统、报表展示等场景都离不开它们。全程搭配完整可运行代码,新手也能轻松掌握! mjxm4a2v.png图片 一、先明确:两个控件的核心定位 在学习具体用法前,先理清这两个控件的适用场景,避免用错: QTextEdit:多行文本编辑/展示控件,支持富文本(字体、颜色、图片、超链接),比QLineEdit(单行)功能强大,核心用于“大段文本处理”(如记事本、富文本编辑器); QTableWidget:表格控件,支持行/列的增删改查、单元格编辑、数据排序,核心用于“结构化数据展示/编辑”(如Excel简易表格、用户信息列表)。 二、QTextEdit详解:从基础文本到富文本编辑 QTextEdit是阶段一“简易记事本”中用到的核心控件,但当时只用到了基础文本功能,这一节我们深挖它的富文本能力。 1. QTextEdit基础用法(完整代码) 先回顾基础功能,再拓展富文本设置: import sys from PyQt5.QtWidgets import ( QApplication, QWidget, QTextEdit, QVBoxLayout, QPushButton, QHBoxLayout, QColorDialog, QFontDialog ) from PyQt5.QtGui import QTextCharFormat, QFont, QColor from PyQt5.QtCore import Qt class TextEditDemo(QWidget): def __init__(self): super().__init__() self.init_ui() def init_ui(self): self.setWindowTitle("QTextEdit基础与富文本演示") self.resize(600, 400) # 1. 主布局(垂直):按钮区 + 文本编辑区 main_layout = QVBoxLayout() main_layout.setSpacing(10) main_layout.setContentsMargins(15, 15, 15, 15) # 2. 功能按钮区(水平布局) btn_layout = QHBoxLayout() btn_layout.setSpacing(8) # 富文本功能按钮 self.bold_btn = QPushButton("加粗") self.italic_btn = QPushButton("斜体") self.color_btn = QPushButton("字体颜色") self.font_btn = QPushButton("选择字体") self.clear_btn = QPushButton("清空文本") # 按钮样式 btn_size = (80, 30) for btn in [self.bold_btn, self.italic_btn, self.color_btn, self.font_btn, self.clear_btn]: btn.setFixedSize(*btn_size) # 添加到按钮布局 btn_layout.addWidget(self.bold_btn) btn_layout.addWidget(self.italic_btn) btn_layout.addWidget(self.color_btn) btn_layout.addWidget(self.font_btn) btn_layout.addStretch() # 伸缩空间 btn_layout.addWidget(self.clear_btn) # 3. 创建QTextEdit控件 self.text_edit = QTextEdit() # 基础设置:默认提示文本、字体 self.text_edit.setPlaceholderText("请输入文本(支持富文本格式:加粗、斜体、改颜色等)") self.text_edit.setFont(QFont("微软雅黑", 12)) # 允许自动换行 self.text_edit.setLineWrapMode(QTextEdit.WidgetWidth) # 4. 添加到主布局 main_layout.addLayout(btn_layout) main_layout.addWidget(self.text_edit) # 5. 绑定布局和信号 self.setLayout(main_layout) self.bind_signals() def bind_signals(self): """绑定信号与槽""" self.bold_btn.clicked.connect(self.set_bold) self.italic_btn.clicked.connect(self.set_italic) self.color_btn.clicked.connect(self.set_font_color) self.font_btn.clicked.connect(self.choose_font) self.clear_btn.clicked.connect(self.text_edit.clear) def set_bold(self): """设置选中文本加粗/取消加粗""" # 获取当前光标选中的文本格式 fmt = QTextCharFormat() # 切换加粗状态:当前加粗则取消,反之则加粗 fmt.setFontWeight(QFont.Bold if self.text_edit.fontWeight() != QFont.Bold else QFont.Normal) # 应用格式到选中文本 self.text_edit.mergeCurrentCharFormat(fmt) def set_italic(self): """设置选中文本斜体/取消斜体""" fmt = QTextCharFormat() fmt.setFontItalic(not self.text_edit.fontItalic()) self.text_edit.mergeCurrentCharFormat(fmt) def set_font_color(self): """选择字体颜色并应用到选中文本""" # 弹出颜色选择对话框 color = QColorDialog.getColor(Qt.black, self, "选择字体颜色") if color.isValid(): # 用户选择了有效颜色 fmt = QTextCharFormat() fmt.setForeground(color) self.text_edit.mergeCurrentCharFormat(fmt) def choose_font(self): """选择字体(字体名、大小、样式)""" # 弹出字体选择对话框 font, ok = QFontDialog.getFont(self.text_edit.font(), self, "选择字体") if ok: # 用户确认选择 self.text_edit.setCurrentFont(font) if __name__ == "__main__": app = QApplication(sys.argv) window = TextEditDemo() window.show() sys.exit(app.exec_())2. QTextEdit核心方法解析 QTextEdit的核心分为“文本操作”和“格式设置”两类,重点掌握以下方法: (1)基础文本操作 方法作用toPlainText()获取纯文本内容(忽略富文本格式)setPlainText(文本)设置纯文本内容(覆盖原有内容)toHtml()获取富文本内容(HTML格式)setHtml(HTML文本)设置富文本内容(支持HTML标签)append(文本)在末尾追加文本(保留原有格式)clear()清空所有文本undo()/redo()撤销/重做操作(2)富文本格式设置 方法作用mergeCurrentCharFormat(格式对象)将格式应用到选中的文本setCurrentFont(字体对象)设置当前光标位置/选中文本的字体setFontWeight(QFont.Bold/Normal)设置加粗/取消加粗setFontItalic(True/False)设置斜体/取消斜体setForeground(QColor)设置字体颜色3. QTextEdit实战:简易富文本编辑器 基于基础用法,拓展一个带“打开/保存富文本”功能的编辑器,支持保存为HTML格式(保留富文本样式): import sys import os from PyQt5.QtWidgets import ( QApplication, QWidget, QTextEdit, QVBoxLayout, QPushButton, QHBoxLayout, QColorDialog, QFontDialog, QFileDialog ) from PyQt5.QtGui import QTextCharFormat, QFont, QColor from PyQt5.QtCore import Qt class RichTextEditor(QWidget): def __init__(self): super().__init__() self.init_ui() self.current_file_path = None # 记录当前文件路径 def init_ui(self): self.setWindowTitle("简易富文本编辑器") self.resize(800, 600) # 1. 主布局 main_layout = QVBoxLayout() main_layout.setSpacing(10) main_layout.setContentsMargins(15, 15, 15, 15) # 2. 顶部功能按钮区 top_btn_layout = QHBoxLayout() self.new_btn = QPushButton("新建") self.open_btn = QPushButton("打开") self.save_btn = QPushButton("保存") for btn in [self.new_btn, self.open_btn, self.save_btn]: btn.setFixedSize(80, 30) top_btn_layout.addWidget(self.new_btn) top_btn_layout.addWidget(self.open_btn) top_btn_layout.addWidget(self.save_btn) top_btn_layout.addStretch() # 3. 格式设置按钮区 fmt_btn_layout = QHBoxLayout() self.bold_btn = QPushButton("加粗") self.italic_btn = QPushButton("斜体") self.color_btn = QPushButton("字体颜色") self.font_btn = QPushButton("选择字体") for btn in [self.bold_btn, self.italic_btn, self.color_btn, self.font_btn]: btn.setFixedSize(80, 30) fmt_btn_layout.addWidget(self.bold_btn) fmt_btn_layout.addWidget(self.italic_btn) fmt_btn_layout.addWidget(self.color_btn) fmt_btn_layout.addWidget(self.font_btn) fmt_btn_layout.addStretch() # 4. 文本编辑区 self.text_edit = QTextEdit() self.text_edit.setFont(QFont("微软雅黑", 12)) # 5. 添加到主布局 main_layout.addLayout(top_btn_layout) main_layout.addLayout(fmt_btn_layout) main_layout.addWidget(self.text_edit) # 6. 绑定布局和信号 self.setLayout(main_layout) self.bind_signals() def bind_signals(self): """绑定所有信号与槽""" # 文件操作 self.new_btn.clicked.connect(self.on_new) self.open_btn.clicked.connect(self.on_open) self.save_btn.clicked.connect(self.on_save) # 格式操作 self.bold_btn.clicked.connect(self.set_bold) self.italic_btn.clicked.connect(self.set_italic) self.color_btn.clicked.connect(self.set_font_color) self.font_btn.clicked.connect(self.choose_font) # ---------- 文件操作槽函数 ---------- def on_new(self): """新建文件:清空文本,重置路径""" self.text_edit.clear() self.current_file_path = None self.setWindowTitle("简易富文本编辑器 - 未保存文件") def on_open(self): """打开文件:支持txt(纯文本)和html(富文本)""" file_path, _ = QFileDialog.getOpenFileName( self, "打开文件", "", "HTML Files (*.html);;Text Files (*.txt);;All Files (*.*)" ) if file_path and os.path.exists(file_path): self.current_file_path = file_path # 根据后缀选择读取方式 if file_path.endswith(".html"): with open(file_path, "r", encoding="utf-8") as f: content = f.read() self.text_edit.setHtml(content) else: with open(file_path, "r", encoding="utf-8") as f: content = f.read() self.text_edit.setPlainText(content) # 更新窗口标题 self.setWindowTitle(f"简易富文本编辑器 - {os.path.basename(file_path)}") def on_save(self): """保存文件:默认保存为HTML(保留富文本格式)""" if self.current_file_path: # 直接保存 self.save_file(self.current_file_path) else: # 弹出保存对话框 file_path, _ = QFileDialog.getSaveFileName( self, "保存文件", "", "HTML Files (*.html);;Text Files (*.txt)" ) if file_path: # 补充后缀 if not (file_path.endswith(".html") or file_path.endswith(".txt")): file_path += ".html" self.save_file(file_path) self.current_file_path = file_path self.setWindowTitle(f"简易富文本编辑器 - {os.path.basename(file_path)}") def save_file(self, file_path): """辅助函数:保存文件""" if file_path.endswith(".html"): content = self.text_edit.toHtml() else: content = self.text_edit.toPlainText() with open(file_path, "w", encoding="utf-8") as f: f.write(content) # ---------- 格式设置槽函数 ---------- def set_bold(self): fmt = QTextCharFormat() fmt.setFontWeight(QFont.Bold if self.text_edit.fontWeight() != QFont.Bold else QFont.Normal) self.text_edit.mergeCurrentCharFormat(fmt) def set_italic(self): fmt = QTextCharFormat() fmt.setFontItalic(not self.text_edit.fontItalic()) self.text_edit.mergeCurrentCharFormat(fmt) def set_font_color(self): color = QColorDialog.getColor(Qt.black, self, "选择字体颜色") if color.isValid(): fmt = QTextCharFormat() fmt.setForeground(color) self.text_edit.mergeCurrentCharFormat(fmt) def choose_font(self): font, ok = QFontDialog.getFont(self.text_edit.font(), self, "选择字体") if ok: self.text_edit.setCurrentFont(font) if __name__ == "__main__": app = QApplication(sys.argv) editor = RichTextEditor() editor.show() sys.exit(app.exec_())三、QTableWidget详解:结构化数据的展示与编辑 QTableWidget是处理表格数据的核心控件,支持行/列管理、单元格编辑、数据排序,是实现“数据表格”的首选。 1. QTableWidget基础用法(完整代码) 先实现一个基础表格,演示行/列添加、单元格赋值、选中行获取等核心操作: import sys from PyQt5.QtWidgets import ( QApplication, QWidget, QTableWidget, QTableWidgetItem, QVBoxLayout, QHBoxLayout, QPushButton, QMessageBox ) from PyQt5.QtCore import Qt class TableWidgetDemo(QWidget): def __init__(self): super().__init__() self.init_ui() def init_ui(self): self.setWindowTitle("QTableWidget基础演示") self.resize(600, 400) # 1. 主布局:按钮区 + 表格区 main_layout = QVBoxLayout() main_layout.setSpacing(15) main_layout.setContentsMargins(15, 15, 15, 15) # 2. 功能按钮区 btn_layout = QHBoxLayout() self.add_row_btn = QPushButton("添加行") self.del_row_btn = QPushButton("删除选中行") self.get_data_btn = QPushButton("获取选中行数据") self.clear_btn = QPushButton("清空表格") for btn in [self.add_row_btn, self.del_row_btn, self.get_data_btn, self.clear_btn]: btn.setFixedSize(100, 30) btn_layout.addWidget(self.add_row_btn) btn_layout.addWidget(self.del_row_btn) btn_layout.addWidget(self.get_data_btn) btn_layout.addWidget(self.clear_btn) btn_layout.addStretch() # 3. 创建QTableWidget控件 self.table = QTableWidget() # 设置表格行列数:5行4列 self.table.setRowCount(5) self.table.setColumnCount(4) # 设置列标题 self.table.setHorizontalHeaderLabels(["ID", "姓名", "性别", "年龄"]) # 可选设置:列宽自适应、行高自适应、禁止编辑(默认允许) self.table.horizontalHeader().setStretchLastSection(True) # 最后一列拉伸 self.table.verticalHeader().setVisible(False) # 隐藏行号 # self.table.setEditTriggers(QTableWidget.NoEditTriggers) # 禁止编辑单元格 # 4. 填充初始数据 init_data = [ [1, "张三", "男", 25], [2, "李四", "女", 28], [3, "王五", "男", 30], [4, "赵六", "女", 22], [5, "钱七", "男", 27] ] for row in range(len(init_data)): for col in range(len(init_data[row])): # 创建表格项(设置居中对齐) item = QTableWidgetItem(str(init_data[row][col])) item.setTextAlignment(Qt.AlignCenter) # 将项添加到表格 self.table.setItem(row, col, item) # 5. 添加到主布局 main_layout.addLayout(btn_layout) main_layout.addWidget(self.table) # 6. 绑定布局和信号 self.setLayout(main_layout) self.bind_signals() def bind_signals(self): """绑定信号与槽""" self.add_row_btn.clicked.connect(self.add_row) self.del_row_btn.clicked.connect(self.del_selected_row) self.get_data_btn.clicked.connect(self.get_selected_data) self.clear_btn.clicked.connect(self.clear_table) def add_row(self): """添加一行空数据""" # 获取当前行数,在末尾添加新行 current_row = self.table.rowCount() self.table.insertRow(current_row) # 给新行ID列赋值(自增) id_item = QTableWidgetItem(str(current_row + 1)) id_item.setTextAlignment(Qt.AlignCenter) self.table.setItem(current_row, 0, id_item) def del_selected_row(self): """删除选中的行""" # 获取选中的行号(单个选中) selected_rows = self.table.selectedItems() if not selected_rows: QMessageBox.warning(self, "提示", "请先选中要删除的行!") return # 获取选中行的行号(取第一个选中项的行号) row = selected_rows[0].row() self.table.removeRow(row) def get_selected_data(self): """获取选中行的所有数据""" selected_rows = self.table.selectedItems() if not selected_rows: QMessageBox.warning(self, "提示", "请先选中一行!") return # 提取选中行的所有列数据 row = selected_rows[0].row() data = [] for col in range(self.table.columnCount()): item = self.table.item(row, col) data.append(item.text() if item else "") # 显示数据 QMessageBox.information(self, "选中行数据", f"ID:{data[0]}\n姓名:{data[1]}\n性别:{data[2]}\n年龄:{data[3]}") def clear_table(self): """清空表格(保留列标题)""" self.table.setRowCount(0) if __name__ == "__main__": app = QApplication(sys.argv) window = TableWidgetDemo() window.show() sys.exit(app.exec_())2. QTableWidget核心方法解析 QTableWidget的核心围绕“行/列管理”和“单元格操作”,重点掌握: (1)行列管理 方法作用setRowCount(行数)设置表格行数setColumnCount(列数)设置表格列数setHorizontalHeaderLabels([列标题列表])设置列标题insertRow(行号)在指定行号位置插入新行removeRow(行号)删除指定行setRowCount(0)清空所有行(保留列标题)(2)单元格操作 方法作用setItem(行号, 列号, QTableWidgetItem)给指定单元格设置内容item(行号, 列号)获取指定单元格的项selectedItems()获取所有选中的单元格项setEditTriggers(触发方式)设置单元格编辑触发方式(如NoEditTriggers禁止编辑)setTextAlignment(对齐方式)设置单元格文本对齐(如Qt.AlignCenter居中)(3)样式/布局优化 方法作用horizontalHeader().setStretchLastSection(True)最后一列自适应拉伸verticalHeader().setVisible(False)隐藏行号setColumnWidth(列号, 宽度)设置指定列的宽度setRowHeight(行号, 高度)设置指定行的高度3. QTableWidget实战:简易数据表格管理器 拓展一个带“导入/导出数据”(CSV格式)、“数据排序”功能的表格管理器,贴合实际数据管理场景: import sys import os import csv from PyQt5.QtWidgets import ( QApplication, QWidget, QTableWidget, QTableWidgetItem, QVBoxLayout, QHBoxLayout, QPushButton, QMessageBox, QFileDialog, QComboBox ) from PyQt5.QtCore import Qt class TableManager(QWidget): def __init__(self): super().__init__() self.init_ui() def init_ui(self): self.setWindowTitle("简易数据表格管理器") self.resize(700, 500) # 1. 主布局 main_layout = QVBoxLayout() main_layout.setSpacing(15) main_layout.setContentsMargins(15, 15, 15, 15) # 2. 顶部功能区(导入/导出 + 排序) top_layout = QHBoxLayout() # 导入/导出按钮 self.import_btn = QPushButton("导入CSV") self.export_btn = QPushButton("导出CSV") # 排序下拉框 self.sort_combo = QComboBox() self.sort_combo.addItems(["按ID升序", "按年龄升序", "按年龄降序"]) self.sort_btn = QPushButton("排序") # 样式设置 for btn in [self.import_btn, self.export_btn, self.sort_btn]: btn.setFixedSize(100, 30) self.sort_combo.setFixedWidth(120) # 添加到布局 top_layout.addWidget(self.import_btn) top_layout.addWidget(self.export_btn) top_layout.addStretch() top_layout.addWidget(self.sort_combo) top_layout.addWidget(self.sort_btn) # 3. 表格区 self.table = QTableWidget() # 初始列标题 self.table.setColumnCount(4) self.table.setHorizontalHeaderLabels(["ID", "姓名", "性别", "年龄"]) # 布局优化 self.table.horizontalHeader().setStretchLastSection(True) self.table.verticalHeader().setVisible(False) # 4. 添加到主布局 main_layout.addLayout(top_layout) main_layout.addWidget(self.table) # 5. 绑定信号 self.setLayout(main_layout) self.bind_signals() def bind_signals(self): self.import_btn.clicked.connect(self.import_csv) self.export_btn.clicked.connect(self.export_csv) self.sort_btn.clicked.connect(self.sort_data) # ---------- CSV导入导出 ---------- def import_csv(self): """导入CSV文件到表格""" file_path, _ = QFileDialog.getOpenFileName( self, "导入CSV文件", "", "CSV Files (*.csv);;All Files (*.*)" ) if not file_path: return try: # 清空原有数据 self.table.setRowCount(0) # 读取CSV文件 with open(file_path, "r", encoding="utf-8") as f: reader = csv.reader(f) # 跳过表头(如果CSV有表头) # next(reader) # 逐行添加数据 for row_idx, row_data in enumerate(reader): self.table.insertRow(row_idx) for col_idx, col_data in enumerate(row_data): item = QTableWidgetItem(col_data) item.setTextAlignment(Qt.AlignCenter) self.table.setItem(row_idx, col_idx, item) QMessageBox.information(self, "成功", "CSV文件导入成功!") except Exception as e: QMessageBox.critical(self, "错误", f"导入失败:{str(e)}") def export_csv(self): """导出表格数据到CSV""" file_path, _ = QFileDialog.getSaveFileName( self, "导出CSV文件", "", "CSV Files (*.csv)" ) if not file_path: return # 补充.csv后缀 if not file_path.endswith(".csv"): file_path += ".csv" try: # 写入CSV文件 with open(file_path, "w", encoding="utf-8", newline="") as f: writer = csv.writer(f) # 写入表头 headers = [self.table.horizontalHeaderItem(col).text() for col in range(self.table.columnCount())] writer.writerow(headers) # 写入数据 for row in range(self.table.rowCount()): row_data = [] for col in range(self.table.columnCount()): item = self.table.item(row, col) row_data.append(item.text() if item else "") writer.writerow(row_data) QMessageBox.information(self, "成功", "CSV文件导出成功!") except Exception as e: QMessageBox.critical(self, "错误", f"导出失败:{str(e)}") # ---------- 数据排序 ---------- def sort_data(self): """按选择的规则排序""" sort_type = self.sort_combo.currentText() if sort_type == "按ID升序": # 按第0列(ID)升序排序 self.table.sortItems(0, Qt.AscendingOrder) elif sort_type == "按年龄升序": # 按第3列(年龄)升序排序 self.table.sortItems(3, Qt.AscendingOrder) elif sort_type == "按年龄降序": # 按第3列(年龄)降序排序 self.table.sortItems(3, Qt.DescendingOrder) if __name__ == "__main__": app = QApplication(sys.argv) manager = TableManager() manager.show() sys.exit(app.exec_())四、综合案例:文本+表格的信息管理窗口 整合QTextEdit和QTableWidget,实现一个“用户信息管理窗口”——表格展示用户列表,选中用户后在文本区显示详情,支持编辑详情并保存: import sys from PyQt5.QtWidgets import ( QApplication, QWidget, QTableWidget, QTableWidgetItem, QVBoxLayout, QHBoxLayout, QPushButton, QTextEdit, QMessageBox, QSplitter ) from PyQt5.QtCore import Qt, QSize class InfoManager(QWidget): def __init__(self): super().__init__() self.init_ui() def init_ui(self): self.setWindowTitle("用户信息管理窗口(文本+表格综合)") self.resize(800, 500) # 1. 创建分割器(左右布局,可拖动调整宽度) splitter = QSplitter(Qt.Horizontal) # 2. 左侧表格区 self.table = QTableWidget() self.table.setColumnCount(3) self.table.setHorizontalHeaderLabels(["ID", "姓名", "性别"]) self.table.horizontalHeader().setStretchLastSection(True) self.table.verticalHeader().setVisible(False) # 填充测试数据 test_data = [[1, "张三", "男"], [2, "李四", "女"], [3, "王五", "男"]] for row in range(len(test_data)): self.table.insertRow(row) for col in range(len(test_data[row])): item = QTableWidgetItem(str(test_data[row][col])) item.setTextAlignment(Qt.AlignCenter) self.table.setItem(row, col, item) # 3. 右侧文本区(详情编辑) right_widget = QWidget() right_layout = QVBoxLayout(right_widget) # 文本编辑区 self.info_edit = QTextEdit() self.info_edit.setPlaceholderText("选中表格中的用户,查看/编辑详情...") self.info_edit.setFont(QtGui.QFont("微软雅黑", 11)) # 保存按钮 save_btn = QPushButton("保存详情") save_btn.setFixedSize(100, 30) # 添加到右侧布局 right_layout.addWidget(self.info_edit) right_layout.addWidget(save_btn, alignment=Qt.AlignCenter) # 4. 将表格和右侧控件添加到分割器 splitter.addWidget(self.table) splitter.addWidget(right_widget) # 设置分割器初始宽度比例 splitter.setSizes([300, 500]) # 5. 主布局 main_layout = QVBoxLayout() main_layout.addWidget(splitter) self.setLayout(main_layout) # 6. 绑定信号 self.table.clicked.connect(self.show_user_info) save_btn.clicked.connect(self.save_user_info) def show_user_info(self): """选中表格行,显示用户详情""" selected_items = self.table.selectedItems() if not selected_items: return row = selected_items[0].row() # 获取用户基础信息 user_id = self.table.item(row, 0).text() name = self.table.item(row, 1).text() gender = self.table.item(row, 2).text() # 构造详情文本 info = f"""用户详情(ID:{user_id}) 姓名:{name} 性别:{gender} 年龄:暂未填写 电话:暂未填写 邮箱:暂未填写 备注:无 """ self.info_edit.setPlainText(info) def save_user_info(self): """保存编辑后的详情""" if not self.info_edit.toPlainText(): QMessageBox.warning(self, "提示", "详情不能为空!") return QMessageBox.information(self, "成功", "用户详情保存成功!") # 实际项目中可将详情写入数据库/文件 if __name__ == "__main__": app = QApplication(sys.argv) manager = InfoManager() manager.show() sys.exit(app.exec_())五、常见问题排查 1. QTextEdit相关问题 问题1:富文本格式设置不生效 → 解决:确保先选中文本再点击格式按钮;检查mergeCurrentCharFormat是否正确传入格式对象; 问题2:保存的HTML文件打开乱码 → 解决:保存时指定encoding="utf-8"; 问题3:文本编辑区不自适应窗口缩放 → 解决:确保文本编辑区直接添加到垂直布局,未设置固定大小。 2. QTableWidget相关问题 问题1:表格数据显示不全 → 解决:用horizontalHeader().setStretchLastSection(True)让最后一列拉伸;或手动设置列宽setColumnWidth; 问题2:选中行获取不到数据 → 解决:selectedItems()返回的是选中的单元格列表,需通过item.row()获取行号,再遍历列获取整行数据; 问题3:CSV导入/导出乱码 → 解决:读写CSV时指定encoding="utf-8";Windows系统可尝试encoding="gbk"; 问题4:单元格无法编辑 → 解决:检查setEditTriggers是否设置为NoEditTriggers,如需编辑改为DoubleClicked或AllEditTriggers。 总结 QTextEdit:核心用于多行文本/富文本处理,支持纯文本和HTML格式,mergeCurrentCharFormat是设置富文本格式的核心方法; QTableWidget:核心用于结构化数据展示/编辑,重点掌握行列管理、单元格操作、数据导入导出; 两个控件常结合使用(如表格展示列表+文本区展示详情),是数据管理类应用的核心组合; 下一章我们将学习PyQt5的对话框控件(QDialog),包括标准对话框和自定义对话框,进一步完善界面的交互能力。 如果在实操中遇到文本/表格处理的问题,或者想拓展更复杂的功能(如表格单元格合并、富文本插入图片),欢迎在评论区留言讨论~ -
腾讯换机助手 安卓iOS跨平台零流量数据迁移工具 换机必备 腾讯换机助手:跨平台数据迁移神器,零流量一键搞定换机难题 换手机最头疼的就是重要数据转移?腾讯官方出品的换机助手完美解决这个痛点!不管是安卓与iOS互传、同系统新机升级,还是手机与电脑数据互联,它都能实现安全、高速、零流量的数据迁移,不用手动录入信息、不用压缩文件画质,小白也能轻松操作,妥妥的换机必备工具! mjxlmvq5.png图片 一、核心功能:覆盖全场景数据迁移需求 1. 全品类数据无遗漏迁移 支持九大核心数据类型,从基础通讯信息到个性化内容全涵盖: 通讯类:联系人(含备注、分组)、短信(含验证码、聊天记录)、通话记录; 多媒体类:照片(保留相册分类、编辑记录)、视频(高清无损传输)、音乐(含歌词、播放列表); 应用与个性化类:手机应用(安卓支持迁移安装包,iOS支持同步应用列表)、浏览器书签、日程(含提醒设置); 特色类:微信资料(聊天记录、重要文件单独迁移,避免关键信息丢失)。 2. 跨平台无缝兼容,打破系统壁垒 彻底告别“系统不同不能传”的限制,全场景适配: 安卓↔iOS:跨系统迁移无压力,基础数据完美适配,不用担忧格式不兼容; 安卓↔安卓/ iOS↔iOS:同系统迁移更高效,应用配置、个性化设置同步转移,新机开机即还原旧机体验; 多设备互联:支持手机与Windows电脑、Mac(M1+芯片)、iPod touch间的数据互传,满足多设备数据管理需求。 3. 零流量高速传输,省时又省流 采用设备自建热点直连技术,传输体验拉满: 零流量消耗:无需WiFi、手机流量或数据线,外出没网也能轻松换机; 极速秒传:传输速度远超蓝牙,100张高清照片约1分钟完成,大体积4K视频也能快速传输; 无损品质:照片、视频不压缩画质,音乐不损失音质,应用数据不丢失配置。 4. 加密防护,隐私安全有保障 数据传输全程守护隐私,杜绝信息泄露: 双机直连不上云:数据仅在新旧设备间直接传输,不经过第三方服务器,避免云端存储风险; 加密传输技术:采用腾讯自研加密算法,数据传输过程中全程加密,防止被截取、偷窥; 授权验证机制:新机需扫码确认连接,仅授权设备可接收数据,避免陌生设备接入。 5. 3步极简操作,小白也能上手 界面设计简洁直观,步骤指引清晰,不用专业知识也能快速完成: 步骤1:新旧设备/手机与电脑均安装换机助手; 步骤2:旧设备发起“零流量转移”生成二维码,新设备/电脑扫码建立连接; 步骤3:勾选需要迁移的数据类型(支持全选或部分选择),点击“发送”即可等待完成。 二、核心特色:官方出品的差异化优势 1. 官方背书,兼容性与稳定性拉满 腾讯专业团队开发,适配市面上主流机型(华为、苹果、小米等),定期更新修复问题,不会因系统升级导致迁移失败,比第三方工具更靠谱。 2. 一机多用,不止于换机 除了换机场景,日常也能发挥大作用: 文件分享:朋友间互传高清照片、大视频,不用发微信压缩画质; 存储释放:手机存储满时,可将大文件迁移到电脑或另一台设备,快速释放空间; iOS额外福利:支持骚扰拦截功能,百万级号码库实时识别诈骗、推销来电,守护通话安全。 三、适用人群与场景 换新机用户:不管是跨系统切换(安卓换iOS或反之),还是同品牌升级,都能一键迁移所有数据,省去重新下载应用、录入联系人的麻烦; 多设备用户:拥有安卓手机+iPhone、手机+电脑的人群,可实现跨设备数据互联,不用依赖U盘或云盘; 注重隐私用户:担心云端传输泄露信息,选择双机直连加密传输,隐私更有保障; 小白/长辈用户:3步简单操作+中文清晰指引,不用求助他人,自己就能完成数据迁移。 四、使用小贴士 首次使用需授权WiFi、相册、通讯录、摄像头权限,否则无法正常建立连接和读取数据; 传输时保持新旧设备距离在1米内,避免热点信号弱导致传输中断; 传输完成后,建议核对联系人数量、照片完整性,确保无遗漏;若遇问题可通过“设置-我要反馈”联系官方客服。 APP下载 下载腾讯换机助手 下载地址:https://pan.quark.cn/s/f495ff74405f 提取码: 腾讯换机助手凭借跨平台兼容、全品类数据迁移、零流量高速传输、安全加密等优势,让换机过程变得轻松高效。不管你是准备换新机,还是需要跨设备传数据,这款官方工具都值得一试! -
太极工具箱v1.3.6下载 安卓无广告纯净版 百种实用工具聚合APP 太极工具箱v1.3.6:Android无广告纯净版聚合工具,百种功能轻松解决日常需求 给大家推荐一款超实用的Android端工具聚合APP——太极工具箱v1.3.6无广告纯净版!这款软件主打“轻量无扰+功能全面”,32.3MB的小巧体积不占手机内存,运行流畅不卡顿,不管是日常应急用工具、图片创意处理,还是查询设备信息,都能一站式满足,关键是全程无广告干扰,免费就能用所有功能,妥妥的手机必备“万能小助手”! mjxldmts.png图片 一、核心基础信息:快速了解这款工具 信息类别详情说明软件版本v1.3.6(无广告纯净版,无任何弹窗或推送广告,使用体验清爽)运行环境仅支持Android系统(适配主流Android版本,安装后无需复杂配置,打开即能用)软件大小32.3 MB(体积小巧,下载快、占用内存少,老旧手机也能流畅运行)界面语言全程中文界面,功能分类清晰,老人小孩也能轻松找到需要的工具二、四大核心功能模块:从日常到专业全覆盖 太极工具箱的功能按使用场景分为四大类,每类都包含多个高频实用工具,不用再下载多个单一工具APP,一个就能搞定所有需求: 1. 日常应急工具:生活小事不用愁 这类工具聚焦日常高频需求,关键时刻能帮上大忙: 基础便捷工具:手电筒(亮度可调,夜间找东西、走夜路超实用)、直尺(屏幕实时显示长度,临时量小物件尺寸)、量角器(DIY手工、学习画图时测角度)、LED字幕(输入文字生成滚动字幕,演唱会、接机举牌超吸睛)。 时间与天气工具:万年历(查节气、节假日、干支纪年,传统节日安排更省心)、天气查询(实时显示温度、降水概率,出门前快速了解天气)、日期计算器(计算两个日期之间的天数、工作日,规划行程或项目截止时间很方便)、时间屏保(设置个性化时间显示,手机闲置时也能当小闹钟)。 2. 专业传感器工具:手机秒变“测量仪” 利用手机硬件特性,将普通手机变成专业测量工具,适合学生、DIY爱好者或需要临时测量的场景: 环境与物理测量:指南针(户外迷路时定位方向,徒步、露营必备)、分贝仪(检测环境噪音,避免噪音干扰学习或休息)、金属探测器(找掉落的小金属零件、钥匙,或检测物体是否含金属)、水平仪(挂照片、装家具时找水平,避免歪歪扭扭)。 设备状态监测:重力传感器(直观显示手机倾斜角度,物理实验、游戏辅助都能用)、磁力传感器(检测磁场强度,科普或特殊场景测量)、方向传感器(精准显示方位,配合指南针使用更准确)、电池检测(查看电池剩余电量、健康状态,了解手机续航情况)。 3. 图片创意工具:轻松玩转图片处理 不管是日常修图、制作表情包,还是设计头像壁纸,这类工具都能满足创意需求,无需专业修图软件: 图片编辑与美化:壁纸大全(内置海量高清壁纸,涵盖风景、动漫、简约等风格,一键设置手机桌面)、头像大全(多种风格头像可选,不用再手动找图,直接保存使用)、图片水印(添加文字或图案水印,保护原创图片不被盗用)、图片取色(提取图片中的任意颜色代码,设计、画画时精准配色)。 图片创意玩法:GIF分解(将GIF动图拆分成单张图片,提取喜欢的帧制作表情包)、九空格切图(把一张图分成9张,朋友圈发九宫格拼图更整齐美观)、纯色图制作(生成任意颜色的纯色图片,当壁纸或设计背景很实用)、图片像素化(将图片处理成像素风格,打造复古或创意效果)。 4. 查询与辅助工具:快速获取关键信息 这类工具帮你快速查询实用信息,或了解手机状态,提升使用效率: 信息查询工具:二维码生成(支持带LOGO的个性化二维码,生成微信、网址、联系方式二维码,方便分享)、手机号归属地查询(输入手机号,快速了解号码所属运营商和地区,识别陌生号码)、IP查询地理位置(查IP对应的地区,了解网络状态或识别异地登录)、身份证查询(验证身份证号码格式是否正确,避免输入错误)。 手机辅助工具:屏幕检测(检测屏幕是否有坏点、漏光,新买手机或日常检测屏幕状态)、手机信息查看(一键显示手机型号、系统版本、硬件配置等信息,了解手机性能或维修时提供参考)。 三、三大核心特色:为什么值得下载? 1. 无广告纯净体验,使用不被打扰 作为“纯净版”,软件全程无任何弹窗广告、开屏广告或推送广告,打开工具、切换功能时不会被广告打断,专注处理需求,这点比很多同类工具APP更良心。 2. 功能聚合度高,告别“APP臃肿” 整合近百种功能,涵盖日常、专业、创意、查询四大场景,不用为了一个小功能下载一个APP,既节省手机存储空间,又减少桌面图标杂乱,找工具更高效。 3. 免费全功能开放,零门槛使用 所有工具均免费使用,不用开通会员、充值付费,也没有“试用功能”限制;界面操作简单,功能图标直观易懂,打开APP后点击对应工具就能用,新手不用学习就能上手。 四、适用场景:谁最需要这款工具? 学生党:直尺、量角器辅助学习,图片工具制作手抄报、PPT配图,日期计算器规划学习计划,一个APP解决多种学习需求。 上班族:二维码生成分享工作文件,图片水印保护工作图片,手机信息查询了解设备状态,提升办公效率。 户外爱好者:指南针、分贝仪、金属探测器,徒步、露营时应对各种突发情况,关键时刻能派上用场。 创意达人:GIF分解、九空格切图、头像壁纸制作,轻松玩转社交平台内容,打造个性化分享素材。 普通用户:手电筒、天气查询、日期计算等日常工具,解决生活中的小麻烦,不用再下载多个单一工具。 五、使用建议 首次打开APP时,建议先浏览“我的工具箱”页面,熟悉功能分类,后续找工具更快速; 常用工具可以添加到“我的工具箱”收藏,下次打开直接点击,不用再翻找分类; 使用传感器类工具时,尽量保持手机平稳,避免手抖影响测量精度; 图片处理后的文件会自动保存到手机相册,可直接在相册中查看或分享。 APP下载 太极工具箱 1.3.6.zip 下载地址:https://pan.quark.cn/s/e1f3b5ab2316 提取码: 总之,太极工具箱v1.3.6无广告纯净版是一款“小而全”的实用工具APP,体积小、功能全、无广告、免费使用,不管是日常应急、学习办公,还是创意处理,都能满足需求,Android用户值得一试! -
秒解再续前缘主题百度统计 “没有当前站点”:域名适配优化教程 秒解joe再续前缘百度统计“没有当前站点”:域名适配优化指南 很多使用joe再续前缘的站长,在百度统计配置中都会踩一个坑——明明API密钥、站点信息都填对了,前端却始终显示“没有当前站点”,导致统计数据无法正常加载。其实这不是配置问题,而是主题默认的域名匹配逻辑过于严格,今天就用一篇结构化教程,带大家一步到位解决问题! mjw77r4q.png图片 一、问题直击:你是否遇到这些现象? 主题后台已完整填写百度统计API的access_token、refresh_token、client_id等信息; 百度统计后台已添加当前站点,且状态正常; 前端页面统计区域显示“没有当前站点”,无任何统计数据展示; 排查后发现,百度统计API能正常返回站点列表,但主题无法匹配到当前域名。 二、问题根源:域名匹配逻辑的“严格性”陷阱 joe再续前缘中🐔🐔航写的默认的百度统计代码中,域名匹配采用“完全字符一致”规则,但实际场景中很容易出现格式差异: 百度统计API返回域名:www.xxx.com,主题JOE_DOMAIN常量:xxx.com; 百度统计API返回域名:http://xxx.com,主题JOE_DOMAIN常量:https://xxx.com; 域名大小写差异(如XXX.com与xxx.com)、端口号冗余等。 这些细微格式差异,会让主题代码判定“无匹配站点”,最终返回错误提示。核心需求是:让域名匹配具备“容错性”,忽略无关格式差异。 三、解决方案:3步替换优化代码 3.1 准备工作:明确文件路径 操作前先确认文件位置,避免找错文件: 服务器环境:宝塔面板(可视化操作更高效); 核心路径:网站根目录 → usr/themes/joe/(若主题文件夹重命名,对应修改); 目标文件:通常为 core/function.php 或 api.php(含“没有当前站点”文本的文件)。 3.2 第一步:定位目标代码块 登录宝塔面板,进入网站根目录,导航至 usr/themes/joe/; 点击文件管理器右上角“搜索”,输入关键词“没有当前站点”; 搜索结果中打开对应文件,找到 public static function baiduStatistic($self) 方法——该方法即为百度统计核心逻辑,从方法定义到结束大括号 } 为完整代码块。 3.3 第二步:替换为优化后代码 将以下优化后的代码,完整替换原 baiduStatistic 方法(删除原有代码,粘贴新代码): // 百度统计展示 public static function baiduStatistic($self) { $normalizeDomain = function ($domain) { $domain = preg_replace('/^https?:\/\//', '', $domain); $domain = preg_replace('/^www\./', '', $domain); return strtolower(trim($domain)); }; $statistics_config = \joe\baidu_statistic_config(); if (!is_array($statistics_config)) { return (array('access_token' => 'off')); } if (empty($statistics_config['access_token'])) { return (array('access_token' => 'off')); } $baidu_list = function () use ($statistics_config, $self) { $url = 'https://openapi.baidu.com/rest/2.0/tongji/config/getSiteList?access_token=' . $statistics_config['access_token']; $data = json_decode(file_get_contents($url), true); if (isset($data['error_code'])) { if ($data['error_code'] == 111) { $refresh_token = \network\http\get('http://openapi.baidu.com/oauth/2.0/token', [ 'grant_type' => 'refresh_token', 'refresh_token' => $statistics_config['refresh_token'], 'client_id' => $statistics_config['client_id'], 'client_secret' => $statistics_config['client_secret'] ])->toArray(); if (is_array($refresh_token)) { $theme_options = self::$options->__get('theme:' . THEME_NAME); if (empty($theme_options)) return (['message' => '请更新您的 access_token']); $backup_field = 'theme:' . THEME_NAME . '_backup'; $backup = Db::name('options')->where('name', $backup_field)->find(); if ($backup) { Db::name('options')->where('name', $backup_field)->update(['value' => $theme_options]); } else { Db::name('options')->where('name', $backup_field)->insert(['user' => '0', 'name' => $backup_field, 'value' => $theme_options]); } $theme_options = unserialize($theme_options); $theme_options['baidu_statistics'] = trim($refresh_token['access_token']) . "\r\n" . trim($refresh_token['refresh_token']) . "\r\n" . $statistics_config['client_id'] . "\r\n" . $statistics_config['client_secret']; $options_update = Db::name('options')->where('name', 'theme:' . THEME_NAME)->update(['value' => serialize($theme_options)]); if ($options_update) { $statistics_config['access_token'] = $refresh_token['access_token']; $new_url = 'https://openapi.baidu.com/rest/2.0/tongji/config/getSiteList?access_token=' . $statistics_config['access_token']; $new_data = json_decode(file_get_contents($new_url), true); return $new_data['list'] ?? []; } else { return ['message' => 'access_token 更新失败!']; } } else { return ['message' => '请更新您的 access_token']; } } return $data; } return $data['list']; }; $web_metrics = function ($site_id, $start_date, $end_date) use ($statistics_config) { $access_token = $statistics_config['access_token']; $url = "https://openapi.baidu.com/rest/2.0/tongji/report/getData?access_token=$access_token&site_id=$site_id&method=trend/time/a&start_date=$start_date&end_date=$end_date&metrics=avg_visit_time,ip_count,pv_count,&gran=day"; $data = \network\http\post($url)->toArray(); if (is_array($data)) { $data = $data['result']['sum'][0]; } else { $data = 0; } return $data; }; $list = $baidu_list(); if (!is_array($list)) { return $list; } for ($i = 0; $i < count($list); $i++) { if ($normalizeDomain($list[$i]['domain']) === $normalizeDomain(JOE_DOMAIN)) { $list = $list[$i]; break; } } if (is_array($list) && isset($list['domain'])) { $today = $web_metrics($list['site_id'], date('Ymd'), date('Ymd')); $yesterday = $web_metrics($list['site_id'], date('Ymd', strtotime("-1 days")), date('Ymd', strtotime("-1 days"))); $moon = $web_metrics($list['site_id'], date('Ym') . '01', date('Ymd')); $data = [ 'code' => 200, 'today' => $today, 'yesterday' => $yesterday, 'month' => $moon ]; return ($data); } else { return ['message' => '没有当前站点']; } }3.4 第三步:保存生效 点击文件编辑器右上角“保存”,清空浏览器缓存(Ctrl+Shift+Del),重新访问网站前端——“没有当前站点”提示消失,统计数据正常加载! mjw78h99.png图片 四、核心修改解析:域名标准化适配 优化代码的核心是新增“域名标准化”逻辑,让不同格式的域名统一规则后再匹配,关键代码如下: $normalizeDomain = function ($domain) { $domain = preg_replace('/^https?:\/\//', '', $domain); // 去除http/https协议头 $domain = preg_replace('/^www\./', '', $domain); // 去除www前缀 return strtolower(trim($domain)); // 转为小写+去除空格 }; 原逻辑:$list[$i]['domain'] == JOE_DOMAIN(完全字符匹配); 新逻辑:$normalizeDomain($list[$i]['domain']) === $normalizeDomain(JOE_DOMAIN)(标准化后匹配)。 示例:无论原域名是www.xxx.com“https://XXX.com”还是xxx.com:80,都会被标准化为xxx.com,确保匹配成功。 此外,代码还优化了access_token刷新后的逻辑——刷新成功后自动用新token重新获取站点列表,无需手动刷新页面,流程更顺畅。 五、常见问题排查 5.1 替换后仍显示“没有当前站点” 检查JOE_DOMAIN常量是否定义:需确保主题配置中已正确设置该常量,且不为空; 核实百度统计站点:登录百度统计后台,确认当前站点已添加,且域名与标准化后的JOE_DOMAIN一致; 检查文件路径:确认修改的是“含‘没有当前站点’文本”的目标文件,而非其他同名文件。 5.2 替换后出现语法错误 确保代码完整复制:未遗漏大括号、分号等语法符号; 检查PHP版本:确保服务器PHP版本≥8.0(joe再续前缘最低要求),避免语法兼容问题。 5.3 access_token频繁失效 核实refresh_token有效性:百度统计refresh_token有效期较长,若失效需重新申请API密钥; 检查client_id/client_secret:确保与百度统计开放平台配置一致,无拼写错误。 六、总结 joe再续前缘百度统计“没有当前站点”的问题,本质是域名格式匹配的“容错性不足”。通过新增域名标准化逻辑,能快速解决不同格式域名的匹配问题,且不影响原有统计功能和API交互流程。 整个操作仅需3步:定位文件→替换代码→保存生效,无需复杂配置,新手也能轻松完成。如果在操作中遇到其他问题,欢迎在评论区留言讨论~ -
PyQt5布局管理器进阶:网格布局与表单布局(附实战代码) 第6篇:PyQt5布局管理器进阶:网格布局与表单布局(完整代码) mjw558rv.png图片 哈喽~ 欢迎来到PyQt5系列的第6篇!上一章我们通过“简易文本编辑器”实战,巩固了线性布局(QVBoxLayout/QHBoxLayout)的用法。但在实际开发中,很多复杂界面(比如计算器、用户信息表单、数据展示表格)无法只用线性布局满足——要么控件排列混乱,要么自适应效果差。今天我们就来学习两种进阶布局管理器:网格布局(QGridLayout)和表单布局(QFormLayout),彻底解决复杂界面的排版难题! 一、先明确:进阶布局的核心作用 在学习具体布局前,先搞清楚两种布局的适用场景,避免用错地方: 网格布局(QGridLayout):控件按“行×列”的网格排列,适合需要精准控制控件位置的场景(如计算器按钮、表格数据展示);支持控件跨多行/多列,灵活性极高; 表单布局(QFormLayout):专门用于“标签+输入框”的表单场景(如用户注册/登录表单、信息填写窗口),自动对齐标签和输入框,界面规整且开发高效。 核心优势:两种布局都支持自适应——窗口缩放时,控件会按预设规则自动调整大小和位置,无需手动计算坐标。 二、网格布局(QGridLayout)详解:从基础到实战 网格布局的核心逻辑是“划分网格、给控件分配行和列”,比如将界面划分为3行3列,每个控件占1个“格子”,也可以让控件占2行1列(跨行吗)、1行2列(跨列)。 1. 网格布局基础用法(完整代码) 先实现一个简单的3×3网格,放置9个按钮,演示基础的行、列分配: import sys from PyQt5.QtWidgets import ( QApplication, QWidget, QPushButton, QGridLayout, QLabel ) from PyQt5.QtCore import Qt class GridLayoutDemo(QWidget): def __init__(self): super().__init__() self.init_ui() def init_ui(self): self.setWindowTitle("QGridLayout网格布局基础演示") self.resize(400, 300) # 1. 创建网格布局实例 grid_layout = QGridLayout() # 设置控件间距(格子之间的距离) grid_layout.setSpacing(10) # 设置边距(布局与窗口边缘的距离) grid_layout.setContentsMargins(20, 20, 20, 20) # 2. 创建控件并添加到网格布局 # 核心方法:addWidget(控件, 行号, 列号, 占用行数, 占用列数) # 行号、列号从0开始;占用行数/列数默认是1(可不写) for i in range(3): # 行:0、1、2 for j in range(3): # 列:0、1、2 btn = QPushButton(f"按钮({i},{j})") # 添加到网格的(i,j)位置,占1行1列 grid_layout.addWidget(btn, i, j) # 3. 额外添加一个跨列控件(占1行2列) cross_col_btn = QPushButton("跨2列按钮") grid_layout.addWidget(cross_col_btn, 3, 0, 1, 2) # 第4行(索引3),第0列,占1行2列 # 4. 额外添加一个跨行控件(占2行1列) cross_row_btn = QPushButton("跨2行按钮") grid_layout.addWidget(cross_row_btn, 0, 3, 2, 1) # 第0行,第4列(索引3),占2行1列 # 5. 将布局绑定到窗口 self.setLayout(grid_layout) if __name__ == "__main__": app = QApplication(sys.argv) window = GridLayoutDemo() window.show() sys.exit(app.exec_())mjw55cag.png图片 2. 网格布局关键方法解析 网格布局的核心是addWidget()方法,参数含义必须记牢: addWidget(控件, row, column, rowSpan, columnSpan) # row:控件所在的行号(从0开始) # column:控件所在的列号(从0开始) # rowSpan:控件占用的行数(默认1,即不跨行) # columnSpan:控件占用的列数(默认1,即不跨列)其他常用方法: setSpacing(像素值):设置相邻控件之间的间距,避免控件挤在一起; setContentsMargins(左, 上, 右, 下):设置布局与窗口边缘的距离,提升界面美观度; setRowStretch(行号, 拉伸系数):设置某一行的拉伸权重(窗口缩放时,拉伸系数大的行占更多空间); setColumnStretch(列号, 拉伸系数):设置某一列的拉伸权重,同理。 3. 网格布局实战:简易计算器界面(核心场景) 计算器是网格布局的典型应用——按钮按固定网格排列,部分按钮(如“0”“=”)跨列。我们实现一个简易计算器的界面(含输入框+按钮区): import sys from PyQt5.QtWidgets import ( QApplication, QWidget, QPushButton, QGridLayout, QLineEdit ) from PyQt5.QtCore import Qt class SimpleCalculator(QWidget): def __init__(self): super().__init__() self.init_ui() def init_ui(self): self.setWindowTitle("简易计算器(网格布局实战)") self.resize(350, 400) # 1. 创建主布局(垂直布局:输入框在上,按钮区在下) main_layout = QGridLayout() main_layout.setSpacing(10) main_layout.setContentsMargins(15, 15, 15, 15) # 2. 创建输入框(占1行4列) self.input_edit = QLineEdit() self.input_edit.setAlignment(Qt.AlignRight) # 文本右对齐(符合计算器习惯) self.input_edit.setStyleSheet("font-size: 20px; padding: 10px;") self.input_edit.setReadOnly(True) # 输入框只读,通过按钮输入 main_layout.addWidget(self.input_edit, 0, 0, 1, 4) # 第0行,第0列,占1行4列 # 3. 定义计算器按钮文本(按网格顺序排列) btn_texts = [ '7', '8', '9', '/', '4', '5', '6', '*', '1', '2', '3', '-', '0', '.', '=', '+', 'C' # 清空按钮 ] # 4. 给按钮分配行和列,添加到网格布局 row = 1 # 从第1行开始(第0行是输入框) col = 0 for text in btn_texts: btn = QPushButton(text) btn.setStyleSheet("font-size: 16px; padding: 15px;") # 特殊处理:0按钮跨2列,C按钮跨2列 if text == '0': main_layout.addWidget(btn, row, col, 1, 2) # 占1行2列 col += 2 # 列号+2(跳过一个格子) elif text == 'C': main_layout.addWidget(btn, row, col, 1, 2) # 占1行2列 col += 2 else: main_layout.addWidget(btn, row, col) # 默认占1行1列 col += 1 # 每4列换行(计算器是4列按钮) if col >= 4: col = 0 row += 1 # 5. 绑定布局到窗口 self.setLayout(main_layout) # 6. 绑定按钮点击信号(简单演示:点击按钮显示文本到输入框) for i in range(main_layout.count()): widget = main_layout.itemAt(i).widget() if isinstance(widget, QPushButton): widget.clicked.connect(self.on_btn_click) def on_btn_click(self): """按钮点击槽函数:将按钮文本显示到输入框""" sender = self.sender() text = sender.text() if text == 'C': # 清空输入框 self.input_edit.clear() elif text == '=': # 简单计算(实际项目需处理异常,此处简化) try: result = eval(self.input_edit.text()) self.input_edit.setText(str(result)) except: self.input_edit.setText("错误") else: # 拼接文本 current_text = self.input_edit.text() self.input_edit.setText(current_text + text) if __name__ == "__main__": app = QApplication(sys.argv) calculator = SimpleCalculator() calculator.show() sys.exit(app.exec_())4. 计算器界面亮点 用网格布局精准还原计算器的按钮排列,“0”和“C”按钮跨列,符合实际计算器的交互习惯; 结合垂直布局的思路,将输入框和按钮区整合,界面层次清晰; 实现了基础的计算逻辑(数字拼接、清空、结果计算),信号与槽绑定简洁高效。 三、表单布局(QFormLayout)详解:高效实现表单界面 表单布局是“标签+输入框”的专用布局,无需手动调整对齐方式——它会自动将标签放在左侧、输入控件放在右侧,且所有标签和输入框分别对齐,开发效率极高。 1. 表单布局基础用法(完整代码) 实现一个简单的用户注册表单,包含“用户名、密码、邮箱、电话”四个字段: import sys from PyQt5.QtWidgets import ( QApplication, QWidget, QLabel, QLineEdit, QPushButton, QFormLayout, QVBoxLayout, QComboBox ) from PyQt5.QtCore import Qt class FormLayoutDemo(QWidget): def __init__(self): super().__init__() self.init_ui() def init_ui(self): self.setWindowTitle("QFormLayout表单布局基础演示") self.resize(400, 300) # 1. 创建主布局(垂直布局:表单在上,按钮在下) main_layout = QVBoxLayout() main_layout.setSpacing(20) main_layout.setContentsMargins(30, 30, 30, 30) # 2. 创建表单布局实例 form_layout = QFormLayout() form_layout.setSpacing(15) # 标签与输入框、行与行之间的间距 # 3. 创建标签和输入控件,添加到表单布局 # 核心方法:addRow(标签文本/标签控件, 输入控件) # 方式1:直接传标签文本(自动生成QLabel) form_layout.addRow("用户名:", QLineEdit()) # 方式2:传QLabel控件(可自定义标签样式) pwd_label = QLabel("密码:") pwd_label.setStyleSheet("color: #e74c3c;") pwd_edit = QLineEdit() pwd_edit.setEchoMode(QLineEdit.Password) # 密码隐藏 form_layout.addRow(pwd_label, pwd_edit) # 方式3:输入控件可以是其他类型(如下拉框) form_layout.addRow("性别:", QComboBox()) # 方式4:添加提示标签(跨两列) tip_label = QLabel("* 带星号的为必填项") tip_label.setStyleSheet("color: #95a5a6; font-size: 12px;") form_layout.addRow(tip_label) # 无输入控件时,标签跨两列 # 4. 调整标签对齐方式(默认左对齐,可改为右对齐) form_layout.setLabelAlignment(Qt.AlignRight) # 5. 创建提交按钮 submit_btn = QPushButton("提交表单") submit_btn.setStyleSheet("background-color: #3498db; color: white; padding: 8px;") # 6. 将表单布局和按钮添加到主布局 main_layout.addLayout(form_layout) main_layout.addWidget(submit_btn, alignment=Qt.AlignCenter) # 7. 绑定布局到窗口 self.setLayout(main_layout) if __name__ == "__main__": app = QApplication(sys.argv) window = FormLayoutDemo() window.show() sys.exit(app.exec_())2. 表单布局关键方法解析 addRow(标签, 输入控件):核心方法,添加一行表单;标签可以是字符串(自动生成QLabel)或QLabel实例,输入控件可以是QLineEdit、QComboBox等任意交互控件; setLabelAlignment(对齐方式):设置标签的对齐方式(如Qt.AlignRight让标签右对齐,与输入框间距更紧凑); setSpacing(像素值):设置“标签与输入框之间”和“相邻行之间”的间距; setFieldGrowthPolicy(策略):设置输入控件的拉伸策略(如QFormLayout.ExpandingFieldsGrow让输入控件随窗口缩放而拉伸)。 3. 表单布局实战:完整用户信息登记表单 整合表单布局和之前学的控件,实现一个完整的用户信息登记表单,包含输入框、下拉框、复选框,添加表单验证逻辑: import sys from PyQt5.QtWidgets import ( QApplication, QWidget, QLabel, QLineEdit, QPushButton, QFormLayout, QVBoxLayout, QComboBox, QCheckBox, QMessageBox ) from PyQt5.QtCore import Qt class UserInfoForm(QWidget): def __init__(self): super().__init__() self.init_ui() def init_ui(self): self.setWindowTitle("用户信息登记表单(表单布局实战)") self.resize(450, 350) self.setStyleSheet("font-size: 14px; color: #2c3e50;") # 1. 主布局 main_layout = QVBoxLayout() main_layout.setSpacing(20) main_layout.setContentsMargins(30, 30, 30, 30) # 2. 表单布局 form_layout = QFormLayout() form_layout.setSpacing(15) form_layout.setLabelAlignment(Qt.AlignRight) # 设置输入控件拉伸(随窗口缩放) form_layout.setFieldGrowthPolicy(QFormLayout.ExpandingFieldsGrow) # 3. 表单控件初始化 self.user_edit = QLineEdit() self.user_edit.setPlaceholderText("请输入用户名(3-10个字符)") self.pwd_edit = QLineEdit() self.pwd_edit.setEchoMode(QLineEdit.Password) self.pwd_edit.setPlaceholderText("请输入密码(6-16个字符)") self.email_edit = QLineEdit() self.email_edit.setPlaceholderText("请输入邮箱(如xxx@xxx.com)") self.gender_combo = QComboBox() self.gender_combo.addItems(["男", "女", "保密"]) self.phone_edit = QLineEdit() self.phone_edit.setPlaceholderText("请输入手机号(11位数字)") # 4. 添加表单行 form_layout.addRow("用户名*:", self.user_edit) form_layout.addRow("密码*:", self.pwd_edit) form_layout.addRow("邮箱*:", self.email_edit) form_layout.addRow("性别:", self.gender_combo) form_layout.addRow("手机号:", self.phone_edit) # 同意条款复选框(跨两列) self.agree_check = QCheckBox("我已阅读并同意《用户服务条款》") form_layout.addRow(self.agree_check) # 5. 提交按钮 self.submit_btn = QPushButton("提交信息") self.submit_btn.setStyleSheet(""" QPushButton { background-color: #27ae60; color: white; padding: 10px; border: none; border-radius: 4px; } QPushButton:hover { background-color: #219653; } """) # 6. 结果显示标签 self.result_label = QLabel("") self.result_label.setAlignment(Qt.AlignCenter) # 7. 添加到主布局 main_layout.addLayout(form_layout) main_layout.addWidget(self.submit_btn, alignment=Qt.AlignCenter) main_layout.addWidget(self.result_label) # 8. 绑定布局和信号 self.setLayout(main_layout) self.submit_btn.clicked.connect(self.check_form) def check_form(self): """表单验证逻辑:检查必填项、格式正确性""" # 1. 获取表单内容 username = self.user_edit.text().strip() password = self.pwd_edit.text().strip() email = self.email_edit.text().strip() gender = self.gender_combo.currentText() phone = self.phone_edit.text().strip() # 2. 验证必填项 if not username: QMessageBox.warning(self, "验证失败", "用户名不能为空!") return if not password: QMessageBox.warning(self, "验证失败", "密码不能为空!") return if not email: QMessageBox.warning(self, "验证失败", "邮箱不能为空!") return if not self.agree_check.isChecked(): QMessageBox.warning(self, "验证失败", "请同意用户服务条款!") return # 3. 验证格式(简化版) if len(username) < 3 or len(username) > 10: QMessageBox.warning(self, "验证失败", "用户名长度需在3-10个字符之间!") return if len(password) < 6 or len(password) > 16: QMessageBox.warning(self, "验证失败", "密码长度需在6-16个字符之间!") return if "@" not in email: QMessageBox.warning(self, "验证失败", "邮箱格式不正确(需包含@)!") return if phone and len(phone) != 11: QMessageBox.warning(self, "验证失败", "手机号需为11位数字!") return # 4. 验证通过,显示结果 result = f""" 信息提交成功! 用户名:{username} 性别:{gender} 邮箱:{email} 手机号:{phone if phone else "未填写"} """ self.result_label.setText(result) self.result_label.setStyleSheet("color: #27ae60;") if __name__ == "__main__": app = QApplication(sys.argv) form = UserInfoForm() form.show() sys.exit(app.exec_())5. 实战表单亮点 用表单布局快速实现规整的表单界面,标签右对齐,输入框自适应拉伸,开发效率高; 添加了完整的表单验证逻辑(必填项检查、格式验证),用QMessageBox弹出提示,提升用户体验; 结合了多种控件(输入框、下拉框、复选框),覆盖实际表单的常见场景; 美化了按钮样式(悬停效果、圆角),界面更美观。 四、布局嵌套技巧:复杂界面的核心思路 实际开发中,很少用单一布局完成复杂界面,而是通过“布局嵌套”组合使用——比如“主布局(垂直)”包含“表单布局”和“网格布局”,再搭配“水平布局”排列按钮。 嵌套核心原则: 先划分界面大区域(如“顶部标题区、中间内容区、底部按钮区”),用主布局(垂直/水平)管理; 每个小区域内部,根据控件类型选择合适的子布局(网格/表单/线性); 用addLayout()方法将子布局添加到主布局,实现层次化管理。 五、常见问题排查 问题1:网格布局控件重叠/位置错乱 → 解决:检查行号、列号是否正确,避免多个控件分配到同一个格子;跨行列时注意rowSpan和columnSpan的数值; 问题2:表单布局标签和输入框不对齐 → 解决:用setLabelAlignment()统一标签对齐方式;避免手动设置输入控件的固定宽度(让布局自动适配); 问题3:窗口缩放时控件不拉伸 → 解决:给布局添加拉伸系数(setRowStretch/setColumnStretch),或设置输入控件的拉伸策略(如表单布局的setFieldGrowthPolicy); 问题4:布局嵌套后界面混乱 → 解决:先画界面草图,明确大区域和子区域的划分;给每个布局添加setSpacing和setContentsMargins,避免间距混乱。 总结 本章我们掌握了两种进阶布局管理器的核心用法: 网格布局(QGridLayout):适合“行×列”的规整排列场景(如计算器),支持控件跨行列,灵活性极高; 表单布局(QFormLayout):专门用于“标签+输入框”的表单场景,自动对齐,开发效率高; 布局嵌套是复杂界面的核心思路,先划分大区域,再用子布局管理小区域。 下一章我们将学习PyQt5的文本与表格控件(QTextEdit与QTableWidget),进一步拓展界面的功能边界。如果在布局实操中遇到问题,或者有复杂界面的排版需求,欢迎在评论区留言讨论~ -
免费分享石大导航网站HTML源码 - 学生专属简洁校园导航工具 石大导航网站HTML源码:免费学生专属简洁导航资源分享 给大家免费分享一款专为学生群体打造的实用导航资源——HTML简洁大气石大导航网站源码!无需付费,石大学子、学生群体及需要简洁导航的用户都能免费获取,界面清爽简约,贴合日常上网与学习需求,不管是快速访问校园官网、学习平台,还是常用工具网站,都能高效直达,妥妥的轻量化便捷导航工具! mjw50t1c.png图片 一、核心资源信息 核心定位(资源核心价值):专为石大学子定制开发,聚焦校园学习与日常上网场景,整合校园官网、学习平台、工具网站、娱乐平台等各类常用网址,分类清晰直观,解决网址查找繁琐的问题,提升上网与学习效率;同时兼顾通用需求,普通用户也可按需修改使用。 技术与部署(资源实用性):基于HTML+JavaScript开发,属于纯静态源码,无需数据库支持,部署门槛极低,上传服务器即可使用,适配各类主机空间;界面简洁无冗余,加载速度快,无需复杂配置,学生或初学者都能轻松上手操作。 注意事项(资源使用提醒):源码集成的天气插件已无法使用,需在HTML代码底部更换为其他天气插件,避免影响网站打开速度与使用体验。 二、核心功能与特色(免费解锁清爽导航体验) 精准网址分类:预设贴合学生需求的网址分类,包括常用(石河子大学官网、各学院官网、教务处官网、一站式服务平台等校园核心网址)、学习(智慧树、雨课堂、U校园、优慕课、itest等学习平台)、工具与娱乐(QQ音乐、网易云音乐、抖音、哔哩哔哩等),无需手动收藏,快速定位目标网站。 实用附加功能:页面内置日历显示,方便查看日期;支持关键词搜索功能,若未输入关键词,将自动跳转到自定义网址,满足个性化使用需求。 界面与体验优势:整体设计简洁大气、清爽简约,无冗余信息干扰,视觉体验舒适;操作逻辑简单,无需学习成本,学生群体可直接上手使用,提升上网浏览心情。 三、资源适用场景(免费资源适配多需求) 这款免费分享的源码用途明确,适配场景集中: 石大学子:作为日常上网与学习的专属导航,快速访问校园官网、学习平台,省去记忆或查找网址的麻烦,提升学习与办事效率。 其他学生群体:可根据自身学校的常用网址,修改替换预设链接,打造专属校园导航网站,适配不同高校学生的需求。 个人用户:喜欢简洁导航风格的用户,可用于整理个人常用网址,打造干净无广告的私人导航页面。 初学者:作为HTML+JavaScript静态网站开发的学习案例,熟悉基础功能集成(日历、搜索跳转)与页面布局,积累建站经验。 资源获取 免费分享石大导航网站HTML源码 - 学生专属简洁校园导航工具 下载地址:https://pan.quark.cn/s/fbc10fe3f6eb 提取码: 免费又实用,针对性强且部署简单,尤其适合学生群体使用,只需替换失效的天气插件,就能快速拥有专属简洁导航平台,值得获取体验! -
免费分享Webstack纯静态网址导航源码 - HTML响应式导航网站搭建工具 Webstack纯静态网址导航系统HTML源码:免费开源导航资源分享 给大家免费分享一款实用的网址导航类资源——Webstack纯静态大气网址导航系统HTML源码!无需付费,个人用户、初学者或需要快速搭建导航网站的使用者都能免费获取,不用复杂配置,上传服务器即可使用,不管是整理常用网址、搭建个人导航平台,还是做小型工具导航站点,都能轻松满足需求,妥妥的轻量化高效资源! mjw4sngr.png图片 一、核心资源信息 核心定位(资源核心价值):源自WordPress主题的纯静态网址导航系统,专注提供清晰的网址分类与简洁大气的前台界面,整合一言API和和风天气API,额外补充实用信息(需替换为个人API密钥,避免共享密钥导致服务中断),打造个性化导航体验。 技术与部署(资源实用性):基于HTML开发,无需数据库支持,属于绿色源码,适用于各类主机空间;无复杂后台管理系统,上传到服务器就能直接运行,部署门槛极低,初学者也能快速上手;采用响应式设计,自动适配桌面电脑、平板电脑、智能手机等不同设备屏幕尺寸,兼容IE6-IE9、Firefox、Chrome、Opera、Safari等多种浏览器,使用无兼容顾虑。 二、核心功能与特色(免费解锁便捷导航体验) (一)核心优势 响应式适配:自动匹配不同设备屏幕,不管是电脑还是手机访问,都能保持界面美观、操作便捷,满足多终端使用需求。 部署零门槛:纯静态架构,无需配置数据库和复杂环境,上传服务器即可启用,省去繁琐安装步骤,节省时间成本。 自定义性强:网页内容可通过记事本、写字板或网页编辑器直接修改,无需专业编程知识,就能轻松定制网址分类、网站样式和展示内容,适配个人或小型需求。 轻量化无负担:源码体积小巧,不占用过多主机空间,运行流畅,无惧网络攻击,稳定性有保障。 实用API整合:内置一言API和和风天气API,能在导航页面展示随机语录和天气信息,丰富网站功能,提升用户体验。 (二)存在不足 代码结构杂乱:因源自WordPress主题扒取,代码缺乏规整,需要先美化整理后,才方便后续修改和二次开发。 管理效率较低:纯静态页面无后台管理系统,后续添加、修改网址或更新内容时,需手动编辑文件,批量操作不便,不适合大规模网址管理场景。 三、资源适用场景(免费资源适配多需求) 这款免费分享的源码用途十分广泛: 个人用户:搭建专属私人导航网站,整理常用网址(如工具类、影视类、学习类),告别浏览器收藏夹杂乱,快速访问目标网站。 初学者:作为HTML静态网站开发学习案例,熟悉响应式设计、API调用等基础技能,提升实操能力;同时体验零门槛部署流程,积累建站经验。 小型需求场景:搭建小型工具导航、兴趣圈层导航(如影视资源导航、设计工具导航),满足小范围人群的集中访问需求,无需投入过多技术和服务器成本。 临时展示站点:快速搭建临时网址汇总页面,用于活动推广、团队内部资源共享等场景,部署快、维护简单。 源码获取 免费分享Webstack纯静态网址导航源码 - HTML响应式导航网站搭建工具 下载地址:https://pan.quark.cn/s/84426ecdd655 提取码: 免费又实用,轻量化部署且自定义灵活,适合追求简单高效的导航需求,若无需大规模管理,这款Webstack纯静态导航源码绝对值得入手! -
雨云rainyun.com推荐 - 专属优惠码 MzM2MjI4 高性价比云服务器 实测推荐!雨云rainyun.com:高性价比云服务+专属优惠码,开发者/创业者必入 作为常年和服务器、云产品打交道的技术人,今天给大家安利一款亲测好用的云计算平台——雨云(rainyun.com),不仅产品矩阵齐全、性能稳定,还带来了专属优惠码和直达链接,新老用户都能薅福利,不管是搭建网站、部署源码,还是运行游戏服务器,都能满足需求! mjv8cgbw.png图片 一、雨云核心优势:为什么值得选? 产品丰富,一站式覆盖全场景 雨云的云产品完全能满足从个人开发者到企业的多元需求:云服务器性能强劲,支持弹性扩展,适配源码部署、网站搭建;游戏云(VPS/面板)低延迟、高稳定,玩游戏、开私服都流畅;还有裸金属物理机、显卡/网吧云、对象存储等,甚至包含域名注册、备案、免费SSL证书服务,不用跨平台折腾,一站式搞定所有云计算需求。 稳定靠谱,资质齐全有保障 作为正规云计算平台,雨云拥有《中华人民共和国增值电信业务经营许可证》(B1-20231485)、粤ICP备19052839号、粤公网安备44010302111123等完整资质,平台系统还取得了软件著作权(登记号:2023SR0336952),不用担心服务合规问题。节点监控实时可见,运行过程中几乎无宕机,技术团队响应及时,后续使用更放心。 优惠活动多,性价比拉满 除了日常的拼团优惠,雨云还推出了推广合伙人、雨创计划、润雨赞助计划等福利活动,降低使用成本。现在通过专属链接注册,再使用优惠码,还能额外享受折扣,对比同类型平台,价格优势明显,学生党、个人开发者也能轻松负担。 二、专属福利:优惠码+直达链接,省钱快人一步 专属直达链接:雨云 独家优惠码:MzM2MjI4 使用方式:打开直达链接注册雨云账号,选择心仪的云产品(云服务器、游戏云等),下单时输入优惠码MzM2MjI4,即可享受专属折扣,新用户首购更划算! 三、适用人群&使用场景推荐 开发者:部署开源源码、搭建测试环境,云服务器弹性扩展,配合免费SSL证书,快速上线个人项目; 游戏玩家/腐竹:游戏云(VPS/面板)低延迟、高带宽,支持各类游戏服务器搭建,多人联机不卡顿; 创业者/企业:裸金属物理机、对象存储满足高负载需求,域名备案、企业级安全防护一站式配齐,降低运营成本; 自媒体/站长:搭建个人博客、商业网站,稳定的节点和售后保障,确保网站全年正常访问。 四、额外加分项:细节拉满的用户体验 官方文档详细,新手也能快速上手部署,遇到问题还能通过QQ群、论坛等交流社区求助,用户和官方技术人员都会热心解答; 支持节点监控,实时查看服务器状态,还有完善的服务条款、退款政策,权益有保障; 定期更新产品功能和优惠活动,近期动态及时公示,长期使用能持续享受新福利。 总结 如果你正在寻找一款“产品全、性能稳、价格香”的云计算平台,雨云绝对值得一试!现在注册,输入优惠码MzM2MjI4,就能解锁专属折扣,不管是个人使用还是企业部署,都能省不少钱~ 亲测靠谱,赶紧冲起来! (提示:优惠活动可能有期限,建议尽早注册使用,有任何问题可联系雨云官方客服咨询~) -
免费分享意象桌面扫码点餐系统源码 - 微信小程序+H5餐饮多端运营解决方案 意象桌面扫码点餐系统源码:免费开源餐饮解决方案,多端适配助力商家高效运营 给大家免费分享一款专为餐饮行业打造的全能型开源资源——意象桌面扫码点餐系统源码!无需付费,个体餐饮商户、连锁品牌、餐饮创业者以及开发者都能免费获取,不管是搭建扫码点餐平台、拓展外卖与自取业务,还是实现会员营销与多门店统一管理,都能一站式满足需求,妥妥的餐饮行业降本增效利器! mjunri92.png图片 一、核心资源信息 核心定位(资源核心价值):聚焦餐饮全业务场景,提供从用户点餐到商家运营的完整闭环解决方案,覆盖扫码点餐、在线外卖、到店自取、提前预约、会员管理、营销推广等核心需求,帮助餐饮商家摆脱传统点餐模式的低效束缚,实现数字化、智能化运营,提升服务效率与客户体验。 技术架构(资源硬核配置):采用前后端分离架构,技术栈先进且成熟稳定,适配各类部署场景—— 后端:基于Spring Boot 3构建核心框架,搭配Spring Security OAuth2权限认证、MyBatis Plus数据访问、Redis缓存优化、JWT安全验证,同时整合Lombok、Hutool等实用工具,大幅提升开发效率与系统性能; 前端:PC端后台管理界面采用Vue3 + Element UI开发,界面清晰、操作便捷;移动端通过uni-app(Vue3)实现,无缝适配微信小程序与H5页面,覆盖用户主流访问场景; 项目结构:模块化划分明确,包含后端Java工程、后台管理前端工程、移动端uni-app工程,代码注释完善、逻辑清晰,便于理解与二次开发。 部署与适配(资源实用优势):支持本地服务器快速部署、云平台部署以及私有化部署,满足不同商家的服务器配置需求;兼容JDK 17、MySQL 8、Redis 6+、Node.js 16+等主流开发环境,搭配IDEA、VSCode、HBuilder等常用开发工具即可快速启动项目;同时支持SaaS多租户架构,既能满足个体商户的单门店运营,也能适配连锁品牌的多门店统一管理需求。 二、核心功能资源(免费解锁餐饮全场景运营能力) (一)用户端功能(微信小程序/H5双端支持) 灵活点餐模式:支持桌面扫码点餐,单人点餐高效便捷,多人协同点餐互不干扰,无需服务员手动记录,减少沟通成本;同时提供外卖配送与到店自取两种选择,用户可根据需求自由切换,外卖模式支持物流信息实时查看,自取模式无需排队等待,提升用餐体验。 丰富商品展示:支持多规格商品(SKU)管理,商品详情页包含图文介绍、价格、库存等信息,分类清晰(如新品推荐、招牌热卖、主食、饮品等),用户可快速找到心仪菜品,下单更直观。 多元支付与订单管理:支持微信支付、余额支付、积分+金额混合支付等多种支付方式,满足不同用户的支付习惯;用户可随时查看历史订单、当前订单状态(待支付、待出单、待收货、已完成等),订单信息一目了然,还能便捷处理退款申请。 完善会员体系:用户可维护个人信息、管理收货地址,查看积分明细与优惠券;积分可用于兑换商品或抵扣订单金额,优惠券支持领取与核销,增强用户粘性与复购意愿;同时提供余额充值功能,支持微信支付充值,方便用户快速下单支付。 提前预约功能:用户可提前预约到店时间,商家提前做好备餐准备,避免到店后长时间等待,提升用餐效率,尤其适合高峰时段用餐需求。 (二)商家后台功能(PC端专属管理) 商品与店铺管理:支持商品添加、编辑、上下架操作,可灵活配置商品规格、分类与图文详情;支持多门店信息维护,连锁品牌可统一管理旗下所有门店,独立设置各门店的商品、价格、配送范围等参数;内置图片素材库,商品图片、轮播图等素材可统一存储与管理,方便快速调用。 订单与桌台管理:实时查看所有订单信息,支持订单状态更新(接单、出单、完成、退款等)、订单打印,对接云打印机可实现小票自动打印,提升出单效率;支持桌号配置、扫码绑定桌台,实时查看桌台占用状态(空闲、已点餐、用餐中、已结账),便于合理安排座位,优化店内运营流程。 会员与营销管理:可设置会员等级、积分规则,查看会员充值记录、消费明细,支持黑名单管理,精准筛选优质客户;提供丰富的营销工具,包括优惠券创建与发放、充值活动配置(如充值送积分、送优惠券),助力商家吸引新客户、留住老客户,提升营业额。 收银与数据管理:内置收银台功能,支持扫码枪、扫码盒子等设备收款,适配线下门店直接收银场景;实时统计今日营业额、订单数量、访客人数、退单数量等核心数据,商家可直观掌握门店运营状况,为经营决策提供数据支持。 微信公众号对接:支持微信公众号关注引导、自定义菜单配置,可向用户推送订单通知、活动公告等消息,增强与用户的互动,提升品牌曝光与用户活跃度。 (三)技术支撑功能(保障系统稳定高效运行) 安全机制:采用JWT认证与OAuth2安全框架,保障用户信息与交易数据的传输安全;严格的权限控制体系,不同角色(管理员、门店操作员等)分配专属权限,避免数据误操作。 性能优化:通过Redis缓存热点数据(如商品信息、会员积分等),减少数据库查询压力,提升系统响应速度,即使高峰时段多用户同时点餐也能保持流畅。 开发便捷:整合Lombok、Hutool等工具简化代码编写,开发环境配置清晰,本地部署流程简单,开发者可快速搭建开发环境,开展二次开发工作。 三、资源特色(免费资源优势拉满) 技术先进且稳定:基于Spring Boot 3、Vue3等主流技术栈构建,架构设计合理,兼容性强、扩展性好,能够适应餐饮行业的业务变化与规模扩张,长期使用无后顾之忧。 多场景全面适配:覆盖扫码点餐、外卖、自取、预约、会员营销、多门店管理等餐饮核心场景,无论是快餐店、饮品店、特色餐厅,还是连锁餐饮品牌,都能精准匹配需求。 开源免费无套路:采用MIT License开源协议,完全开源可商用,无强制保留作者信息或版权信息的要求,商家可直接部署使用,开发者可自由修改、定制功能,大幅降低开发与运营成本。 可定制性极强:代码结构清晰、模块化设计合理,附带完善注释与相关文档,二次开发门槛低,商家可根据自身业务特点添加特色功能(如专属营销活动、定制化支付方式等),开发者可基于源码拓展更多餐饮相关功能,打造个性化解决方案。 运营效率翻倍:通过数字化点餐流程减少人工干预,降低服务员工作量与人为失误;多端协同与实时数据统计让商家运营管理更高效,会员营销工具助力提升用户复购与营业额,全方位为餐饮商家降本增效。 四、资源适用场景(免费资源适配多类需求) 这款免费分享的意象桌面扫码点餐系统源码,适用场景十分广泛: 个体餐饮商户(快餐店、饮品店、小吃店等):快速搭建扫码点餐平台,减少人工点餐压力,提升翻台率;支持外卖与自取业务,拓展销售渠道,增加营收来源。 连锁餐饮品牌:借助SaaS多租户架构实现多门店统一管理,同步商品信息、营销活动,实时监控各门店运营数据,规范品牌运营标准,降低管理成本。 餐饮创业者:无需投入高额资金开发定制系统,直接基于源码快速搭建专属点餐平台,缩短项目上线周期,聚焦核心产品与服务,提升创业成功率。 开发者/技术团队:作为餐饮行业系统开发的参考案例,学习前后端分离架构、多端适配、权限管理等技术实现;或基于源码二次开发,为餐饮客户提供定制化解决方案,提升项目交付效率。 餐饮行业服务商:整合源码功能,为合作餐饮商家提供一站式数字化运营解决方案,涵盖点餐、会员、营销等模块,增强服务竞争力。 下载 下载点餐小程序源码 下载地址:https://pan.quark.cn/s/b8b58d03cbb2 提取码: 免费又实用,功能全面且技术成熟,不管是直接部署使用,还是二次开发定制专属功能,这款意象桌面扫码点餐系统源码都能为餐饮行业从业者带来实实在在的价值,强烈推荐获取体验! -
字节曜博客 2026 元旦快乐!愿技术同行新岁顺意,万事可期 元旦快乐!愿新岁如朝阳,温暖而明亮 元旦的钟声已经敲响,时光的年轮又增添了新的一圈。在这辞旧迎新的时刻,我谨向所有字节曜博客的读者们致以最诚挚的祝福:元旦快乐,万事胜意! mju9a26l.png图片 一、岁序更替:告别与迎接的仪式感 站在2026年的门槛上,我们不禁回望刚刚过去的一年。那些欢笑与泪水,成功与挑战,都已沉淀为生命中宝贵的财富。旧岁已展千重锦,新年再进百尺竿。元旦,不仅仅是一个时间节点,更是一个充满仪式感的新起点,让我们有机会重新审视自己,整理行囊,带着希望与梦想再次出发。 二、新年新愿:多元祝福送给特别的你 1. 愿你如阳光般明媚 新的一年,愿阳光洒满你的每一天,温暖而不刺眼。愿你的笑容如春日般灿烂,烦恼如冰雪般消融。当生活偶尔阴霾,请记得:你本就是自己生命中最耀眼的光芒。 2. 愿你如星辰般璀璨 在追求梦想的道路上,愿你像夜空中的星辰一样,既保持自己独特的光芒,又与周围的世界和谐共处。愿你的努力被看见,付出有回报,在属于自己的领域里闪闪发光。 3. 愿你如流水般从容 面对生活的起伏跌宕,愿你拥有流水般的智慧:遇山绕行,遇石分流,始终保持前进的方向。学会在忙碌中寻找安宁,在挑战中锤炼韧性,在变化中把握机遇。 4. 愿你如大地般厚实 新的一年,愿你拥有坚实的根基和广阔的胸怀。像大地一样,默默耕耘,静待花开;像大地一样,包容万物,涵养生命。愿你的内心充满力量,足以支撑你走过每一段路程。 三、字节同行:技术赋能,共赴新程 作为字节曜博客的编辑,我特别想对所有技术爱好者说:2026年,让我们继续在技术的海洋中探索,在代码的世界里创造。愿我们的每一行代码都能解决实际问题,每一个创新都能带来真实价值,每一次分享都能点亮他人的智慧。 在这个AI与大数据交织的时代,愿我们保持"Always Day 1"的初心,不断学习,持续成长,用技术的力量为世界增添美好。 四、结语:携手同行,未来可期 元旦的意义,不仅在于迎接新的一年,更在于我们对未来的共同期待。愿2026年的每一个日子,都能带给你新的惊喜和成长;愿我们在字节曜博客这个平台上,继续分享知识,交流思想,共同进步。 最后,再次祝愿大家:元旦快乐,阖家幸福,身体安康,万事顺遂! 让我们一起,以饱满的热情迎接充满希望的2026年! -
免费分享bujuan开源播放器 - 安卓第三方网易云音乐轻量工具(跨平台) bujuan开源音乐播放器:安卓端免费第三方网易云工具分享 给大家免费分享一款专注音乐体验的播放器资源——bujuan开源第三方网易云音乐播放器!无需付费,网易云音乐爱好者、开发者都能免费获取,安卓用户可直接下载使用,它去除冗余功能、聚焦核心播放体验,不管是日常听歌,还是开发者学习二次开发,都是性价比超高的优质资源! mju3e9tq.png图片 一、核心资源信息 核心定位(资源核心价值):专为网易云音乐用户打造的第三方播放器,专注核心音乐播放功能,剔除原生APP中不必要的社交、视频等冗余模块,让界面更简洁、操作更流畅,沉浸式享受音乐。 技术与适配(资源实用性):基于Flutter框架开发,具备超强跨平台兼容性,支持Android、iOS、Windows、macOS、Linux五大系统(目前官方仅提供安卓APP下载);项目目录结构清晰,包含多平台支持文件,技术成熟且易扩展。 二、核心功能与特色(免费解锁纯粹音乐体验) 便捷账号登录:支持手机号登录和二维码扫码登录两种方式,直接关联网易云音乐账号,无需额外注册,快速同步个人音乐数据。 核心播放功能:覆盖网易云核心音乐服务,包括每日推荐、私人FM、电台播放、云盘歌曲播放,满足日常听歌的各类需求;还能按歌曲、专辑、歌手精准搜索,快速找到想听的音乐。 个性化推荐:内置智能推荐系统,基于用户听歌习惯推送契合口味的音乐,像私人雷达、歌单推荐等功能,精准捕捉音乐偏好。 多平台统一体验:依托Flutter框架优势,不同系统上的界面风格、操作逻辑保持一致,不管后续切换到iOS、Windows等平台,都能快速适应。 开源可定制:项目代码完全开源,开发者可自由修改、定制功能,或打包适配其他平台,适合作为Flutter开发学习案例,也能二次开发打造专属播放器。 轻量中文友好:体积轻巧不占过多设备内存,中文界面简洁直观,国内用户使用无门槛,上手就能顺畅操作。 三、资源适用场景(免费资源适配多需求) 这款免费分享的播放器资源,用途十分广泛: 网易云音乐爱好者:想摆脱原生APP冗余功能,追求纯粹听歌体验,用它能专注音乐本身,界面干净、操作流畅。 跨平台需求用户:后续计划在iOS、Windows、macOS、Linux等设备上使用统一播放器,可等待官方版本或自行编译,实现多设备音乐体验同步。 开发者:学习Flutter跨平台开发技术,研究音乐播放器的功能实现逻辑;或基于开源代码二次开发,添加个性化功能、定制界面风格。 获取APP bujuan播放器 下载地址:https://pan.quark.cn/s/49a886393fee 提取码: 免费又纯粹,专注音乐体验且支持多平台扩展,不管是普通用户日常听歌,还是开发者学习实践,这款bujuan开源播放器都值得一试! -
免费分享基于ThinkPHP在线证书查询系统源码 - 多端证书管理查询工具 基于ThinkPHP在线证书查询系统源码:免费开源资源分享 给大家免费分享一款实用的证书管理类资源——基于ThinkPHP开发的在线证书查询系统源码!无需付费,教育机构、培训机构或任何需要管理和查询证书信息的组织都能免费获取,不管是搭建官方证书查询平台,还是规范证书数据管理流程,都能轻松满足需求,妥妥的高效管理工具资源! mju39ijg.png图片 一、核心资源信息 核心定位(资源核心价值):专注在线证书查询与管理全需求,支持证书信息快速查询、后台统一管理,解决证书真伪核验、数据规范存储等问题,让用户便捷查询证书详情,组织高效管控证书数据,适配各类需要公开或内部查询证书的场景。 技术与适配(资源实用性):基于ThinkPHP框架开发,采用PHP+MySQL作为核心技术组合,技术成熟稳定,易维护易扩展;采用响应式设计,完美适配PC端和手机端,不同设备访问都能获得良好体验,兼容主流浏览器,使用无门槛。 二、核心功能与特色(免费解锁高效证书管理体验) 证书查询与管理:用户可通过证书编号等相关信息快速查询证书详情,核验真伪;管理员在后台能全面管理证书信息,包括添加、修改、删除等操作,流程简洁高效。 批量数据操作:支持JSON、CSV、Excel等多种格式的数据批量导入和导出,不用逐个录入或整理数据,大幅提升证书数据处理效率,节省人力成本。 权限与数据安全:支持多管理员角色设置,可给不同角色分配专属权限,避免数据误操作或泄露;通过加密传输和严格权限控制,全方位保障证书数据和用户信息安全。 界面与体验优化:前端查询界面和后台管理界面都精心设计,清新简洁,操作直观易懂,新手也能快速上手;特别修复了之前版本中证书照片错位、遮挡证件号码的问题,确保证书信息准确可读。 三、资源适用场景(免费资源适配多需求) 这款免费分享的源码用途十分广泛: 教育机构:用于学生毕业证、资格证书等信息管理,方便学生和用人单位在线查询核验,提升管理规范性。 培训机构:管理培训结业证书、技能证书数据,学员可自行查询证书信息,机构高效维护数据,降低沟通成本。 企业/行业组织:针对内部认证证书、职业资格证书等进行管理,实现证书信息公开查询,提升公信力。 其他组织:任何需要集中管理证书数据、提供在线查询服务的场景,都能直接部署使用或二次开发适配。 源码下载 多端证书管理查询工具 下载地址:https://pan.quark.cn/s/877adf53a2b8 提取码: 免费又实用,功能全面且体验流畅,不管是直接搭建使用,还是根据需求二次开发,这款基于ThinkPHP的在线证书查询系统源码都值得入手! -
免费分享酷瓜云课堂PHP源码 - 开源在线教育网校知识付费系统 酷瓜云课堂PHP源码:免费在线教育开源资源分享 mju2gi6m.png图片 给大家免费分享一款超实用的在线教育类资源——酷瓜云课堂PHP开源免费在线教育系统源码!无需付费,教育机构、企业、有知识分享需求的个人或开发者都能免费获取,不管是搭建网课平台、网校系统,还是做知识付费、企业内部培训平台,都能轻松实现,妥妥的低成本高效解决方案! 一、核心资源信息 核心定位(资源核心价值):专注在线教育全场景需求,提供开源的网课、网校、知识付费一体化系统,支持教学全流程管理——从课程发布、直播授课,到作业布置、考试考核、学习进度跟踪,一站式满足线上教学与培训需求,全功能可免费商用,不用顾虑版权问题。 技术与部署(资源实用性):基于高性能C扩展Phalcon框架开发,遵循GPL-2.0开源协议,运行响应快速且安全可靠;采用容器化部署方式,屏蔽环境差异,不用复杂配置,快速就能搭建起专属在线教育平台,依托MySQL数据库存储数据,技术成熟易维护。 二、核心功能与特色(免费解锁优质教育平台体验) 多端无缝适配:支持PC、H5、微信小程序、安卓和苹果端,学员可随时随地通过不同设备学习,打破时间和空间限制,提升学习便利性与灵活性,覆盖更多用户场景。 安全稳定高性能:依托Phalcon框架的C扩展优势,系统响应迅速,就算多用户同时在线学习、观看直播,也能保持流畅体验;具备完善的数据安全保护机制,保障教学数据和用户隐私安全。 全场景教学支持:教育机构可实现线上教学全流程管理,教师能上传教学资料、直播授课、布置作业与考试;企业可开展线上培训,跟踪员工学习进度并考核;个人可发布课程、提供在线辅导,实现知识变现。 低成本无套路:开源免费且支持商业使用,无需支付高额授权费,大幅降低搭建在线教育平台的成本;容器化部署简化操作,不用专业技术团队也能快速上线,省心省力。 三、资源适用场景(免费资源适配多需求) 这款免费分享的源码用途十分广泛: 教育机构:利用自身师资力量搭建专属网课平台,开展线上教学,实现教学全流程数字化管理,拓展教学边界。 企业单位:搭建内部培训平台,发布培训课程,跟踪员工学习进度并进行考核,结合线下培训形成多元化培训模式。 平台用户:针对积累的粉丝群体,搭建自主运营的知识付费平台,将粉丝转化为付费用户,实现商业转型。 个人用户:凭借专业知识或优质资源,搭建个人知识变现平台,通过发布课程、在线辅导等方式,将知识转化为收益。 资源下载 下载 下载地址:https://pan.quark.cn/s/d5f9dd35f8d3 提取码: 免费又实用,功能全面且部署便捷,不管是机构规模化运营,还是个人小范围分享,这款酷瓜云课堂PHP源码都能满足需求,强烈推荐有在线教育需求的用户获取使用! -
免费分享 PHP 码蚁成绩管理系统源码 - 教育机构学生成绩统计管理工具 PHP码蚁成绩管理系统源码:免费教育类开源资源分享 给大家免费分享一款专为教育机构打造的实用管理资源——PHP码蚁成绩管理系统源码!无需付费,学校、培训机构、老师都能免费获取,不管是优化成绩管理流程、减轻教务工作负担,还是规范学生成绩统计分析,都能轻松满足需求,妥妥的教育行业高效工具资源! mju0trbs.png图片 一、核心资源信息 核心定位(资源核心价值):聚焦教育机构的成绩管理需求,由一线小学教师结合实际工作场景开发,功能设计贴合教学日常——从学生信息维护、考试安排,到成绩录入、统计分析,再到权限管控,一站式解决成绩管理全流程问题,不用再依赖Excel手动统计,大幅提升工作效率。 技术适配(资源实用性):基于PHP开发,采用ThinkPHP框架,前端搭配X-adminV2.2界面,后端负责数据处理与逻辑运算,技术成熟稳定;依托MySQL数据库存储数据,支持常规服务器部署,安装配置流程简单,教育机构IT人员或有基础的老师都能操作。 二、核心功能资源(免费解锁全能管理体验) 完善的基础管理:支持学期、班级、班主任、学科管理,可维护学生、教师、管理员信息,还能设置单位信息、类别管理等系统基础配置,满足不同教育机构的组织架构需求。 灵活的考试与成绩管理:可自定义考试信息,设置各学科满分、优秀、良好、及格分数线及人数占比;能生成学生考试号、试卷标签和成绩采集表,方便考试组织;支持多种成绩录入方式——在线手动录入、表格批量录入、扫码枪快速录入,还能随时修改成绩,操作灵活。 全面的成绩统计分析:能查看成绩列表和多类型图表(柱形图、折线图、雷达图、箱体图等),直观呈现班级、年级成绩分布;可统计单个学生历次成绩,用表格+折线图展示成绩变化趋势;还能自定义统计项目,生成详细成绩报告,助力教学分析与决策。 精准的权限管控:支持教师、学生、管理员不同身份登录,按职务(教研组长、班主任、普通教师)分工分配数据权限,确保成绩数据安全,避免信息泄露;管理员可统一管理角色、权限,规范系统使用流程。 实用的数据保障功能:支持数据备份与恢复,防止意外丢失;可下载成绩列表、成绩条、班级/年级成绩统计表等,方便线下存档或分享;还能设置网页统计结果显示项目,按需展示关键数据。 三、资源特色(免费资源优势突出) 操作简便易上手:界面简洁明了,符合教育工作者使用习惯;优化后的操作流程,三步就能到达核心功能位置,不用复杂学习,老师快速就能熟练使用。 功能贴合教学实际:由一线教师开发,精准命中成绩管理痛点——比如扫码枪录入适配考试后快速登分场景,多图表统计满足教学分析需求,比通用管理系统更实用。 数据安全可靠:具备权限分级、数据加密等安全措施,同时支持数据备份恢复,保障成绩数据的完整性和保密性,教育机构可放心使用。 可扩展性强:基于成熟框架开发,代码结构清晰,教育机构可根据自身需求二次开发,比如添加特色统计项目、适配个性化教学管理流程。 四、资源适用场景(免费工具适配多需求) 这款免费分享的源码用途十分广泛: 中小学:用于班级、年级成绩统一管理,快速完成成绩录入、统计分析,生成成绩单和教学分析报告,减轻教务和老师工作量。 培训机构:针对各类考试(随堂测、阶段考、结业考)进行成绩管理,跟踪学员成绩变化,向家长反馈学习情况。 教研部门:汇总多所学校或多个班级成绩数据,进行跨班级、跨年级对比分析,为教学质量评估提供数据支持。 一线教师:个人管理所带班级成绩,快速统计平均分、优秀率、及格率,分析学生薄弱环节,精准调整教学策略。 资源下载 下载 下载地址:https://pan.quark.cn/s/e46b8a706785 提取码: 免费又实用,功能全面还贴合教育场景,不管是直接部署使用,还是二次开发适配个性化需求,这款PHP码蚁成绩管理系统源码都值得教育行业从业者获取! -
Python 微信自动回复工具 | 带 PyQt5 图形界面 支持 Excel 关键词配置 微信自动回复工具(带PyQt界面) 最近帮朋友处理微信客服消息,重复回复太费时间,干脆写了个带图形界面的自动回复工具。不用记命令,填个Excel路径点按钮就能跑,还能实时看日志,日常用着挺顺手。下面把完整代码和用法贴出来,有需要的可以直接拿去改。 mjr3m247.png图片 先说说要准备的东西 环境:Python 3.8+(版本太高可能和pywin32不兼容) 要装的库:直接复制下面的命令到cmd里跑 pip install pywin32 pandas pyqt5 openpyxlmjr3dd3v.png图片 Excel回复表:建个Excel文件,第一列叫“关键词”,第二列叫“回复内容”,比如这样: 关键词回复内容你好您好~有什么可以帮您?下班时间我们18点下班,急事可留言~价格具体报价请发需求给我哦~mjr3ggkk.png图片 没有的朋友们不要急,我提供了默认数据文件下载,方便测试 微信自动回复表 下载地址:https://pan.quark.cn/s/75a06eed928c 提取码: 完整代码 import sys import time import win32gui import win32api import win32con import pandas as pd from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QLabel, QLineEdit, QPushButton, QTextEdit, QVBoxLayout, QHBoxLayout, QFileDialog) from PyQt5.QtCore import QThread, pyqtSignal, Qt from PyQt5.QtGui import QFont, QPalette, QColor # 消息监听线程:单独开线程是为了不让界面卡住 class ReplyWorker(QThread): # 用来给界面发日志的信号 log_send = pyqtSignal(str) # 用来告诉界面线程是否正常启动 thread_status = pyqtSignal(bool) def __init__(self, excel_path): super().__init__() self.excel_path = excel_path self.reply_rules = {} # 存关键词和回复的对应关系 self.wechat_handle = 0 # 微信窗口的句柄 self.running = False # 控制线程运行的开关 def load_excel_rules(self): """加载Excel里的关键词和回复""" try: # 用openpyxl读xlsx格式,避免编码问题 df = pd.read_excel(self.excel_path, engine='openpyxl') # 转成字典,查起来快 self.reply_rules = dict(zip(df['关键词'], df['回复内容'])) self.log_send.emit(f"回复表加载成功!共{len(self.reply_rules)}条规则") return True except Exception as e: # 捕获各种错误:文件没找到、格式不对、列名错 err_msg = f"加载Excel失败:{str(e)}" self.log_send.emit(err_msg) return False def find_wechat(self): """找到微信窗口,返回是否找到""" # 微信PC端的窗口名一般是“微信”,类名留空不限制 self.wechat_handle = win32gui.FindWindow(None, "微信") if self.wechat_handle == 0: self.log_send.emit("没找到微信窗口!请先打开微信并登录") return False # 把微信窗口提到最前面 win32gui.SetForegroundWindow(self.wechat_handle) self.log_send.emit(f"找到微信啦!窗口句柄:{self.wechat_handle}") return True def find_child(self, parent_handle, class_name=None): """找窗口里的子控件(比如输入框、发送按钮)""" child_handles = [] # 递归遍历所有子控件 def _enum_child(hwnd, extra): if class_name is None or win32gui.GetClassName(hwnd) == class_name: extra.append(hwnd) return True win32gui.EnumChildWindows(parent_handle, _enum_child, child_handles) # 返回第一个找到的控件(一般够用) return child_handles[0] if child_handles else 0 def get_last_msg(self, chat_panel): """获取聊天面板里最后一条消息""" # 微信聊天面板的文本就是所有消息,按换行分割取最后一行 all_msg = win32gui.GetWindowText(chat_panel) if all_msg: return all_msg.split("\n")[-1].strip() return "" def send_reply(self, input_box, send_btn, reply_content): """模拟输入并发送回复""" # 先清空输入框:选中所有文本再删除 win32gui.SendMessage(input_box, win32con.EM_SETSEL, 0, -1) win32gui.SendMessage(input_box, win32con.WM_CLEAR, 0, 0) # 逐个字符输入(太快会乱码,加个小延迟) for char in reply_content: win32gui.SendMessage(input_box, win32con.WM_CHAR, ord(char), 0) time.sleep(0.02) # 点击发送按钮 win32gui.SendMessage(send_btn, win32con.BM_CLICK, 0, 0) def run(self): """线程主逻辑:启动后一直监听""" self.running = True # 先加载规则和找微信,有一个失败就退出 if not self.load_excel_rules() or not self.find_wechat(): self.thread_status.emit(False) self.running = False return self.thread_status.emit(True) # 定位微信的核心控件(不同版本可能要改class_name,用Spy++看) session_list = self.find_child(self.wechat_handle, "ContactPanel") # 会话列表 input_box = self.find_child(self.wechat_handle, "Edit") # 输入框 send_btn = self.find_child(self.wechat_handle, "Button") # 发送按钮 chat_panel = self.find_child(self.wechat_handle, "ChatPanel") # 聊天面板 # 检查控件是否都找到 if not all([session_list, input_box, send_btn, chat_panel]): self.log_send.emit("没找到微信的核心控件!可能版本不兼容") self.running = False return self.log_send.emit("所有控件已定位,开始监听消息...") # 循环监听未读消息 while self.running: # 遍历所有会话找带“未读”的 sessions = [] win32gui.EnumChildWindows(session_list, lambda hwnd, extra: extra.append(hwnd), sessions) for session in sessions: session_text = win32gui.GetWindowText(session) if "未读" in session_text: # 点击未读会话,切换到聊天界面 win32gui.SendMessage(session, win32con.BM_CLICK, 0, 0) time.sleep(0.5) # 等消息加载出来 # 提取联系人(去掉“未读”字样) contact = session_text.replace("未读", "").strip() # 提取最后一条消息 last_msg = self.get_last_msg(chat_panel) if not last_msg: continue self.log_send.emit(f"\n收到[{contact}]的消息:{last_msg}") # 匹配关键词找回复 reply = "抱歉呀,我暂时没理解你的意思~" for keyword, content in self.reply_rules.items(): if keyword in last_msg: reply = content break self.log_send.emit(f"准备回复:{reply}") # 发送回复 self.send_reply(input_box, send_btn, reply) self.log_send.emit("回复发送成功!") # 每2秒查一次,别占太多CPU time.sleep(2) def stop(self): """停止线程""" self.running = False self.log_send.emit("\n监听已停止") # 主界面窗口 class ReplyWindow(QMainWindow): def __init__(self): super().__init__() self.worker = None # 监听线程对象 self.init_ui() # 初始化界面 def init_ui(self): """画界面:布局、按钮、输入框这些""" # 窗口基本设置 self.setWindowTitle("微信自动回复工具 v1.0 - 作者:寒烟似雪 2025/12/29发布在字节曜www.ziyeyao.com博客") self.setFixedSize(1200, 1000) # 固定大小,不允许拉伸 self.setStyleSheet("background-color: #f5f5f5;") # 中心部件(主窗口必须有个中心部件才能放内容) central_widget = QWidget() self.setCentralWidget(central_widget) # 主布局(垂直排列:路径输入→按钮→日志) main_layout = QVBoxLayout(central_widget) main_layout.setSpacing(15) # 控件之间的间距 main_layout.setContentsMargins(25, 25, 25, 25) # 边距 # 1. Excel路径选择区域(水平排列:标签→输入框→选择按钮) path_layout = QHBoxLayout() # 路径标签 path_label = QLabel("回复表路径:") path_label.setFont(QFont("微软雅黑", 10)) # 路径输入框 self.path_edit = QLineEdit() self.path_edit.setFont(QFont("微软雅黑", 9)) self.path_edit.setPlaceholderText("点击右侧按钮选择Excel文件") self.path_edit.setStyleSheet(""" QLineEdit { padding: 6px; border: 1px solid #ddd; border-radius: 4px; background-color: white; } """) # 路径选择按钮 self.select_btn = QPushButton("选择文件") self.select_btn.setFont(QFont("微软雅黑", 9)) self.select_btn.setStyleSheet(""" QPushButton { padding: 6px 12px; border: none; border-radius: 4px; background-color: #4285f4; color: white; } QPushButton:hover { background-color: #3367d6; } """) self.select_btn.clicked.connect(self.select_excel) # 绑定选择文件事件 # 把三个控件加到水平布局里 path_layout.addWidget(path_label) path_layout.addWidget(self.path_edit, stretch=1) # 输入框占满剩余空间 path_layout.addWidget(self.select_btn, stretch=0) main_layout.addLayout(path_layout) # 2. 启动/停止按钮区域(水平排列) btn_layout = QHBoxLayout() # 启动按钮 self.start_btn = QPushButton("启动监听") self.start_btn.setFont(QFont("微软雅黑", 10)) self.start_btn.setStyleSheet(""" QPushButton { padding: 8px 0; border: none; border-radius: 4px; background-color: #34a853; color: white; } QPushButton:disabled { background-color: #a0d9a0; } QPushButton:hover:enabled { background-color: #2d8d46; } """) self.start_btn.clicked.connect(self.start_listen) # 绑定启动事件 # 停止按钮 self.stop_btn = QPushButton("停止监听") self.stop_btn.setFont(QFont("微软雅黑", 10)) self.stop_btn.setStyleSheet(""" QPushButton { padding: 8px 0; border: none; border-radius: 4px; background-color: #ea4335; color: white; } QPushButton:disabled { background-color: #e8a098; } QPushButton:hover:enabled { background-color: #d33526; } """) self.stop_btn.clicked.connect(self.stop_listen) # 绑定停止事件 self.stop_btn.setEnabled(False) # 初始状态:停止按钮禁用 # 两个按钮平分宽度 btn_layout.addWidget(self.start_btn, stretch=1) btn_layout.addSpacing(10) # 按钮之间的间距 btn_layout.addWidget(self.stop_btn, stretch=1) main_layout.addLayout(btn_layout) # 3. 日志显示区域 # 日志标签 log_label = QLabel("运行日志:") log_label.setFont(QFont("微软雅黑", 10)) main_layout.addWidget(log_label) # 日志文本框(只读) self.log_edit = QTextEdit() self.log_edit.setFont(QFont("Consolas", 9)) self.log_edit.setReadOnly(True) self.log_edit.setStyleSheet(""" QTextEdit { padding: 8px; border: 1px solid #ddd; border-radius: 4px; background-color: white; color: #333; } """) main_layout.addWidget(self.log_edit, stretch=1) # 日志框占满剩余空间 def select_excel(self): """选择Excel文件,把路径填到输入框""" # 打开文件选择对话框,只显示Excel文件 file_path, _ = QFileDialog.getOpenFileName( self, "选择回复表", "", "Excel Files (*.xlsx; *.xls)" ) if file_path: self.path_edit.setText(file_path) def start_listen(self): """启动监听线程""" # 先检查路径是否填了 excel_path = self.path_edit.text().strip() if not excel_path: self.add_log("请先选择Excel回复表!") return # 检查线程是否已经在跑了 if self.worker and self.worker.isRunning(): self.add_log(" 监听已经在运行啦,不用重复启动") return # 创建线程对象,绑定信号 self.worker = ReplyWorker(excel_path) self.worker.log_send.connect(self.add_log) # 接收日志信号 self.worker.thread_status.connect(self.set_btn_status) # 接收线程状态信号 self.worker.finished.connect(self.thread_finished) # 线程结束时的信号 # 启动线程 self.worker.start() # 暂时禁用启动按钮 self.start_btn.setEnabled(False) self.add_log("正在初始化监听...") def stop_listen(self): """停止监听线程""" if self.worker and self.worker.isRunning(): self.worker.stop() # 禁用停止按钮,启用启动按钮 self.stop_btn.setEnabled(False) self.start_btn.setEnabled(True) else: self.add_log(" 监听还没启动呢,不用停止") def add_log(self, msg): """往日志框里加内容,自动滚到最下面""" # 加个时间戳,方便看什么时候发生的 time_str = time.strftime("[%H:%M:%S]", time.localtime()) self.log_edit.append(f"{time_str} {msg}") # 自动滚动到最后一行 self.log_edit.moveCursor(self.log_edit.textCursor().End) def set_btn_status(self, is_running): """根据线程状态设置按钮是否可用""" self.start_btn.setEnabled(not is_running) self.stop_btn.setEnabled(is_running) def thread_finished(self): """线程结束时的处理""" self.set_btn_status(False) self.add_log("监听线程已结束") def closeEvent(self, event): """窗口关闭时,确保线程也停了""" if self.worker and self.worker.isRunning(): self.worker.stop() self.worker.wait() # 等线程彻底结束 event.accept() def add_log(self, msg): """往日志里加内容(单独写个方法,方便调用)""" time_str = time.strftime("[%H:%M:%S]", time.localtime()) self.log_edit.append(f"{time_str} {msg}") self.log_edit.ensureCursorVisible() # 自动滚屏 # 程序入口 if __name__ == "__main__": app = QApplication(sys.argv) window = ReplyWindow() window.show() sys.exit(app.exec_()) 怎么用? 先建好转发的Excel表(列名必须是“关键词”和“回复内容”) 运行代码,会弹出一个窗口 点击“选择文件”,找到你建的Excel表 点击“启动监听”,然后打开微信(必须是PC端,登录状态) 有人发消息含关键词,就会自动回复了,日志里能看到过程 不想用了就点“停止监听”,或者直接关窗口 mjr3et38.png图片 注意事项 微信版本兼容问题 这个工具是靠pywin32识别微信窗口控件来实现的,不同版本的微信,控件的类名(比如ContactPanel、ChatPanel)可能不一样。如果运行时提示“没找到核心控件”,可以用Spy++(VS自带工具)查看你电脑上微信的控件类名,然后修改代码里find_child方法传入的class_name参数。 必须打开微信PC端 工具没法模拟微信登录,运行前一定要手动打开微信PC端并登录账号,而且最好不要最小化微信窗口,否则可能识别不到控件。 Excel格式要求 Excel文件里必须有两列,列名严格对应“关键词”和“回复内容”,建议保存为.xlsx格式,避免编码问题。如果提示“加载Excel失败”,检查一下文件路径有没有中文或特殊字符,或者是不是被其他软件占用了。 避免重复回复 工具默认每2秒扫描一次未读消息,如果你担心同一条消息被重复回复,可以在代码里加一个“已处理消息列表”,把已经回复过的消息内容存进去,下次扫描时先判断是否在列表里。 权限问题 运行程序时,如果遇到“权限不足”的提示,右键点击Python.exe,选择“以管理员身份运行”,或者给当前用户授予窗口控制的权限。 常见问题解决 问题1:启动后提示“没找到微信窗口” 解决:确认微信PC端已经打开,并且窗口标题是“微信”(不是其他自定义标题);如果微信在任务栏隐藏,先点击显示出来。 问题2:能找到微信,但提示“没找到核心控件” 解决:用Spy++查看微信的会话列表、输入框、发送按钮的类名,替换代码里对应的class_name;比如有些版本的微信输入框类名是RichEdit20W。 问题3:回复内容发送乱码 解决:在send_reply方法里,延长字符输入的延迟时间,把time.sleep(0.02)改成time.sleep(0.05);同时确保Excel文件的编码是UTF-8。 问题4:线程启动后,界面卡死 解决:检查是不是把监听逻辑写在了主线程里——这个工具的监听代码在ReplyWorker线程里,和界面线程分离,不会卡界面;如果还是卡,大概率是控件识别耗时太长,可以减少扫描频率,把time.sleep(2)改成time.sleep(5)。 结语 这便是我制作的微信自动回复工具啦,有bug可以在评论区留言。有动手能力的朋友们可以尝试添加以下功能: 添加黑白名单:可以在Excel里加一列“是否启用”,或者单独建一个黑白名单文件,指定哪些联系人需要自动回复,哪些不需要。 支持多关键词匹配:现在是匹配到第一个关键词就回复,可以改成支持多个关键词同时匹配,比如“价格”和“优惠”同时出现时,回复特定内容。 定时启停:添加一个时间选择控件,设置每天的监听时间段,比如只在9:00-18:00运行,其他时间自动停止。 回复记录导出:把收到的消息和发送的回复记录到本地文件(比如CSV),方便后续查看和统计。 -
免费分享HTML在线扫雷游戏网页源码 - 经典益智Web游戏开发素材 HTML在线扫雷游戏网页源码:免费开源资源分享 给大家免费分享一款经典又耐玩的Web游戏资源——HTML在线扫雷游戏网页源码!无需付费,玩家、开发者都能免费获取,不用复杂安装,打开浏览器就能直接玩,不管是日常休闲打发时间,还是学习Web开发技术,都是性价比超高的优质资源! mjr1mfvo.png图片 一、核心资源信息 技术架构(资源核心配置):基于HTML+CSS+JavaScript开发,是单页小游戏源码,包含完整的游戏逻辑,代码结构清晰,拿来就能直接部署使用,也方便后续按需修改。 部署使用便捷性(资源优势):无需安装任何软件,不用配置复杂环境,直接在浏览器中打开就能玩;不管是PC、平板还是手机浏览器,都能顺畅运行,跨平台体验无压力。 二、核心功能资源(免费解锁经典扫雷体验) 多难度自由选择:内置初级、中级、高级三种预设难度,满足不同水平玩家需求——新手可以从初级上手,熟悉规则;老玩家能挑战高级难度,享受推理乐趣;还支持自定义雷区尺寸和地雷数量,想玩多大规模、多少地雷都能自己设置,玩法更灵活。 友好界面设计:界面简洁明了,色彩搭配和谐不刺眼,游戏区域和控制按钮一目了然,就算是第一次玩扫雷的用户,也能快速找到操作入口,上手无难度。 流畅稳定体验:源码经过精心优化,资源占用少、加载速度快,游戏过程中不会出现卡顿、延迟的情况,点击排查、标记地雷等操作响应迅速,保障沉浸式游戏体验。 三、资源特色(免费资源优势突出) 经典玩法复刻:完美还原传统扫雷的核心逻辑,通过点击排查方块、标记地雷,锻炼推理能力和反应速度,勾起童年回忆,休闲解压超合适。 可定制性强:支持自定义难度参数,开发者还能基于源码修改界面风格、添加特效或拓展新功能,满足个性化需求。 轻量化无负担:单页源码设计,加载快、不占设备内存,打开浏览器就能启动游戏,碎片时间随时能玩。 学习价值高:代码逻辑清晰,涵盖Web开发基础技能(如事件处理、界面交互、逻辑判断等),适合Web开发初学者作为学习案例,也能给有经验的开发者提供项目参考灵感。 四、资源适用场景(免费资源适配多需求) 这款免费分享的扫雷游戏源码,用途十分广泛: 普通玩家:日常休闲解压、打发碎片时间,不管是通勤路上、午休间隙,打开浏览器就能玩一局,轻松放松。 Web开发初学者:学习HTML、CSS、JavaScript的实际应用,通过分析源码理解游戏逻辑搭建、界面交互实现等基础技能,提升编程实践能力。 开发者/团队:作为项目参考素材,借鉴代码优化、轻量化设计的思路,或嵌入自己的网站、小程序中,丰富平台娱乐功能。 教学场景:作为编程教学案例,帮助学员直观理解前端开发的核心逻辑和操作流程,提升学习兴趣。 获取资源 H5扫雷源码 下载地址:https://pan.quark.cn/s/3839123b35bd 提取码: 免费无套路,经典又实用,不管是直接玩还是用来学习开发,这款HTML在线扫雷游戏网页源码都值得入手! -
免费分享变声器大师APP - 安卓聊天游戏短视频变声工具(萝莉御姐音) 变声器大师APP:安卓端免费变声工具,聊天游戏短视频都能用 给大家免费分享一款超有意思的手机变声工具——变声器大师APP!它是专为安卓用户设计的手机变声软件,不管是和好友微信QQ聊天整蛊、游戏开黑互动,还是在快手抖音做短视频配音,都能轻松切换声线,让声音玩出花样,妥妥的趣味工具资源! mjr1giec.png图片 一、核心资源信息 核心定位(资源核心价值):专注手机端实时变声与语音处理,支持微信、QQ、快手、抖音等主流社交/娱乐平台,不用切换APP,开悬浮窗就能随时变声;内置超多声线和语音包,从少女、御姐、萝莉、正太,到大叔、搞怪音效(比如海绵宝宝、机器人),甚至还有四川话、东北话、粤语等方言声线,满足不同场景的趣味需求。 使用门槛(资源便捷性):界面简洁直观,没有复杂操作步骤——不管是新手还是长辈,打开APP就能找到变声功能;不用注册登录,保护隐私的同时,省去繁琐流程,直接上手就能玩。 二、核心功能资源(免费解锁趣味变声体验) 丰富变声效果:采用全新变声算法,效果自然不生硬,预设了小男孩、小女孩、男青年、女青年等基础声线,还有萝莉、御姐、正太、大叔等热门类型,支持自定义调节变声参数(比如音调、语速),DIY专属个性声音;还自带火爆的海量语音包,适合LOL、吃鸡、王者荣耀等热门游戏,开黑时发一句“有人吗”“你在干嘛鸭”,瞬间活跃氛围。 实时变声互动:支持悬浮窗模式,开启后不用退出聊天或游戏APP——按住悬浮窗“按住说话”录完音,就能直接切换变声类型,点击播放试听效果,再同步到微信QQ发语音,全程不用来回切换,实时变声超方便;快手录短视频时也能这么操作,计时结束直接对接录音功能,配音变声一步到位。 清晰录音与管理:录音音质清晰,能完整保留声音细节,变声后也不模糊;还有完善的本地录音文件管理功能,录好的变声音频能分类保存,想找的时候一目了然,不怕丢失。 便捷分享传播:处理好的变声语音或录音,能直接分享到微信、QQ、微博、抖音等平台,不用额外保存再上传;不管是给好友发“土味情话”,还是分享游戏变声片段,都能快速完成,互动更有乐趣。 三、资源特色(免费工具优势突出) 效果自然不生硬:新变声算法比传统工具更细腻,不会有“机械感”,比如萝莉音软萌不刺耳,御姐音沉稳有质感,日常聊天或配音都不违和。 多场景无缝适配:不管是微信QQ实时聊天、游戏开黑语音,还是短视频录制配音,悬浮窗功能都能让变声“不打断操作”,不用频繁切APP,体验流畅。 免费无套路:核心变声功能完全免费,没有隐藏收费,也不用强制看广告才能用;录音和分享功能也不限制,普通用户日常使用完全够。 兼顾实用与趣味:除了变声,还能当清晰录音机用,课堂、会议记笔记也合适;语音包覆盖游戏、聊天、整蛊等场景,既好玩又实用。 四、资源适用场景(免费工具适配多需求) 这款免费的变声器大师APP,用途特别广: 游戏玩家:吃鸡、王者荣耀开黑时,用萝莉或御姐音和队友互动,让开黑更有氛围; 日常聊天:微信QQ和好友开玩笑,切换搞怪声线发语音,比如用海绵宝宝声说“你是不是不想理我呀”,增添互动趣味; 短视频创作者:抖音、快手做搞笑视频或配音时,用不同声线演绎角色,让作品更有特色; 普通用户:给家人发语音时换可爱声线,或者录“土味情话”分享,让日常沟通更有意思。 APP下载 变声器下载 下载地址:https://www.123865.com/s/WVrQvd-uHB6H?pwd=cytK# 提取码:cytK 免费又好玩,操作简单还不用费流量,不管是临时整蛊还是长期用,这款变声器大师APP都值得试试! -
免费分享水印抹布APP - 安卓视频图片去水印工具(多平台解析) 水印抹布APP:免费视频图片去水印工具,安卓端实用资源分享 给大家免费分享一款超实用的多媒体处理工具——水印抹布APP!它是专为去除视频和图片水印设计的手机应用,安卓用户可直接获取使用,不管是日常想保存无水印素材,还是自媒体创作者处理素材、普通用户编辑照片视频,都能轻松满足需求,妥妥的高效工具资源! mjr1bdpv.png图片 一、核心资源信息 核心定位(资源核心价值):专注解决视频、图片水印问题,能快速识别并去除各类水印——不管是社交媒体平台(如抖音、快手、小红书等)的平台水印,还是相机拍摄自带的水印,甚至支持YouTube、Instagram等国外主流平台素材的去水印与下载,输入素材链接就能自动处理,让素材恢复纯净质感。 使用门槛(资源便捷性):界面简洁直观,操作没有复杂步骤,就算是第一次用去水印工具的新手,也能快速上手;不用登录账号,保护隐私的同时,减少操作流程,打开APP就能直接处理素材。 二、核心功能资源(免费解锁全能处理体验) 高效去水印能力:采用先进的图像处理算法,几秒钟就能识别并抹除水印,还能精准定位复杂水印;支持“快速去除”“精细去除”“局部去除”等多种模式,按需选择更贴合需求;去除水印后还能保持视频图片的高清质量,不损失细节,画面依旧清晰。 批量与多平台支持:可一次性选择多个视频或图片批量处理,不用逐个操作,节省大量时间;不仅能处理本地素材,还支持解析抖音、快手、小红书、B站,以及YouTube、Instagram等国内外热门平台的素材链接,一键下载无水印版本,还能保存视频封面、字幕信息。 丰富编辑工具:除了去水印,还自带超多实用编辑功能——视频方面支持裁剪(自由比例/固定比例)、裁剪时长(剪片头片尾)、拼接多个片段、转GIF动图、变速;图片方面可裁剪尺寸、旋转角度、调整亮度对比度;还提供多种滤镜效果,能给素材加创意滤镜,打造个性化视觉风格。 安全与便捷辅助:处理过程会自动备份,防止意外丢失数据;采用数据加密技术,保护个人信息和素材安全,所有处理基本在本地执行,不泄露隐私;处理完成后能直接分享到社交平台,不用额外保存再上传,一步到位。 三、资源特色(免费工具优势突出) 功能全面无短板:不只是单纯去水印,还整合了下载、编辑、分享功能,一站式解决素材处理需求,不用再装多个工具。 操作简单易上手:界面模块化布局,功能按钮清晰,从解析素材、去水印到编辑保存,几步就能完成,新手也能轻松驾驭。 多场景适配:不管是自媒体创作者收集素材、处理作品,还是普通用户保存喜欢的视频图片、编辑生活记录,甚至是团队处理设计素材,都能满足。 免费友好:无订阅陷阱,不会自动扣费,低频用户还能通过观看广告、签到获取免费处理次数,不用花钱也能正常使用核心功能。 四、资源适用场景(免费工具适配多需求) 这款免费的水印抹布APP,用途特别广: 自媒体/内容创作者:快速收集各平台无水印素材,编辑后用于短视频、Vlog创作,提升内容质量。 日常用户:保存社交媒体上喜欢的视频图片(如教程、美景、生活片段),去除水印后收藏或分享给亲友。 设计/项目团队:批量处理设计素材中的水印,调整尺寸、拼接片段,高效完成设计方案或作品集。 海外内容爱好者:下载YouTube、Instagram等平台的优质内容,无水印保存,方便离线观看或二次创作(需注意版权)。 APP下载 水印抹布_1.0.3.zip 下载地址:https://pan.quark.cn/s/433c1619f03d 提取码:Advu 免费又好用,功能全还安全,不管是临时处理素材,还是长期使用,这款水印抹布APP都值得试试! -
免费分享多功能实用工具箱微信小程序源码 - 可变现工具类小程序资源 多功能实用工具箱微信小程序源码:免费开源资源分享 给大家免费分享一款超实用的微信小程序资源——多功能实用工具箱大全微信小程序源码!无需付费,个人开发者、小型团队都能免费获取,不管是学习小程序开发、快速搭建工具类产品,还是做创业项目孵化、个人副业变现,都是性价比超高的优质资源! mjr16vnj.png图片 一、核心资源信息 技术架构(资源核心配置):基于微信小程序原生开发,是综合性工具集合类项目,源码结构清晰、模块化设计合理,维护和二次开发都很方便,拿来就能按需调整功能。 部署便捷性(资源使用优势):不用配置服务器,也不用购买域名,直接在微信开发者工具中导入就能运行;数据可存在本地缓存,也能通过小程序云开发实现轻量级后端,零成本就能上线,技术门槛极低。 二、核心功能资源(免费解锁全能工具体验) 丰富工具集合:内置超多日常生活常用工具,比如单位换算、天气查询、快递查询、二维码生成器、日历提醒,还有手机清灰、震动手机、闪光灯、水平尺、各种计算器(房贷、工资、血型、亲戚关系等)、垃圾分类查询、网络测速等实用功能;还支持自定义添加新工具模块,后续想扩展功能也很灵活。 变现与推广功能:支持接入微信小程序官方流量主广告(包括Banner广告、激励视频广告等),能通过广告变现赚收益,特别适合个人副业或商业项目;首页可自定义轮播图,能用来做宣传推广、活动引导,轮播图还能配置跳转链接(内部页面或第三方小程序),支持跨平台导流,方便搭建小程序矩阵。 灵活扩展特性:所有功能模块都是独立封装的,提供详细注释和文档说明,就算是新手也能轻松上手二次开发;UI界面也是模块化设计,能根据需求重新设计主题风格,满足个性化需求。 三、资源特色(免费资源优势拉满) 免费可商用:源码完全开源,没有加密、没有使用限制,开发者能自由使用、修改和发布,不管是学习、教学演示,还是创业项目都能用。 低门槛零成本:不依赖服务器和数据库,省去运营成本;支持微信云开发,进一步简化后端逻辑,新手也能快速上线。 变现能力突出:快速接入流量主广告,轻松实现商业变现,是个人副业赚钱、小型团队创业的好选择。 高度可定制:功能模块能按需增删改查,界面风格可自由调整,灵活适配不同使用场景和需求。 体验友好:界面简洁直观,操作流程符合微信小程序用户使用习惯,工具分类清晰、搜索便捷,能提升用户留存率。 四、资源适用场景(免费资源适配多需求) 这款免费分享的源码用途特别广: 新手开发者:用来学习微信小程序开发技巧,熟悉模块化设计和功能封装; 个人用户:搭建专属工具类小程序,自用或分享给好友,提升生活效率; 创业者/小型团队:快速孵化工具类创业项目,借助广告变现和导流功能实现盈利; 教学场景:作为教学演示案例,帮助学员理解小程序开发逻辑和变现模式; 副业刚需:打造能赚钱的工具类小程序,利用流量主广告实现被动收入。 获取源码 微信实用工具箱集...程序源码.zip 下载地址:https://pan.quark.cn/s/045b6d30fcd8 提取码:1hb5 免费无套路,功能丰富又好部署,不管是直接使用还是二次开发,都能满足各类需求,强烈推荐大家获取体验!