【开源工具】:基于PyQt5的智能网络驱动器映射工具开发全流程(附源码)

🔗 【开源工具】:基于PyQt5的智能网络驱动器映射工具开发全流程

在这里插入图片描述
请添加图片描述

🌈 个人主页:创客白泽 - CSDN博客
🔥 系列专栏:🐍《Python开源项目实战》
💡 热爱不止于代码,热情源自每一个灵感闪现的夜晚。愿以开源之火,点亮前行之路。
🐋 希望大家多多支持,我们一起进步!
👍 🎉如果文章对你有帮助的话,欢迎 点赞 👍🏻 评论 💬 收藏 ⭐️ 加关注+💗分享给更多人哦

请添加图片描述
在这里插入图片描述

📖 概述

在企业IT运维和日常办公环境中,网络驱动器映射是一项基础但至关重要的功能。传统的手动映射方式不仅效率低下,而且在处理复杂网络环境时容易出错。本文将详细介绍如何使用Python的PyQt5库开发一款智能网络驱动器映射工具,该工具具备以下特点:

  • 图形化操作界面:告别命令行操作,提供直观的用户体验
  • 一键式操作:集成映射、清理、测试等完整功能链
  • 智能错误处理:自动处理常见网络连接问题
  • 持久化配置:支持重启后自动重连
  • 深度清理机制:彻底解决Windows网络连接残留问题

通过本工具的开发过程,我们不仅能掌握PyQt5的界面开发技巧,还能深入理解Windows网络驱动器的底层工作机制。

🎯 功能清单

功能模块实现要点技术亮点
驱动器映射支持IP、共享路径、凭证等完整参数多线程防阻塞、自动错误重试
连接清理彻底清除残留连接和凭据组合使用CMD命令和Win32 API
状态监控实时反馈操作状态自定义状态栏动画效果
持久化配置支持重启自动重连注册表自动配置技术
兼容性处理适配不同Windows版本自动降级处理机制

🖥️ 界面展示效果

在这里插入图片描述

在这里插入图片描述在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

▲ 工具主界面采用现代化设计,包含:

  1. 服务器连接参数输入区
  2. 凭证信息加密输入框
  3. 驱动器盘符智能选择
  4. 操作状态实时反馈区
  5. 美化后的功能按钮组

🛠️ 开发步骤详解

1. 环境准备

# 必需库安装
pip install pyqt5 pywin32

2. 核心类结构设计

在这里插入图片描述

3. 关键技术实现

3.1 Emoji图标渲染
def emoji_icon(self, emoji):"""使用QPainter绘制Emoji图标"""pixmap = QPixmap(32, 32)pixmap.fill(Qt.transparent)painter = QPainter(pixmap)font = painter.font()font.setPointSize(20)  # 调整字号控制Emoji大小painter.setFont(font)painter.drawText(pixmap.rect(), Qt.AlignCenter, emoji)painter.end()return QIcon(pixmap)
3.2 深度清理机制
def nuclear_cleanup(self, server_ip):"""组合使用多种方式确保彻底清理"""# 1. 标准net命令清理self.run_cmd("net use * /delete /y")# 2. Windows凭据管理器清理self.run_cmd(f"cmdkey /delete:\\\\{server_ip}")# 3. Win32 API强制断开windll.mpr.WNetCancelConnection2W(create_unicode_buffer(f"\\\\{server_ip}"), 0, True)# 4. 重启网络服务self.run_cmd("net stop workstation /y")time.sleep(2)self.run_cmd("net start workstation")
3.3 驱动器映射逻辑
def map_drive(self):# 参数验证if not all([server_ip, share, drive, user, pwd]):QMessageBox.warning(self, "警告", "请填写所有必填字段")return# 构造UNC路径path = f"\\\\{server_ip}\\{share}"# 执行映射命令result = self.run_cmd(f"net use {drive} {path} {pwd} /user:{user} "f"{'/persistent:yes' if self.persistent_check.isChecked() else ''}")# 结果验证if result and "成功" in result:self._verify_drive_access(drive)

🔍 代码深度解析

1. 命令执行安全机制

