文章目录
前言
在PyQt5的GUI开发中,文件浏览器是非常经典的应用场景,它不仅能帮助开发者理解文件系统操作逻辑,还能深入掌握PyQt5中多个核心类的使用。本文将围绕文件浏览器的实现,详细讲解QDir(目录操作)、QListWidget(列表显示)、QProcess(外部进程交互)三个关键类的功能与用法,同时结合界面布局、用户交互逻辑,完整呈现文件浏览器的开发流程,适合有一定PyQt5基础,想要进阶学习文件操作与GUI结合的开发者。
一、文件浏览器整体设计思路
文件浏览器的核心需求是实现目录导航、文件/文件夹展示、文件打开等功能,整体设计需包含界面布局和业务逻辑两部分,具体如下:
1.1 界面布局设计
采用PyQt5的布局管理器(QHBoxLayout+QVBoxLayout)实现灵活适配,界面组件包括:
- 返回按钮:用于切换到上一级目录。
- 单行文本框(QLineEdit):实时显示当前目录的绝对路径,方便用户查看路径信息。
- 列表控件(QListWidget):展示当前目录下的所有文件和文件夹,支持双击交互。
布局结构:
- 先用
QHBoxLayout将“返回按钮”和“单行文本框”横向排列,文本框占比更大以完整显示路径。 - 再用
QVBoxLayout将上述横向布局与QListWidget纵向排列,形成完整界面。
1.2 核心业务逻辑
- 初始化:启动程序时,默认定位到某个初始目录(如当前工作目录),获取目录下的文件/文件夹信息,展示在
QListWidget中,并在文本框显示当前路径。 - 目录切换:
- 双击
QListWidget中的文件夹项:切换到该子目录,重新加载目录内容并更新路径。 - 点击“返回按钮”:尝试切换到上一级目录,若当前已是根目录则不操作。
- 双击
- 文件打开:双击
QListWidget中的文件项:通过QProcess启动外部程序(如记事本)打开该文件。 - 目录内容筛选:使用
QDir的筛选器,过滤不需要显示的内容(如.、..条目、隐藏文件等)。
二、核心类详解与用法
文件浏览器的实现依赖QDir、QListWidget(含QListWidgetItem)、QProcess三个核心类,以下分别讲解其导入方式、常用方法、典型场景及代码示例。
2.1 QDir:目录操作的核心类
QDir属于PyQt5.QtCore模块,提供跨平台的目录操作能力,可实现目录创建、删除、内容列表、路径解析等功能,是文件浏览器获取目录信息的基础。
2.1.1 导入方式
from PyQt5.QtCore import QDir
2.1.2 常用方法与示例
1. 创建QDir对象
通过指定路径初始化,若路径为空则默认对应当前工作目录:
# 初始化指定目录
dir = QDir("D:/code/PyQt5")
# 初始化当前工作目录
current_dir = QDir()
2. 目录内容列表(关键)
通过entryList()或entryInfoList()获取目录内容,前者返回文件名列表,后者返回QFileInfo对象列表(含文件类型、大小等详细信息),支持通过筛选器过滤内容。
常用筛选器(预定义常量):
QDir.AllEntries:列出所有条目(文件、子目录、符号链接)。QDir.AllDirs:仅列出目录。QDir.Files:仅列出文件。QDir.NoDotAndDotDot:不列出.(当前目录)和..(父目录),文件浏览器必用。QDir.Hidden:显示隐藏文件/目录。QDir.CaseSensitive:文件名比较区分大小写。
示例:获取目录下所有文件和目录(排除.和..):
# 设置筛选器:排除.和..,显示所有文件和目录
filters = QDir.NoDotAndDotDot | QDir.Files | QDir.AllDirs
# 获取文件名列表
file_names = dir.entryList(filters)
# 获取QFileInfo列表(含详细信息)
file_infos = dir.entryInfoList(filters)
# 遍历QFileInfo列表,区分文件和目录
for info in file_infos:
if info.isDir():
print(f"目录:{info.fileName()}")
elif info.isFile():
print(f"文件:{info.fileName()},大小:{info.size()}字节")
3. 目录状态检查
判断目录是否存在、可读、是否为绝对路径等:
# 检查目录是否存在
if dir.exists():
print("目录存在")
else:
print("目录不存在")
# 检查目录是否可读
if dir.isReadable():
print("目录可读")
# 检查路径是否为绝对路径
if dir.isAbsolute():
print("当前路径是绝对路径")
else:
print("当前路径是相对路径")
4. 目录创建与删除
mkdir():创建子目录(仅创建一级)。mkpath():创建多级子目录(如a/b/c)。rmdir():删除空目录(非空目录无法删除)。
示例:
# 创建一级子目录
if dir.mkdir("new_dir"):
print("子目录创建成功")
else:
print("子目录创建失败(可能已存在)")
# 创建多级子目录
if dir.mkpath("a/b/c"):
print("多级子目录创建成功")
# 删除空目录
if dir.rmdir("new_dir"):
print("子目录删除成功")
5. 路径操作
absolutePath():获取目录的绝对路径(文件浏览器中用于更新文本框显示)。cd():切换到指定子目录。cdUp():切换到上一级目录(文件浏览器“返回”功能核心)。relativeFilePath():将绝对路径转换为相对于当前目录的相对路径。
示例:
# 获取绝对路径
abs_path = dir.absolutePath()
print(f"绝对路径:{abs_path}")
# 切换到子目录
if dir.cd("new_dir"):
print(f"切换到子目录:{dir.absolutePath()}")
else:
print("子目录不存在,切换失败")
# 切换到上一级目录
if dir.cdUp():
print(f"返回上一级:{dir.absolutePath()}")
# 转换为相对路径
abs_file_path = "D:/code/PyQt5/test.py"
rel_path = dir.relativeFilePath(abs_file_path)
print(f"相对路径:{rel_path}")
6. 文件过滤(按后缀)
通过setNameFilters()设置文件名过滤器,仅显示指定后缀的文件:
# 仅显示.txt和.py文件
dir.setNameFilters(["*.txt", "*.py"])
filtered_files = dir.entryList(QDir.Files | QDir.NoDotAndDotDot)
print("筛选后的文件:", filtered_files)
2.1.3 典型应用场景
- 文件浏览器中获取目录内容并区分文件/目录。
- 动态创建/删除目录(如程序日志目录)。
- 路径解析与转换(绝对路径→相对路径)。
- 跨平台路径适配(自动处理Windows的
\和Linux的/)。
2.2 QListWidget与QListWidgetItem:列表显示与交互
QListWidget是PyQt5.QtWidgets模块中的列表控件,用于展示条目列表;QListWidgetItem则表示列表中的单个条目,支持文本、图标、复选框等功能,二者结合实现文件浏览器的目录内容显示与交互。
2.2.1 导入方式
from PyQt5.QtWidgets import QListWidget, QListWidgetItem
from PyQt5.QtGui import QIcon # 用于设置条目图标
from PyQt5.QtCore import Qt # 用于设置条目状态(如复选框)
2.2.2 QListWidget常用方法
addItem():添加QListWidgetItem条目。clear():清空所有条目(目录切换时必用)。itemDoubleClicked:信号,当条目被双击时触发(文件打开/目录切换的核心信号)。currentItem():获取当前选中的条目。
示例:初始化QListWidget并添加条目:
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QApplication, QListWidget, QWidget, 
QVBoxLayout,QListWidgetItem
import sys
app = QApplication(sys.argv)
window = QWidget()
window.setWindowTitle("QListWidget示例")
# 创建QListWidget
list_widget = QListWidget()
# 添加条目(文本+图标)
# 目录图标(可替换为自定义图标路径)
dir_icon = QIcon.fromTheme("folder")
# 文件图标
file_icon = QIcon.fromTheme("file")
# 添加目录条目
dir_item = QListWidgetItem(dir_icon, "文档目录")
list_widget.addItem(dir_item)
# 添加文件条目
file_item = QListWidgetItem(file_icon, "笔记.txt")
list_widget.addItem(file_item)
# 布局
layout = QVBoxLayout(window)
layout.addWidget(list_widget)
# 双击信号绑定(后续讲解)
def on_item_double_clicked(item):
print(f"双击条目:{item.text()}")
list_widget.itemDoubleClicked.connect(on_item_double_clicked)
window.show()
sys.exit(app.exec_())
输出结果为

