使用python实现视频播放器(支持拖动播放位置跳转)
使用python实现视频播放器(支持拖动播放位置跳转)
Python实现视频播放器,在我早期的博文中介绍或作为资料记录过
Python实现视频播放器 https://blog.csdn.net/cnds123/article/details/145926189
Python实现本地视频/音频播放器https://blog.csdn.net/cnds123/article/details/137874107
Python简单GUI程序示例 中 “四、视频播放器” https://blog.csdn.net/cnds123/article/details/122903311
但是,一直不尽人意。现在,再介绍一个。
这是一个基于 PyQt6 和 python-vlc 开发的视频播放器,主要实现了我多次试图实现未果的功能
——带有播放进度条,不仅显示播放进度,还支持拖动播放位置跳转。
普通版视频播放器
主要特点:
播放画面随窗口缩放
支持常见格式(MP4、AVI、MKV 等)
通过文件对话框加载视频文件
播放/暂停、停止、播放进度跳转、音量调节
显示视频文件名、当前播放时间、总时长
播放进度条:显示播放进度并支持拖动播放位置跳转。
音量滑块:音量滑块调整音量大小。
需安装以下 Python第三方库:
python-vlc、 PyQt6
Windows中,还要安装 VLC 播放器,其下载 地址 https://www.videolan.org/vlc/ 。否则,将报错:缺少 libvlc.dll。
运行效果界面如下:
基本使用操作:
打开文件:点击菜单栏 文件 > 打开文件(快捷键 Ctrl+O) 或底部 打开文件 按钮
播放/暂停:空格键 或 点击 按钮切换
停止:停止 按钮
进度跳转:拖动进度条
音量调节:拖动底部音量滑块
源码如下:
import sys
import time
import vlc
import os
from PyQt6 import QtWidgets, QtCore, QtGuiclass VLCPlayer(QtWidgets.QMainWindow):def __init__(self):super().__init__()self.instance = vlc.Instance()self.player = self.instance.media_player_new()self.timer = QtCore.QTimer(self)self.timer.timeout.connect(self.update_ui)self.current_file = Noneself.media_loaded = Falseself.init_ui()def init_ui(self):# 主窗口设置self.setWindowTitle("PyQt6 VLC Player")self.resize(800, 600)# 创建菜单栏menubar = self.menuBar()file_menu = menubar.addMenu("文件(&F)")# 添加"打开"动作open_action = QtGui.QAction("打开文件...", self)open_action.setShortcut("Ctrl+O")open_action.triggered.connect(self.open_file)file_menu.addAction(open_action)# 创建主容器和布局central_widget = QtWidgets.QWidget(self)self.setCentralWidget(central_widget)main_layout = QtWidgets.QVBoxLayout(central_widget)main_layout.setContentsMargins(0, 0, 0, 0)# 视频标题标签 self.title_label = QtWidgets.QLabel("当前未选择媒体文件")self.title_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter)self.title_label.setStyleSheet("font-size: 14px; color: #666; margin: 5px;")main_layout.addWidget(self.title_label)# 视频显示区域self.video_widget = QtWidgets.QWidget()self.video_widget.setStyleSheet("background-color: black;")main_layout.addWidget(self.video_widget, stretch=1)# 控制面板control_panel = QtWidgets.QWidget()control_layout = QtWidgets.QVBoxLayout(control_panel)# 进度条self.progress_bar = QtWidgets.QSlider(QtCore.Qt.Orientation.Horizontal)self.progress_bar.setMinimum(0)self.progress_bar.sliderMoved.connect(self.set_position)control_layout.addWidget(self.progress_bar)# 时间标签self.time_label = QtWidgets.QLabel("00:00:00 / 00:00:00")control_layout.addWidget(self.time_label)# 控制按钮button_layout = QtWidgets.QHBoxLayout()self.play_btn = QtWidgets.QPushButton("播放")self.play_btn.clicked.connect(self.toggle_play)self.stop_btn = QtWidgets.QPushButton("停止")self.stop_btn.clicked.connect(self.stop)self.open_btn = QtWidgets.QPushButton("打开文件")self.open_btn.clicked.connect(self.open_file)# 音量控制self.volume_slider = QtWidgets.QSlider(QtCore.Qt.Orientation.Horizontal)self.volume_slider.setRange(0, 100)self.volume_slider.setValue(100)self.volume_slider.valueChanged.connect(self.set_volume)# 添加控件button_layout.addWidget(self.open_btn)button_layout.addWidget(self.play_btn)button_layout.addWidget(self.stop_btn)button_layout.addWidget(QtWidgets.QLabel("音量:"))button_layout.addWidget(self.volume_slider)control_layout.addLayout(button_layout)main_layout.addWidget(control_panel)# 设置VLC渲染if sys.platform == "win32":self.player.set_hwnd(int(self.video_widget.winId()))elif sys.platform == "linux":self.player.set_xwindow(self.video_widget.winId())elif sys.platform == "darwin":from PyQt6.QtGui import QCocoaNativeContextself.player.set_nsobject(int(QCocoaNativeContext(self.video_widget.winId()).nsview()))self.timer.start(200)def open_file(self):# 修复1:打开文件前先停止播放if self.player.is_playing():self.player.stop()self.media_loaded = Falseself.play_btn.setText("播放")file_dialog = QtWidgets.QFileDialog(self)file_dialog.setNameFilter("视频文件 (*.mp4 *.avi *.mkv *.mov *.flv)")if file_dialog.exec():selected_files = file_dialog.selectedFiles()if selected_files:self.load_media(selected_files[0])def load_media(self, file_path):try:# 新增:停止定时器避免冲突self.timer.stop()# 修复2:确保彻底释放旧媒体资源self.player.stop()self.player.set_media(None) # 清除旧媒体引用# 重置状态self.media_loaded = Falseself.play_btn.setText("播放")self.progress_bar.setValue(0)self.time_label.setText("00:00:00 / 00:00:00")# 加载新文件self.current_file = file_pathmedia = self.instance.media_new(file_path)self.player.set_media(media)# 更新标题file_name = os.path.basename(file_path)self.title_label.setText(f"当前播放: {file_name}")# 修复3:异步解析媒体信息(避免阻塞UI)media.parse_with_options(vlc.MediaParseFlag.network, 1000)# 设置进度条最大值self.progress_bar.setMaximum(media.get_duration())self.media_loaded = True# 显示总时长total_time = time.strftime("%H:%M:%S", time.gmtime(media.get_duration() // 1000))self.time_label.setText(f"00:00:00 / {total_time}")# 新增:确保媒体加载完成后再启定时器self.timer.start(200)except Exception as e:QtWidgets.QMessageBox.critical(self, "错误", f"无法加载文件:\n{str(e)}")self.media_loaded = Falseself.title_label.setText("媒体加载失败")def toggle_play(self):if not self.media_loaded:self.open_file()return# 修复4:强制同步按钮状态if self.player.is_playing():self.player.pause()self.play_btn.setText("播放")else:self.player.play()self.play_btn.setText("暂停")def stop(self):self.player.stop()self.progress_bar.setValue(0)self.time_label.setText("00:00:00 / 00:00:00")self.play_btn.setText("播放")self.title_label.setText("播放已停止")def set_volume(self, value):self.player.audio_set_volume(value)def set_position(self, value):if self.player.is_seekable():self.player.set_position(value / self.progress_bar.maximum())def update_ui(self):if not self.media_loaded:return # 新增:防止在无媒体时更新media_length = self.player.get_length()if media_length > 0:current_time = self.player.get_time()# 新增:检测播放结束if current_time >= media_length - 500: # 留50ms容差self.stop()returnself.progress_bar.setMaximum(media_length)self.progress_bar.setValue(current_time)total_time = time.strftime("%H:%M:%S", time.gmtime(media_length // 1000))current_time_str = time.strftime("%H:%M:%S", time.gmtime(current_time // 1000))self.time_label.setText(f"{current_time_str} / {total_time}")def closeEvent(self, event):self.player.stop()event.accept()if __name__ == "__main__":app = QtWidgets.QApplication(sys.argv)player = VLCPlayer()player.show()sys.exit(app.exec())
专用版视频播放控制器(视频播控器)
主要添加视频“加密”、“解密”功能
运行条件除了和上面的一样外,还需安装第三方库pycryptodome
pycryptodome 是一个强大的加密库,用于实现加密算法。
界面如下:
1)加密视频
菜单栏点击 安全 → 加密视频
优先当前播放文件路径,即:
如果当前正在播放视频且未加密 → 弹出确认对话框
否则 → 弹出文件选择对话框
加密文件的后缀 .vef,放在原文将后缀之后。命名规则为:原文件名.vef(如 video.mp4 → video.mp4.vef)
2)解密视频
菜单栏点击 安全 → 解密视频
文件过滤:仅显示 .vef 文件
解密文件,出现保存对话框,默认放置在原位置,默认用文件名(可改),若存放处有同名文件,提示是否替换。
命名规则:自动去除 .vef 后缀 → video.mp4
解密时,若输入的密码和加密时不一致,提示:密码错误或文件损坏 → 立即终止并提示
源码如下:
import sys
import time
import hashlib
import secrets
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
import vlc
import os
from PyQt6 import QtWidgets, QtCore, QtGuiclass VLCPlayer(QtWidgets.QMainWindow):def __init__(self):super().__init__()self.instance = vlc.Instance()self.player = self.instance.media_player_new()self.timer = QtCore.QTimer(self)self.timer.timeout.connect(self.update_ui) # 连接定时器到更新方法self.current_file = Noneself.media_loaded = Falseself.temp_files = set() #用于跟踪临时解密文件self.init_ui()self.init_crypto()def init_ui(self):# 主窗口设置self.setWindowTitle("视频播控器(特别专用版)")self.resize(800, 600)# 初始化菜单menubar = self.menuBar()file_menu = menubar.addMenu("文件(&F)")crypto_menu = menubar.addMenu("安全(&S)")# 文件操作open_action = self.create_action("打开文件...", "Ctrl+O", self.open_file)# exit_action = self.create_action("退出", "Ctrl+Q", lambda: self.close()) # 播放退出太慢# 加密解密操作encrypt_action = self.create_action("加密视频...", "Ctrl+E", self.encrypt_video)decrypt_action = self.create_action("解密视频...", "Ctrl+D", self.decrypt_video)# 添加菜单项file_menu.addAction(open_action)file_menu.addSeparator()# file_menu.addAction(exit_action)crypto_menu.addAction(encrypt_action)crypto_menu.addAction(decrypt_action)# 创建主容器和布局central_widget = QtWidgets.QWidget(self)self.setCentralWidget(central_widget)main_layout = QtWidgets.QVBoxLayout(central_widget)main_layout.setContentsMargins(0, 0, 0, 0)# 视频标题标签 self.title_label = QtWidgets.QLabel("当前未选择媒体文件")self.title_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter)self.title_label.setStyleSheet("font-size: 14px; color: #666; margin: 5px;")main_layout.addWidget(self.title_label)# 视频显示区域self.video_widget = QtWidgets.QWidget()self.video_widget.setStyleSheet("background-color: black;")main_layout.addWidget(self.video_widget, stretch=1)# 控制面板control_panel = QtWidgets.QWidget()control_layout = QtWidgets.QVBoxLayout(control_panel)# 进度条self.progress_bar = QtWidgets.QSlider(QtCore.Qt.Orientation.Horizontal)self.progress_bar.setMinimum(0)self.progress_bar.sliderMoved.connect(self.set_position)control_layout.addWidget(self.progress_bar)# 时间标签self.time_label = QtWidgets.QLabel("00:00:00 / 00:00:00")control_layout.addWidget(self.time_label)# 控制按钮button_layout = QtWidgets.QHBoxLayout()self.play_btn = QtWidgets.QPushButton("播放")self.play_btn.clicked.connect(self.toggle_play)self.stop_btn = QtWidgets.QPushButton("停止")self.stop_btn.clicked.connect(self.stop)self.open_btn = QtWidgets.QPushButton("打开文件")self.open_btn.clicked.connect(self.open_file)# 音量控制self.volume_slider = QtWidgets.QSlider(QtCore.Qt.Orientation.Horizontal)self.volume_slider.setRange(0, 100)self.volume_slider.setValue(100)self.volume_slider.valueChanged.connect(self.set_volume)# 添加控件button_layout.addWidget(self.open_btn)button_layout.addWidget(self.play_btn)button_layout.addWidget(self.stop_btn)button_layout.addWidget(QtWidgets.QLabel("音量:"))button_layout.addWidget(self.volume_slider)control_layout.addLayout(button_layout)main_layout.addWidget(control_panel)# 设置VLC渲染if sys.platform == "win32":self.player.set_hwnd(int(self.video_widget.winId()))elif sys.platform == "linux":self.player.set_xwindow(self.video_widget.winId())elif sys.platform == "darwin":from PyQt6.QtGui import QCocoaNativeContextself.player.set_nsobject(int(QCocoaNativeContext(self.video_widget.winId()).nsview()))self.timer.start(200)def init_crypto(self):"""初始化加密参数"""self.key_derivation_iterations = 100000self.salt_size = 16self.nonce_size = 16self.tag_size = 16self.chunk_size = 64 * 1024 # 64KB块处理def create_action(self, text, shortcut, callback):"""创建标准化菜单动作"""action = QtGui.QAction(text, self)action.setShortcut(shortcut)action.triggered.connect(callback)return action def open_file(self):# 修复1:打开文件前先停止播放if self.player.is_playing():self.player.stop()self.media_loaded = Falseself.play_btn.setText("播放")file_dialog = QtWidgets.QFileDialog(self)file_dialog.setNameFilter("视频文件 (*.mp4 *.avi *.mkv *.mov *.flv)")if file_dialog.exec():selected_files = file_dialog.selectedFiles()if selected_files:self.load_media(selected_files[0])def load_media(self, file_path):try:# 如果是加密文件需要特殊处理if file_path.lower().endswith('.vef'):QtWidgets.QMessageBox.warning(self, "警告", "请使用菜单中的解密功能打开加密文件")return# 新增:停止定时器避免冲突self.timer.stop()# 修复2:确保彻底释放旧媒体资源self.player.stop()self.player.set_media(None) # 清除旧媒体引用# 重置状态self.media_loaded = Falseself.play_btn.setText("播放")self.progress_bar.setValue(0)self.time_label.setText("00:00:00 / 00:00:00")# 加载新文件self.current_file = file_pathmedia = self.instance.media_new(file_path)self.player.set_media(media)# 更新标题file_name = os.path.basename(file_path)self.title_label.setText(f"当前播放: {file_name}")# 修复3:异步解析媒体信息(避免阻塞UI)media.parse_with_options(vlc.MediaParseFlag.network, 1000)# 设置进度条最大值self.progress_bar.setMaximum(media.get_duration())self.media_loaded = True# 显示总时长total_time = time.strftime("%H:%M:%S", time.gmtime(media.get_duration() // 1000))self.time_label.setText(f"00:00:00 / {total_time}")# 新增:确保媒体加载完成后再启定时器self.timer.start(200)except Exception as e:QtWidgets.QMessageBox.critical(self, "错误", f"无法加载文件:\n{str(e)}")self.media_loaded = Falseself.title_label.setText("媒体加载失败")def toggle_play(self):if not self.media_loaded:self.open_file()return# 修复4:强制同步按钮状态if self.player.is_playing():self.player.pause()self.play_btn.setText("播放")else:self.player.play()self.play_btn.setText("暂停")# ---------- 加密解密功能 ----------def _get_encrypted_filename(self, src_path):"""生成加密文件名(原文件名+.vef)"""return src_path + ".vef" # 直接在原文件名后追加.vefdef encrypt_video(self):"""智能加密方法:优先处理当前播放文件"""# 自动检测当前播放文件src_path = Noneif self.current_file and os.path.exists(self.current_file):# 检查是否已经是加密文件if not self.current_file.lower().endswith('.vef'):reply = QtWidgets.QMessageBox.question(self, '加密确认', f"是否加密当前播放的文件?\n{os.path.basename(self.current_file)}",QtWidgets.QMessageBox.StandardButton.Yes | QtWidgets.QMessageBox.StandardButton.No)if reply == QtWidgets.QMessageBox.StandardButton.Yes:src_path = self.current_file# 如果无当前可用文件,则选择文件if not src_path:src_path, _ = QtWidgets.QFileDialog.getOpenFileName(self, "选择要加密的视频文件", "","视频文件 (*.mp4 *.avi *.mkv *.mov *.flv)")if not src_path:return# 处理加密文件特殊情况if src_path.lower().endswith('.vef'):QtWidgets.QMessageBox.warning(self, "警告", "不能加密已加密文件")return# 获取保存路径default_name = self._get_encrypted_filename(os.path.basename(src_path))dest_path, _ = QtWidgets.QFileDialog.getSaveFileName(self, "保存加密文件", os.path.join(os.path.dirname(src_path), default_name), # 默认原目录"加密视频 (*.vef)")if not dest_path:return# 获取密码password, ok = QtWidgets.QInputDialog.getText(self, "输入密码", "设置加密密码:", QtWidgets.QLineEdit.EchoMode.Password)if not ok or not password:return# 执行加密流程try:# 如果是当前播放文件,停止播放was_playing = Falseif src_path == self.current_file:was_playing = self.player.is_playing()self.player.stop()self.media_loaded = Falseself._encrypt_file(src_path, dest_path, password)# 成功提示msg = f"加密成功!\n原文件: {os.path.basename(src_path)}\n加密文件: {os.path.basename(dest_path)}"QtWidgets.QMessageBox.information(self, "完成", msg)# 如果加密的是当前文件,询问是否加载加密文件if src_path == self.current_file:choice = QtWidgets.QMessageBox.question(self, "加载文件", "是否立即加载加密后的文件?",QtWidgets.QMessageBox.StandardButton.Yes | QtWidgets.QMessageBox.StandardButton.No)if choice == QtWidgets.QMessageBox.StandardButton.Yes:self.load_media(dest_path)except Exception as e:self.show_error(f"加密失败: {str(e)}")finally:# 恢复原始状态(如果需要)if was_playing and src_path != dest_path:self.load_media(src_path)def _encrypt_file(self, src_path, dest_path, password):"""执行文件加密(新增)"""try:# 生成加密参数salt = secrets.token_bytes(self.salt_size)key = hashlib.pbkdf2_hmac('sha256',password.encode('utf-8'),salt,self.key_derivation_iterations,dklen=32)cipher = AES.new(key, AES.MODE_GCM)cipher.update(salt)# 分块加密with open(src_path, 'rb') as fin, open(dest_path, 'wb') as fout:# 写入加密头fout.write(salt)fout.write(cipher.nonce)while True:chunk = fin.read(self.chunk_size)if not chunk:breakencrypted = cipher.encrypt(pad(chunk, AES.block_size))fout.write(encrypted)# 写入认证标签fout.write(cipher.digest())except PermissionError:raise RuntimeError("文件被其他程序占用,请关闭后重试")except Exception as e:raise RuntimeError(f"加密失败: {str(e)}")def _get_decrypted_filename(self, src_path):"""生成解密文件名(去除.vef后缀)"""if src_path.lower().endswith('.vef'):return src_path[:-4] # 去除.vefreturn src_path + "_decrypted"def decrypt_video(self):"""增强型解密方法"""try:# 选择加密文件src_file, _ = QtWidgets.QFileDialog.getOpenFileName(self, "选择要解密的文件", "", "加密视频 (*.vef)")if not src_file:return# 生成默认保存路径default_path = self._get_decrypted_filename(src_file)dest_file, _ = QtWidgets.QFileDialog.getSaveFileName(self, "保存解密文件",default_path, # 默认原目录+去后缀"视频文件 (*.*)")if not dest_file:return# 检查文件是否已存在if os.path.exists(dest_file):reply = QtWidgets.QMessageBox.question(self, "文件存在",f"目标文件已存在,是否覆盖?\n{dest_file}",QtWidgets.QMessageBox.StandardButton.Yes | QtWidgets.QMessageBox.StandardButton.No)if reply != QtWidgets.QMessageBox.StandardButton.Yes:return# 获取密码password, ok = QtWidgets.QInputDialog.getText(self, "输入密码", "解密密码:", QtWidgets.QLineEdit.EchoMode.Password)if not ok or not password:return# 执行解密decrypted_path = self._decrypt_file(src_file, password, dest_file)if decrypted_path:QtWidgets.QMessageBox.information(self, "成功", f"文件解密成功!\n保存路径: {decrypted_path}")self.load_media(decrypted_path)except Exception as e:self.show_error(f"解密失败: {str(e)}")def _decrypt_file(self, src_path, password, dest_path):"""增强型解密方法(保存到指定路径)"""try:with open(src_path, 'rb') as fin:salt = fin.read(self.salt_size)nonce = fin.read(self.nonce_size)key = self._derive_key(password, salt)cipher = AES.new(key, AES.MODE_GCM, nonce=nonce)cipher.update(salt)with open(dest_path, 'wb') as fout:encrypted = fin.read()ciphertext, tag = encrypted[:-self.tag_size], encrypted[-self.tag_size:]# 分块解密写入chunk_size = self.chunk_size + AES.block_sizefor i in range(0, len(ciphertext), chunk_size):chunk = ciphertext[i:i+chunk_size]decrypted = unpad(cipher.decrypt(chunk), AES.block_size)fout.write(decrypted)# 验证标签cipher.verify(tag)return dest_pathexcept ValueError as ve:# 清理已写入的部分文件if os.path.exists(dest_path):try:os.remove(dest_path)except:passraise ValueError("解密失败 - 密码错误或文件损坏") from veexcept Exception as e:if os.path.exists(dest_path):try:os.remove(dest_path)except:passraise RuntimeError(f"解密过程错误: {str(e)}") from edef _derive_key(self, password, salt):"""生成加密密钥"""return hashlib.pbkdf2_hmac('sha256',password.encode('utf-8'),salt,self.key_derivation_iterations,dklen=32 # AES-256需要32字节密钥)# ---------- 辅助功能 ----------def show_error(self, message):"""显示错误提示"""QtWidgets.QMessageBox.critical(self, "错误", message)def closeEvent(self, event):"""关闭处理,清理临时文件"""for temp_file in self.temp_files:try:if os.path.exists(temp_file):os.remove(temp_file)except Exception as e:print(f"删除临时文件失败: {str(e)}")self.player.stop() # 停止播放器event.accept() # def stop(self):self.player.stop()self.progress_bar.setValue(0)self.time_label.setText("00:00:00 / 00:00:00")self.play_btn.setText("播放")self.title_label.setText("播放已停止")def set_volume(self, value):self.player.audio_set_volume(value)def set_position(self, value):if self.player.is_seekable():self.player.set_position(value / self.progress_bar.maximum())def update_ui(self):if not self.media_loaded:return # 新增:防止在无媒体时更新media_length = self.player.get_length()if media_length > 0:current_time = self.player.get_time()# 新增:检测播放结束if current_time >= media_length - 500: # 留50ms容差self.stop()returnself.progress_bar.setMaximum(media_length)self.progress_bar.setValue(current_time)total_time = time.strftime("%H:%M:%S", time.gmtime(media_length // 1000))current_time_str = time.strftime("%H:%M:%S", time.gmtime(current_time // 1000))self.time_label.setText(f"{current_time_str} / {total_time}")if __name__ == "__main__":app = QtWidgets.QApplication(sys.argv)player = VLCPlayer()player.show()sys.exit(app.exec())
相关文章:
使用python实现视频播放器(支持拖动播放位置跳转)
使用python实现视频播放器(支持拖动播放位置跳转) Python实现视频播放器,在我早期的博文中介绍或作为资料记录过 Python实现视频播放器 https://blog.csdn.net/cnds123/article/details/145926189 Python实现本地视频/音频播放器https://bl…...
Python星球日记 - 第2天:数据类型与变量
🌟引言: 上一篇:Python星球日记 - 第1天:欢迎来到Python星球 名人说:莫听穿林打叶声,何妨吟啸且徐行。—— 苏轼《定风波莫听穿林打叶声》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和…...
CyclicBarrier、Semaphore、CountDownLatch的区别,适用场景
CyclicBarrier、Semaphore 和 CountDownLatch 是 Java 并发包中用于线程协作的工具类,它们虽然都与线程同步相关,但设计目的和使用场景有显著差异。以下是它们的核心区别和典型应用场景: 1. CountDownLatch 核心机制 一次性计数器…...
【愚公系列】《高效使用DeepSeek》050-外汇交易辅助
🌟【技术大咖愚公搬代码:全栈专家的成长之路,你关注的宝藏博主在这里!】🌟 📣开发者圈持续输出高质量干货的"愚公精神"践行者——全网百万开发者都在追更的顶级技术博主! 👉 江湖人称"愚公搬代码",用七年如一日的精神深耕技术领域,以"…...
java短连接,长连接
在网络通信中,短连接(Short Connection)是指客户端与服务器建立连接后,仅完成一次或几次数据交互就立即断开连接的通信方式。以下是关于短链接的详细说明: 一、短链接的核心特点 连接短暂 数据传输完成后立即关闭连接…...
从零开始训练Codebook:基于ViT的图像重建实践
完整代码在文末,可以一键运行。 1. 核心原理 Codebook是一种离散表征学习方法,其核心思想是将连续特征空间映射到离散的码本空间。我们的实现方案包含三个关键组件: 1.1 ViT编码器 class ViTEncoder(nn.Module):def __init__(self, codebo…...
每日一题洛谷P8664 [蓝桥杯 2018 省 A] 付账问题c++
P8664 [蓝桥杯 2018 省 A] 付账问题 - 洛谷 (luogu.com.cn) 思路:要使方差小,那么钱不能一下付的太多,可以让钱少的全付玩,剩下还需要的钱再让钱多的付(把钱少的补上)。 将钱排序,遍历一遍&…...
蓝桥杯真题——传送阵
原题连接:蓝桥杯2024年第十五届省赛真题-传送阵 - C语言网 知识点:并查集 题目描述 小蓝在环球旅行时来到了一座古代遗迹,里面并排放置了 n 个传送阵,进入第 i 个传送阵会被传送到第 ai 个传送阵前,并且可以随时选择…...
解释回溯算法,如何应用回溯算法解决组合优化问题?
一、回溯算法核心原理 回溯算法本质是暴力穷举的优化版本,采用"试错剪枝"策略解决问题。其核心流程如下: 路径构建:记录当前选择路径选择列表:确定可用候选元素终止条件:确定递归结束时机剪枝优化…...
opencv连接vs2015
需要改的地方: 1.debug x64 2.vc目录 包含目录:D:\softword\opencv\opencv3416\opencv\build\include 3.vc目录 库目录:D:\softword\opencv\opencv3416\opencv\build\x64\vc14\lib 4.链接器——输入:D:\softword\ope…...
用matlab搭建一个简单的图像分类网络
文章目录 1、数据集准备2、网络搭建3、训练网络4、测试神经网络5、进行预测6、完整代码 1、数据集准备 首先准备一个包含十个数字文件夹的DigitsData,每个数字文件夹里包含1000张对应这个数字的图片,图片的尺寸都是 28281 像素的,如下图所示…...
移动端六大语言速记:第6部分 - 错误处理与调试
移动端六大语言速记:第6部分 - 错误处理与调试 本文将对比Java、Kotlin、Flutter(Dart)、Python、ArkTS和Swift这六种移动端开发语言在错误处理与调试方面的特性,帮助开发者理解和掌握各语言的异常处理机制。 6. 错误处理与调试 6.1 异常处理 各语言异常处理的语法对比:…...
【数据库】达梦arm64安装
话不多说,快速开始~ 1.下载 进入官网: 产品下载 | 达梦在线服务平台 下载安装包。 选飞腾、鲲鹏都可以,都是arm架构的。我选择的是: 直接下载地址是https://download.dameng.com/eco/adapter/DM8/202502/dm8_20250117_HWarm920…...
QTableWidget 中insertRow(0)(头插)和 insertRow(rowCount())(尾插)的性能差异
一、目的 在 Qt 的 QTableWidget 中,insertRow(0) (头插)和 insertRow(rowCount())(尾插)在性能上存在显著差异。 二、QAbstractItemModel:: insertRows 原文解释 QAbstractItemModel Class | Qt Core 5.15.18 AI 解…...
使用MFC ActiveX开发KingScada控件(OCX)
最近有个需求,要在KingScada上面开发一个控件。 原来是用的WinCC,WinCC本身是支持调用.net控件,就是winform控件的,winform控件开发简单,相对功能也更丰富。奈何WinCC不是国产的。 话说KingScada,国产组态软…...
大模型学习二:DeepSeek R1+蒸馏模型组本地部署与调用
一、说明 DeepSeek R1蒸馏模型组是基于DeepSeek-R1模型体系,通过知识蒸馏技术优化形成的系列模型,旨在平衡性能与效率。 1、技术路径与核心能力 基础架构与训练方法 DeepSeek-R1-Zero:通过强化学习(RL)训练&…...
通过 Markdown 改进 RAG 文档处理
通过 Markdown 改进 RAG 文档处理 作者:Tableau 原文地址:https://zhuanlan.zhihu.com/p/29139791931 通过 Markdown 改进 RAG 文档处理https://mp.weixin.qq.com/s/LOBOKNA71dANXHuwxe7yxw 如何将 PDF 转换为 Markdown 以获得更好的 LLM RAG 结果 Mar…...
Java学习总结-IO流
什么IO流? 以内存为主体。input:磁盘向内存输入内容。output:内存向磁盘输入内容。 IO流的分类:...
python发送qq邮件
1.发送邮件的前提是你的qq邮箱设置能够用程序访问 这个服务点打开 就在 设置->账号 中 可以找到 # 导入 smtplib 库,用于实现 SMTP 协议,可实现邮件的发送功能 import smtplib # 从 email.mime.multipart 模块导入 MIMEMultipart 类,用…...
使用Deployment运行无状态应用
使用Deployment运行无状态应用 文章目录 使用Deployment运行无状态应用[toc]一、工作负载资源与控制器二、ReplicationController、ReplicaSet和Deployment1. ReplicationController(已淘汰)2. ReplicaSet(ReplicationController 的增强版&am…...
QT Quick(C++)跨平台应用程序项目实战教程 6 — 弹出框
目录 1. Popup组件介绍 2. 使用 上一章内容完成了音乐播放器程序的基本界面框架设计。本小节完成一个简单的功能。单击该播放器顶部菜单栏的“关于”按钮,弹出该程序的相关版本信息。我们将使用Qt Quick的Popup组件来实现。 1. Popup组件介绍 Qt 中的 Popup 组件…...
Design Compiler:库特征分析(ALIB)
相关阅读 Design Compilerhttps://blog.csdn.net/weixin_45791458/category_12738116.html?spm1001.2014.3001.5482 简介 在使用Design Compiler时,可以对目标逻辑库进行特征分析,并创建一个称为ALIB的伪库(可以被认为是缓存)&…...
2025高频面试设计模型总结篇
文章目录 设计模型概念单例模式工厂模式策略模式责任链模式 设计模型概念 设计模式是前人总结的软件设计经验和解决问题的最佳方案,它们为我们提供了一套可复用、易维护、可扩展的设计思路。 (1)定义: 设计模式是一套经过验证的…...
41. 评论日记
越复杂的结构越脆弱,你不能因为有智驾有只能,你就全交给它了,手机永久了还发热呢,你全交给它那你要死了也怪不了谁。 这年头的手机基本都有防水,但是你天天拿着这个在泳池里玩,哪天炸了我都只能说炸的响炸的…...
Python第七章09:自定义python包.py
# 自定义python包# 从物理上看,包就是一个文件夹,在该文件夹下包含了一个_init_.py文件,该文件夹可用于包含多个模块文件 # 从逻辑上看,包的本质依然是模块 # _init_.py 标识python包,没有就是普通文件夹࿰…...
基于大模型预测升主动脉瘤的多维度诊疗研究报告
目录 一、引言 1.1 研究背景 1.2 研究目的与意义 二、升主动脉瘤概述 2.1 定义与分类 2.2 发病原因与机制 2.3 流行病学现状 三、大模型技术原理及应用现状 3.1 大模型基本原理 3.2 在医疗领域的应用进展 3.3 针对升主动脉瘤预测的独特价值 四、术前大模型预测方案…...
Lua中table函数使用详解
目录 1. table.concat(list [, sep [, i [, j]]])2. table.insert(list, [pos,] value)3. table.move(src, a, b, dest [, dest_pos]) (Lua 5.3)4. table.pack(...) (Lua 5.2)5. table.remove(list [, pos])6. table.sort(list [, comp])7. table.unpack(list [, i [, j]])总结…...
如何在Windows上找到Python安装路径?两种方法快速定位
原文:如何在Windows上找到Python安装路径?两种方法快速定位 | w3cschool笔记 在 Windows 系统上找到 Python 的安装路径对于设置环境变量或排查问题非常重要。本文将介绍两种方法,帮助你找到 Python 的安装路径:一种是通过命令提…...
图形库 EasyX - EasyX 初识(EasyX 概述、EasyX 下载与安装、打开一个窗口、打开一个彩色窗口、绘制简易图形、输出文字)
一、EasyX 概述 EasyX 是一款专为 C 开发者设计的轻量级图形库,主要面向 Windows 平台,它有如下特点 EasyX 的 API 设计简洁直观,易学易用,绘图效果所见即所得 二、EasyX 下载与安装 1、EasyX 下载 官方网址:https…...
《深度探秘:SQL助力经典Apriori算法实现》
在数据的广袤世界里,隐藏着无数有价值的信息,等待着我们去挖掘和发现。关联规则挖掘算法,作为数据挖掘领域的关键技术,能够从海量数据中找出事物之间潜在的关联关系,为商业决策、学术研究等诸多领域提供有力支撑。其中…...
AVR128单片机红外遥控8*8LED点阵屏显示
1)将接收到的红外解码信号用LCD液晶显示屏显示。 2)将接收到的5种红外解码信号分别控制88的液晶点阵屏MATRIX-88-GREEN (颜色可以自定)进行不同的显示:整行从上到下、从下到上轮流显示;整列从左到右、从右到左轮流显示;…...
前端Uniapp接入UviewPlus详细教程!!!
相信大家在引入UviewPlusUI时遇到很头疼的问题,那就是明明自己是按照官网教程一步一步的走,为什么到处都是bug呢?今天我一定要把这个让人头疼的问题解决了! 1.查看插件市场 重点: 我们打开Dcloud插件市场搜素uviewPl…...
【c++深入系列】:类与对象详解(中)
🔥 本文专栏:c 🌸作者主页:努力努力再努力wz 💪 今日博客励志语录: 不是因为看到希望才坚持,而是坚持了才能看到希望 那么上一篇博客我讲解了什么是类和对象以及类和对象是怎么定义的࿰…...
【Linux】远程登录时,使用图形界面报错:MoTTY X11 proxy: Unsupported authorisation protocol
1、问题描述 使用 MobaXterm 远程登录Ubuntu后,使用sudo权限运行图形界面程序报错: MoTTY X11 proxy: Unsupported authorisation protocol (gpartedbin:10518): Gtk-WARNING **: 22:01:34.377: cannot open display: localhost:10.02、查看SSH配置 修改 SSH 服务端配置,…...
作用域与上下文:JavaScript魔法森林探秘
在JavaScript的魔法森林里,作用域和上下文是两位神秘的守护者,它们掌控着代码的逻辑流向和变量的生杀大权。今天,就让我们一起踏入这片神奇的土地,揭开全局作用域、函数作用域和闭包的神秘面纱,看它们如何影响我们的代…...
虚拟电商-话费充值业务(五)充值成功逻辑和网络异常重试逻辑
一、网络异常重试逻辑编写 如果在对接供应商的过程中出现了网络异常,我们需要做一个补偿机制,在任务类型枚举类:TaskTypeEnum中有一种业务状态码是针对远程调用失败的 步骤一:在对接供应商的方法:SupplierServiceImp…...
42.评论日记
怎么看待算命? 我能算到你今晚睡觉前会上一次厕所。 你可以选择相信我算的内容,也可以不信。 你也可以有感觉要上厕所的时候不去拉兜里。 也可以选择相信,早早的拿好纸做准备。 你今晚可能不止上一次,也可能今晚没吃没喝早早…...
MTK-GMS版本国内WIFI受限问题
MTK-GMS版本国内WIFI受限问题解决 文章目录 问题参考资料解决方案方案一 修改配置坑点 方案二 直接修改属性 问题 最近负责ROOM 产品,出现WIFI受限显示,但是网络是通畅的。 GMS 版本,在国外或者国内翻墙网络不会出现WIFI受限显示问题&#…...
C# System.Text.Json 中 JsonConverter 使用详解
总目录 前言 在 C# 开发中,System.Text.Json 是一个高性能的 JSON 处理库,广泛用于序列化和反序列化对象。当默认的序列化行为无法满足需求时,JsonConverter 提供了强大的自定义能力。本文将详细讲解 JsonConverter 的使用方法,帮…...
Leetcode 857 -- 贪心 | 数学
题目描述 雇佣 K 名工人的最低成本 思路 参考官方题解和这里。 代码1(正确) class Solution { public:double mincostToHireWorkers(vector<int>& quality, vector<int>& wage, int k) {int n wage.size();double res 0, totalq …...
基于 SpringBoot 的社区维修平台
收藏关注不迷路!! 🌟文末获取源码数据库🌟 感兴趣的可以先收藏起来,还有大家在毕设选题(免费咨询指导选题),项目以及论文编写等相关问题都可以给我留言咨询,希望帮助更多…...
maven项目添加第三方JAR包
项目开发过程中,不可避免的需要用到一些maven库(公共库、司库等)中没有的冷门jar包依赖,这时,可以将这些第三方JAR包安装到本地maven仓库中,实现项目依赖的一致性。具体步骤如下: 1、下载jar包 …...
C#:接口(interface)
目录 接口的核心是什么? 1. 什么是接口(Interface),为什么要用它? 2. 如何定义和使用接口? 3.什么是引用接口? 如何“引用接口”? “引用接口”的关键点 4. 接口与抽象类的区…...
c#和c++脚本解释器科学运算
说明: 我希望用c#和c写一个脚本解释器,用于科学运算 效果图: step1: c# C:\Users\wangrusheng\RiderProjects\WinFormsApp3\WinFormsApp3\Form1.cs using System; using System.Collections.Generic; using System.Data; using System.Tex…...
2025年嵌入式大厂春招高频面试真题及解析
以下是 2025 年嵌入式大厂春招高频面试真题及解析,结合真题分类和核心知识点整理: 一、C/C++编程基础 1.1 指针与内存 野指针的成因及避免方法(未初始化、释放后未置空) malloc与calloc的区别(后者自动初始化为0) 指针与数组的区别(内存分配方…...
【C++】nlohmann::json 配置加载技术实践:从基础到高级应用
一、nlohmann::json 库概况与核心特性 nlohmann::json 是 C 社区最受欢迎的 JSON 库之一,其设计理念简洁即美,通过单头文件实现完整的 JSON 解析、序列化和操作功能。 1.1 基本特性 nlohmann::json是一个现代C编写的开源JSON库,采用MIT协议…...
ngx_regex_init
定义在 src\core\ngx_regex.c void ngx_regex_init(void) { #if !(NGX_PCRE2)pcre_malloc ngx_regex_malloc;pcre_free ngx_regex_free; #endif } NGX_PCRE21 #if !(NGX_PCRE2) 就为假 条件不成立 ngx_regex_init 函数就成了空实现 NGX_PCRE2 被定义,则表示 Ngin…...
【前端扫盲】postman介绍及使用
Postman 是一款专为 API 开发与测试设计的 全流程协作工具,程序员可通过它高效完成接口调试、自动化测试、文档管理等工作。以下是针对程序员的核心功能介绍和应用场景说明: 一、核心功能亮点 接口请求构建与调试 支持所有 HTTP 方法(GET/POS…...
Lua中os模块函数使用详解
目录 os.clock()os.date([format [, time]])os.difftime(t2, t1)os.execute(command)os.exit([code [, close]])os.getenv(varname)os.remove(filename)os.rename(oldname, newname)os.setlocale(locale [, category])os.time([table])os.tmpname()总结 以下是 Lua 中 os 模块的…...
量子计算与经典计算的拉锯战:一场关于计算未来的辩论
在计算科学领域,一场关于未来的激烈辩论正在上演。2025年3月,D-Wave量子公司的研究人员在《Science》杂志上发表了一项突破性成果,声称他们的量子退火处理器在几分钟内解决了一个经典超级计算机需要数百万年才能完成的复杂现实问题。这一声明…...