def run_cmd(self, command):try:result = subprocess.run(command,shell=True,check=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE,encoding='gbk',  # 中文系统编码处理text=True)return result.stdout.strip()except subprocess.CalledProcessError as e:self._handle_command_error(e)

关键点说明:

  • 使用subprocess.run()替代已废弃的os.system
  • 显式指定GBK编码解决中文乱码
  • 完整的错误捕获和处理链

2. 界面布局技巧

# 使用QHBoxLayout和QVBoxLayout嵌套实现复杂布局
connection_layout = QVBoxLayout()
ip_layout = QHBoxLayout()
ip_layout.addWidget(QLabel("🖥️ 服务器IP:"))
ip_layout.addWidget(self.ip_input)
connection_layout.addLayout(ip_layout)# 添加弹性空间使按钮居中
button_layout.addItem(QSpacerItem(20, 20, QSizePolicy.Expanding, QSizePolicy.Minimum
))

3. 样式表美化

/* 按钮悬停效果 */
QPushButton {background-color: #4CAF50;border-radius: 5px;padding: 8px;
}
QPushButton:hover {background-color: #45a049;box-shadow: 0 2px 5px rgba(0,0,0,0.2);
}/* 状态栏样式 */
QLabel#status_bar {background-color: #f5f5f5;border-radius: 5px;padding: 8px;color: #666;
}

📥 源码下载