2.2.3 QListWidgetItem常用方法
1. 创建条目
支持仅文本、文本+图标两种方式:
# 仅文本
item1 = QListWidgetItem("test.py")
# 文本+图标
item2 = QListWidgetItem(QIcon("file.png"), "report.txt")
2. 文本与图标设置
setText():修改条目文本。text():获取条目文本。setIcon():设置条目图标(文件浏览器中用于区分文件/目录)。icon():获取条目图标。
示例:
item = QListWidgetItem("old_name.txt")
# 修改文本
item.setText("new_name.txt")
# 设置图标
item.setIcon(QIcon("file.png"))
print(f"条目文本:{item.text()}")
3. 复选框功能
通过setCheckState()设置复选状态,支持多选场景(如文件批量操作):
# 设置复选框为选中状态
item.setCheckState(Qt.Checked)
# 设置复选框为未选中状态
item.setCheckState(Qt.Unchecked)
# 获取复选状态
if item.checkState() == Qt.Checked:
print(f"条目 {item.text()} 已选中")
4. 附加自定义数据
通过setData()和data()为条目附加自定义数据(如文件绝对路径),解决“条目文本≠完整路径”的问题:
# 附加文件绝对路径(使用Qt.UserRole作为角色标识)
item.setData(Qt.UserRole, "D:/code/test.py")
# 获取附加数据
file_path = item.data(Qt.UserRole)
print(f"条目对应的文件路径:{file_path}")
5. 工具提示与可用性
setToolTip():鼠标悬停时显示提示信息(如文件大小、修改时间)。setFlags():设置条目是否可选、可编辑(文件浏览器中通常设为“可选+可用”)。
示例:
# 设置工具提示
item.setToolTip("这是一个Python脚本文件")
# 设置条目为可选且可用
item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
2.2.4 典型应用场景
- 文件浏览器中显示目录下的文件/目录条目(区分图标)。
- 双击条目触发文件打开或目录切换。
- 批量操作(如复选框选择多个文件删除)。
- 条目附加自定义数据(如文件路径、类型)。
2.3 QProcess:外部进程交互
QProcess属于PyQt5.QtCore模块,用于启动外部程序(如记事本、Python脚本)并与之交互,是文件浏览器“打开文件”功能的核心。
2.3.1 导入方式
from PyQt5.QtCore import QProcess
2.3.2 常用方法与示例
1. 启动进程(关键)
start(program, arguments):异步启动外部程序,program为程序路径/命令,arguments为参数列表(可选)。execute(program, arguments):同步启动外部程序,阻塞当前线程直到程序结束,返回退出码。
示例1:用记事本打开文本文件(文件浏览器核心功能):
def open_file(file_path):
process = QProcess()
# Windows:notepad.exe打开文件;Linux:gedit;macOS:open
# 跨平台适配可通过QDir判断系统
if QDir.separator() == "\\": # Windows系统
program = "notepad.exe"
else: # Linux/macOS
program = "gedit" if QDir("/usr/bin/gedit").exists() else "open"
# 启动进程:打开指定文件
process.start(program, [file_path])
# 检查进程是否启动成功
if not process.waitForStarted(3000): # 等待3秒
print(f"启动程序失败:{program}")
示例2:同步执行系统命令(如ls -l):
# 执行ls -l命令(Linux/macOS)
exit_code = QProcess.execute("ls", ["-l"])
print(f"命令退出码:{exit_code}")
2. 读取进程输出
通过readAllStandardOutput()和readAllStandardError()获取外部程序的标准输出和错误输出,通常结合信号readyReadStandardOutput实时读取:
process = QProcess()
# 实时读取标准输出
def read_output():
output = process.readAllStandardOutput().data().decode("utf-8")
if output:
print(f"程序输出:{output}")
# 实时读取标准错误
def read_error():
error = process.readAllStandardError().data().decode("utf-8")
if error:
print(f"程序错误:{error}")
# 绑定信号
process.readyReadStandardOutput.connect(read_output)
process.readyReadStandardError.connect(read_error)
# 启动进程(示例:执行Python脚本并查看输出)
process.start("python", ["test.py"])
3. 监控进程状态
waitForFinished(msecs):等待进程结束(超时时间,单位毫秒)。state():获取进程状态(QProcess.NotRunning/QProcess.Starting/QProcess.Running)。exitCode():获取进程退出码(0通常表示成功)。
示例:
process = QProcess()
process.start("notepad.exe", ["test.txt"])
# 等待进程结束(超时10秒)
if process.waitForFinished(10000):
print(f"进程正常结束,退出码:{process.exitCode()}")
else:
print("进程超时未结束,强制终止")
process.kill() # 强制终止进程
4. 信号与槽(常用)
started:进程启动时触发。finished(exit_code):进程结束时触发,返回退出码。readyReadStandardOutput:有标准输出可读时触发。
示例:绑定进程结束信号:
def on_process_finished(exit_code):
print(f"进程结束,退出码:{exit_code}")
process = QProcess()
process.finished.connect(on_process_finished)
process.start("notepad.exe", ["test.txt"])
2.3.3 典型应用场景
- 文件浏览器中打开文件(调用系统默认程序或指定程序)。
- 执行外部脚本(如Python、Shell脚本)并获取结果。
- 实时监控外部程序输出(如日志打印)。
- 跨平台执行系统命令(如Windows的
ping、Linux的ifconfig)。
三、文件浏览器完整代码实现
from PyQt5.QtWidgets import (QApplication, QWidget, QVBoxLayout, QHBoxLayout,
QPushButton, QLineEdit, QListWidget, QListWidgetItem)
from PyQt5.QtCore import QDir, QProcess, Qt
from PyQt5.QtGui import QIcon
import sys
class FileBrowser(QWidget):
def __init__(self):
super().__init__()
# 初始化界面(按文档要求采用水平+垂直布局)
self.init_ui()
# 初始化当前目录(文档逻辑:默认加载当前目录)
self.current_dir = QDir()
# 加载当前目录下的文件与文件夹列表
self.load_dir_content()
def init_ui(self):
# 窗口基础设置
self.setWindowTitle("PyQt5文件浏览器")
self.resize(800, 600)
# 1. 水平布局(文档要求:按钮和文本框放在QHBoxLayout)
top_h_layout = QHBoxLayout()
# 返回上一级按钮(文档核心界面组件)
self.back_btn = QPushButton("返回上一级目录")
self.back_btn.clicked.connect(self.switch_to_parent_dir)
# 显示当前目录路径的单行文本框(文档核心界面组件)
self.path_edit = QLineEdit()
self.path_edit.setReadOnly(True) # 路径仅显示,不允许编辑
# 将按钮和文本框添加到水平布局,文本框占满剩余空间
top_h_layout.addWidget(self.back_btn)
top_h_layout.addWidget(self.path_edit)
top_h_layout.setStretchFactor(self.path_edit, 1)
# 2. QListWidget(文档要求:显示当前目录下所有文件夹及文件列表)
self.file_list_widget = QListWidget()
# 绑定双击信号(文档逻辑:双击处理文件打开/目录切换)
self.file_list_widget.itemDoubleClicked.connect(self.handle_item_double_click)
# 3. 垂直布局(文档要求:水平布局和QListWidget放在QVBoxLayout)
main_v_layout = QVBoxLayout(self)
main_v_layout.addLayout(top_h_layout)
main_v_layout.addWidget(self.file_list_widget)
def load_dir_content(self):
"""按文档逻辑:读取当前目录内容,添加到QListWidget"""
# 清空列表(避免目录切换时内容叠加)
self.file_list_widget.clear()
# 更新文本框显示当前目录绝对路径(文档QDir的absolutePath()方法)
self.path_edit.setText(self.current_dir.absolutePath())
# 文档预定义筛选器:排除"."(当前目录)和".."(父目录),显示所有文件和文件夹
filters = QDir.NoDotAndDotDot | QDir.Files | QDir.AllDirs
# 读取目录下文件/文件夹的详细信息(文档QDir的entryInfoList()方法)
file_info_list = self.current_dir.entryInfoList(filters)
# 区分文件与文件夹图标(提升视觉识别性)
dir_icon = QIcon.fromTheme("folder") # 文件夹图标
file_icon = QIcon.fromTheme("file") # 文件图标
# 循环添加条目到QListWidget(文档步骤:挨个添加文件/文件夹信息)
for info in file_info_list:
if info.isDir():
# 文件夹条目:图标+名称,附加绝对路径(便于后续切换)
item = QListWidgetItem(dir_icon, info.fileName())
else:
# 文件条目:图标+名称,附加绝对路径(便于后续打开)
item = QListWidgetItem(file_icon, info.fileName())
# 附加文件大小作为工具提示(优化用户体验)
item.setToolTip(f"文件大小:{info.size()} 字节")
# 用Qt.UserRole存储文件/文件夹绝对路径(文档QListWidgetItem的setData()思路)
item.setData(Qt.UserRole, info.absoluteFilePath())
self.file_list_widget.addItem(item)
def switch_to_parent_dir(self):
"""按文档逻辑:点击返回按钮,切换到上一级目录"""
# 文档QDir的cdUp()方法:返回True表示切换成功
if self.current_dir.cdUp():
# 切换成功后重新加载目录内容(文档步骤:重复3.4.5步骤)
self.load_dir_content()
# 切换失败(如当前已是根目录)则不操作(文档逻辑)
def handle_item_double_click(self, item):
"""按文档逻辑:双击条目,区分文件/文件夹处理"""
# 获取条目附加的绝对路径(文档QListWidgetItem的data()思路)
target_path = item.data(Qt.UserRole)
target_dir = QDir(target_path)
if target_dir.isDir():
# 双击的是文件夹:切换目录并重新加载内容(文档步骤:切换目录,重复3.4.5)
self.current_dir = target_dir
self.load_dir_content()
else:
# 双击的是文件:用外部程序打开(文档逻辑:调用记事本打开文件)
self.open_file_with_process(target_path)
def open_file_with_process(self, file_path):
"""按文档逻辑:用QProcess启动外部程序打开文件"""
# 初始化QProcess(文档核心类:用于启动外部进程)
process = QProcess()
# 文档格式:Windows下用记事本打开,其他系统适配基础打开方式
if QDir.separator() == "\\":
# Windows系统:调用notepad.exe打开文件(文档推荐程序)
program = "notepad.exe"
arguments = [file_path]
else:
# Linux/macOS:用系统默认文本编辑器打开
program = "gedit" if QDir("/usr/bin/gedit").exists() else "open"
arguments = [file_path] if program == "gedit" else ["-a", "TextEdit", file_path]
# 文档QProcess的start()方法:启动外部程序
process.start(program, arguments)
# 检查程序是否启动成功(超时3秒,避免阻塞)
if not process.waitForStarted(3000):
print(f"启动程序失败:{program}")
if __name__ == "__main__":
# 程序入口:初始化应用并显示窗口
app = QApplication(sys.argv)
browser = FileBrowser()
browser.show()
sys.exit(app.exec_())
输出结果可以自己试一下,生成了一个文件浏览器窗口
总结
本文通过实现一个简单的文件浏览器,深入讲解了PyQt5中三个核心类:QDir、QListWidget和QProcess的用法。以下是关键点回顾:
- 设计思路
界面布局:采用水平布局(返回按钮和路径显示)和垂直布局(整体结构)相结合,确保界面整洁且自适应。
业务逻辑:包括初始化当前目录、双击目录切换、返回上一级、双击文件用默认程序打开等。
- 核心类详解
QDir:用于目录操作,如获取目录内容、切换目录、判断目录是否存在等。我们使用entryInfoList方法获取目录下的文件和文件夹信息,并利用过滤器排除不必要的条目(如.和…)。
QListWidget和QListWidgetItem:用于显示目录内容。每个条目都是一个QListWidgetItem,可以设置图标、文本和附加数据(如绝对路径)。通过双击条目触发相应的操作(切换目录或打开文件)。
QProcess:用于启动外部程序来打开文件。我们根据操作系统选择适当的程序(如Windows的记事本,Linux的gedit或macOS的open命令)。
656

被折叠的 条评论
为什么被折叠?