import subprocess
import sys
import os
import time
from ctypes import windll, create_unicode_buffer
import win32wnet
import win32netcon
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit, QPushButton, QGroupBox, QCheckBox, QMessageBox, QComboBox, QSpacerItem, QSizePolicy)
from PyQt5.QtCore import Qt, QSize
from PyQt5.QtGui import QIcon, QFont, QPixmap, QPainterclass DriveMapperApp(QMainWindow):def __init__(self):super().__init__()self.setWindowTitle("网络驱动器映射工具")self.setWindowIcon(self.emoji_icon("🔗"))self.setFixedSize(500, 500)  # 稍微增大窗口尺寸# 主窗口部件self.main_widget = QWidget()self.setCentralWidget(self.main_widget)# 主布局self.main_layout = QVBoxLayout()self.main_layout.setContentsMargins(20, 20, 20, 20)  # 设置边距self.main_layout.setSpacing(15)  # 设置控件间距self.main_widget.setLayout(self.main_layout)# 初始化UIself.init_ui()def emoji_icon(self, emoji):"""创建emoji图标"""pixmap = QPixmap(32, 32)pixmap.fill(Qt.transparent)painter = QPainter(pixmap)font = painter.font()font.setPointSize(20)painter.setFont(font)painter.drawText(pixmap.rect(), Qt.AlignCenter, emoji)painter.end()return QIcon(pixmap)def init_ui(self):"""初始化用户界面"""# 标题title = QLabel("网络驱动器映射工具")title.setFont(QFont("Microsoft YaHei", 16, QFont.Bold))title.setAlignment(Qt.AlignCenter)title.setStyleSheet("margin-bottom: 15px;")self.main_layout.addWidget(title)# 连接设置组connection_group = QGroupBox("⚡ 连接设置")connection_group.setFont(QFont("Microsoft YaHei", 10))connection_layout = QVBoxLayout()connection_layout.setSpacing(12)  # 组内控件间距connection_layout.setContentsMargins(15, 15, 15, 15)  # 组内边距# 服务器IPip_layout = QHBoxLayout()ip_label = QLabel("🖥️ 服务器IP:")ip_label.setFixedWidth(100)  # 固定标签宽度ip_layout.addWidget(ip_label)self.ip_input = QLineEdit("")self.ip_input.setPlaceholderText("例如: 192.168.1.100")self.ip_input.setStyleSheet("padding: 5px;")ip_layout.addWidget(self.ip_input)connection_layout.addLayout(ip_layout)# 共享文件夹share_layout = QHBoxLayout()share_label = QLabel("📁 共享文件夹:")share_label.setFixedWidth(100)share_layout.addWidget(share_label)self.share_input = QLineEdit("")self.share_input.setPlaceholderText("例如: SharedFolder")self.share_input.setStyleSheet("padding: 5px;")share_layout.addWidget(self.share_input)connection_layout.addLayout(share_layout)# 驱动器盘符drive_layout = QHBoxLayout()drive_label = QLabel("💽 驱动器盘符:")drive_label.setFixedWidth(100)drive_layout.addWidget(drive_label)self.drive_combo = QComboBox()self.drive_combo.addItems([f"{chr(i)}:" for i in range(90, 64, -1)])self.drive_combo.setCurrentText("")self.drive_combo.setStyleSheet("padding: 5px;")drive_layout.addWidget(self.drive_combo)connection_layout.addLayout(drive_layout)# 账户信息user_layout = QHBoxLayout()user_label = QLabel("👤 用户名:")user_label.setFixedWidth(100)user_layout.addWidget(user_label)self.user_input = QLineEdit("")self.user_input.setPlaceholderText("例如: administrator")self.user_input.setStyleSheet("padding: 5px;")user_layout.addWidget(self.user_input)connection_layout.addLayout(user_layout)pwd_layout = QHBoxLayout()pwd_label = QLabel("🔑 密码:")pwd_label.setFixedWidth(100)pwd_layout.addWidget(pwd_label)self.pwd_input = QLineEdit("")self.pwd_input.setPlaceholderText("输入密码")self.pwd_input.setEchoMode(QLineEdit.Password)self.pwd_input.setStyleSheet("padding: 5px;")pwd_layout.addWidget(self.pwd_input)connection_layout.addLayout(pwd_layout)# 持久化选项self.persistent_check = QCheckBox("保持持久连接 (重启后自动重新连接)")self.persistent_check.setChecked(True)self.persistent_check.setStyleSheet("margin-top: 10px;")connection_layout.addWidget(self.persistent_check)connection_group.setLayout(connection_layout)self.main_layout.addWidget(connection_group)# 按钮区域button_layout = QHBoxLayout()button_layout.setSpacing(20)  # 按钮间距# 添加弹性空间使按钮居中button_layout.addItem(QSpacerItem(20, 20, QSizePolicy.Expanding, QSizePolicy.Minimum))# 映射按钮self.map_button = QPushButton(" 映射驱动器")self.map_button.setIcon(self.emoji_icon("🗺️"))self.map_button.setFixedSize(150, 40)  # 固定按钮大小self.map_button.setStyleSheet("""QPushButton {background-color: #4CAF50;color: white;border-radius: 5px;padding: 8px;font-weight: bold;}QPushButton:hover {background-color: #45a049;}""")self.map_button.clicked.connect(self.map_drive)button_layout.addWidget(self.map_button)# 清理按钮self.clean_button = QPushButton(" 清理连接")self.clean_button.setIcon(self.emoji_icon("🧹"))self.clean_button.setFixedSize(150, 40)self.clean_button.setStyleSheet("""QPushButton {background-color: #f44336;color: white;border-radius: 5px;padding: 8px;font-weight: bold;}QPushButton:hover {background-color: #d32f2f;}""")self.clean_button.clicked.connect(self.clean_connections)button_layout.addWidget(self.clean_button)button_layout.addItem(QSpacerItem(20, 20, QSizePolicy.Expanding, QSizePolicy.Minimum))self.main_layout.addLayout(button_layout)# 状态栏self.status_bar = QLabel("🟢 就绪")self.status_bar.setAlignment(Qt.AlignCenter)self.status_bar.setStyleSheet("""color: #666;margin-top: 10px;padding: 8px;background-color: #f5f5f5;border-radius: 5px;""")self.main_layout.addWidget(self.status_bar)def run_cmd(self, command):"""执行命令并返回输出"""try:result = subprocess.run(command,shell=True,check=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE,encoding='gbk',text=True)return result.stdout.strip()except subprocess.CalledProcessError as e:self.status_bar.setText(f"🔴 错误: {e.stderr}")return Nonedef nuclear_cleanup(self, server_ip):"""彻底清除所有可能的残留连接"""self.status_bar.setText("🧽 正在深度清理...")QApplication.processEvents()self.run_cmd("net use * /delete /y")self.run_cmd(f"net use \\\\{server_ip} /delete /y")creds = self.run_cmd("cmdkey /list")if creds and server_ip in creds:self.run_cmd(f"cmdkey /delete:\\\\{server_ip}")self.run_cmd(f"cmdkey /delete:WindowsLive:target=\\\\{server_ip}")try:windll.mpr.WNetCancelConnection2W(create_unicode_buffer(f"\\\\{server_ip}"), 0, True)win32wnet.WNetCancelConnection2(f"\\\\{server_ip}", 0, True)except Exception as e:self.status_bar.setText(f"🔴 API清理错误: {e}")self.status_bar.setText("🔄 正在重启网络服务...")QApplication.processEvents()self.run_cmd("net stop workstation /y")time.sleep(2)self.run_cmd("net start workstation")time.sleep(1)self.status_bar.setText("🟢 清理完成")def clean_connections(self):"""清理所有网络连接"""server_ip = self.ip_input.text().strip()if not server_ip:QMessageBox.warning(self, "警告", "请输入服务器IP地址")returnreply = QMessageBox.question(self, '确认','确定要清理所有网络连接吗?这可能会断开现有的网络驱动器连接。',QMessageBox.Yes | QMessageBox.No, QMessageBox.No)if reply == QMessageBox.Yes:self.nuclear_cleanup(server_ip)QMessageBox.information(self, "完成", "网络连接已清理完成")def map_drive(self):"""映射网络驱动器"""server_ip = self.ip_input.text().strip()share = self.share_input.text().strip()drive = self.drive_combo.currentText()user = self.user_input.text().strip()pwd = self.pwd_input.text()if not all([server_ip, share, drive, user, pwd]):QMessageBox.warning(self, "警告", "请填写所有必填字段")returnpath = f"\\\\{server_ip}\\{share}"persistent = "/persistent:yes" if self.persistent_check.isChecked() else ""self.status_bar.setText("🔄 正在准备映射...")QApplication.processEvents()self.nuclear_cleanup(server_ip)self.status_bar.setText(f"🔄 正在映射 {path}{drive}...")QApplication.processEvents()result = self.run_cmd(f"net use {drive} {path} {pwd} /user:{user} {persistent}")if result:self.status_bar.setText(f"🟢 成功映射 {path}{drive}")QMessageBox.information(self, "成功", f"网络驱动器已成功映射到 {drive}")test_result = self.run_cmd(f"dir {drive}")if test_result:self.status_bar.setText(f"🟢 访问测试成功: {drive} 驱动器内容可读")else:self.status_bar.setText(f"🟡 映射成功但访问测试失败")else:self.status_bar.setText("🔴 映射失败")QMessageBox.critical(self, "错误", "驱动器映射失败!\n\n""请尝试以下解决方案:\n""1. 手动执行清理操作\n""2. 重启计算机后重试\n""3. 检查服务器端的共享权限设置")if __name__ == "__main__":app = QApplication(sys.argv)app.setStyle('Fusion')  # 使用Fusion风格使界面更现代window = DriveMapperApp()window.show()sys.exit(app.exec_())

🏆 总结与展望

通过本项目的开发,我们实现了:

  1. 生产级工具开发:从需求分析到完整实现的全流程
  2. PyQt5深度应用:复杂界面布局和自定义组件开发
  3. 系统集成技巧:Windows网络API的混合调用
  4. 异常处理体系:健壮的错误处理机制

未来可扩展方向:

  • 增加批量映射功能
  • 集成网络诊断工具
  • 添加映射配置导出/导入
  • 开发自动重连监控服务

技术箴言:一个好的工具类程序应该像瑞士军刀——小巧但功能完备,简单但可靠耐用。本项目的设计正是遵循这一理念。


附录:常见问题解答

Q: 为什么需要多种清理方式组合使用?
A: Windows网络连接可能残留在不同层级(会话层、凭据管理器、注册表等),单一清理方式往往无法彻底解决问题。

Q: 如何适配不同Windows版本?
A: 可通过sys.getwindowsversion()检测系统版本,对Win7等老系统采用兼容模式。

Q: 密码字段如何增强安全性?
A: 可集成Windows DPAPI加密存储密码,或使用第三方库如keyring

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/436.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

MySQL 索引学习笔记

1.二叉树,红黑树,B 树,B树 二叉树:就是每个节点最多只能有两个子节点的树; 红黑树:就是自平衡二叉搜索树,红黑树通过一下五个规则构建: 1.节点只能是红色或黑色; 2.根…

嵌入式通信模块实战新范式:基于虚拟仿真平台的NB-IoT核心技能训练——零硬件损耗的全栈式实验方案,重构物联网通信教学逻辑

在万物智联时代,NB-IoT通信模块已成为低功耗广域网的基石。BC260Y作为行业主流模组,其AT指令控制与网络诊断能力是嵌入式开发者的必备技能。传统教学受限于硬件采购成本、设备管理难度及实验风险,难以开展规模化训练。嵌入式仿真实验教学平台…

docker compose的变量使用说明

澄清一下 x-shared-env 和 &shared-api-worker-env 的作用范围: 核心概念:Docker Compose 配置 vs 容器环境 x-shared-env: &shared-api-worker-env 是 Docker Compose 配置的一部分 这些定义仅在 Docker Compose 解析 YAML 文件时 有效它们定义…

美团完整面经

面试岗位 面试的岗位 - 2025春季校招 【转正实习】软件服务工程师-后端方向(成都 - 软硬件服务-SaaS事业部) 一面(业务初试 - 30min) 问题 自我介绍 Java基础 HashMap底层用的数据结构是什么?是线程安全的吗&…

JAVA毕业设计227—基于SpringBoot+hadoop+spark+Vue的大数据房屋维修系统(源代码+数据库)

毕设所有选题: https://blog.csdn.net/2303_76227485/article/details/131104075 基于SpringBoothadoopsparkVue的大数据房屋维修系统(源代码数据库)227 一、系统介绍 本项目前后端分离,分为业主、维修人员、管理员三种角色 1、业主: 登…

uniapp 页面栈一定深度后,回首页导航到新页面的解决方案

uniapp 页面栈一定深度后,回首页导航到新页面的解决方案 uniapp 页面导航解决方案 在 uniapp 中,要实现先弹出页面栈回到首页,然后再跳转到指定页面。 /*** description 后台选择链接专用跳转*/ interface Link {path: string;name?: stri…

java实现Google邮箱SMTP协议

一、开通Google的SMTP协议 在谷歌邮箱中开启IMAP访问 到google的设置中开启两步验证功能 在到 创建和管理应用专用密码 二、java中实现 引入maven <!--邮件--><dependency><groupId>com.sun.mail</groupId><artifactId>javax.mail</artif…

【2025最新】Adobe Illustrator下载保姆级安装教程(附官方下载链接)

文章目录 Adobe Illustrator 2024新功能介绍如何提高Adobe Illustrator的运行效率 Adobe Illustrator 这款神器相信不用我多介绍了吧&#xff0c;设计师们的得力助手&#xff01;最新的2025版据说功能和体验都提升了不少。这篇呢&#xff0c;算是我个人整理的一个超详细adobe i…

2025.06.11【Ribo-seq】|根据注释文件获取外显子及ORF序列

文章目录 一、准备材料二、提取外显子区间为BED文件1. 提取GTF中exon为BED 三、用bedtools提取外显子fasta四、后续拼接外显子为ORF序列五、流程总结 一、准备材料 基因组fasta&#xff08;如&#xff1a;genome.fa&#xff09;RiboCode生成的GTF文件&#xff08;如&#xff1…

python第48天打卡

知识点回顾&#xff1a; 随机张量的生成&#xff1a;torch.randn函数卷积和池化的计算公式&#xff08;可以不掌握&#xff0c;会自动计算的&#xff09;pytorch的广播机制&#xff1a;加法和乘法的广播机制 ps&#xff1a;numpy运算也有类似的广播机制&#xff0c;基本一致 作…

Day50 Python打卡训练营

知识点回顾&#xff1a; 1. resnet结构解析 2. CBAM放置位置的思考 3. 针对预训练模型的训练策略 a. 差异化学习率 b. 三阶段微调 现在我们思考下&#xff0c;是否可以对于预训练模型增加模块来优化其效果&#xff0c;这里我们会遇到一个问题 预训练模型的结构和权重是固定…

leetcode:42. 接雨水(秒变简单题)

题目要求 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图&#xff0c;计算按此排列的柱子&#xff0c;下雨之后能接多少雨水。 要求给出一列柱子&#xff0c;求该柱子能盛放多少雨水 解题思路&#xff1a; 这些柱子围城了一个“盆地”&#xff0c;雨水会积攒在低洼处&…