如何在QFileDialog中选择应用执行重解析点并正常返回路径
问题描述
当使用QFileDialog从%LocalAppData%\Microsoft\WindowsApps路径(例如julia.exe)选择重解析点并点击Open按钮时,会弹出错误对话框。点击Ok仅关闭错误对话框,不会关闭文件浏览器窗口。
复现代码
from PySide6.QtWidgets import QApplication, QDialog, QPushButton, QFileDialog, QLineEdit, QVBoxLayout class Main(QDialog): def __init__(self): super().__init__() self.button = QPushButton("Browse") self.le = QLineEdit() self.lo = QVBoxLayout() self.lo.addWidget(self.button) self.lo.addWidget(self.le) self.setLayout(self.lo) self.button.clicked.connect(self.open_browser) def open_browser(self): self.le.clear() answer = QFileDialog.getOpenFileName(self, "Open") if answer[0] != "": self.le.setText(answer[0]) return if __name__ == '__main__': app = QApplication() window = Main() window.show() app.exec()
核心需求
已知%LocalAppData%\Microsoft\WindowsApps已在PATH环境变量中,但用户可能会选择该路径下的重解析点文件,需解决:
- 如何让QFileDialog选中重解析点文件后返回其路径?
- 能否捕获触发错误的异常,直接返回完整路径作为代码中的
answer?
环境信息
- Windows 10
- Python 3.10.8
- PySide6 6.5.2
已尝试无效方案
- 直接使用QFileDialog构造函数调用
open(),问题依旧; - 在
QDialog.accepted信号槽中捕获错误,触发时机过晚,错误对话框已弹出; - 使用
QFileDialog::DontResolveSymlinks选项,仍弹出错误对话框; - 考虑使用Qt自带文件浏览器
QFileDialog::DontUseNativeDialog,但不想改变Windows用户习惯的原生浏览器。
解决方案
方法1:通过Windows API钩子拦截原生对话框结果
利用Windows钩子直接获取原生文件对话框的选中路径,绕过Qt对重解析点的错误处理逻辑:
- 安装依赖库:
pip install pywin32
- 修改代码实现:
import win32gui import win32api import win32con from PySide6.QtWidgets import QApplication, QDialog, QPushButton, QFileDialog, QLineEdit, QVBoxLayout class Main(QDialog): def __init__(self): super().__init__() self.button = QPushButton("Browse") self.le = QLineEdit() self.lo = QVBoxLayout() self.lo.addWidget(self.button) self.lo.addWidget(self.le) self.setLayout(self.lo) self.button.clicked.connect(self.open_browser) self.selected_path = "" def hook_proc(self, hwnd, msg, wparam, lparam): if msg == win32con.WM_COMMAND and wparam == 1: # 捕获Open按钮点击事件 # 获取选中文件的完整路径 buffer = win32gui.SendMessage(hwnd, win32con.CDM_GETFILEPATH, 260, 0) self.selected_path = buffer.decode('utf-16').rstrip('\x00') return win32gui.CallNextHookEx(self.hook, msg, wparam, lparam) def open_browser(self): self.le.clear() self.selected_path = "" # 设置线程钩子,监听对话框消息 self.hook = win32gui.SetWindowsHookEx(win32con.WH_CALLWNDPROC, self.hook_proc, None, win32api.GetCurrentThreadId()) # 调用原生文件对话框 QFileDialog.getOpenFileName(self, "Open") # 卸载钩子 win32gui.UnhookWindowsHookEx(self.hook) # 使用钩子捕获的路径更新输入框 if self.selected_path: self.le.setText(self.selected_path) if __name__ == '__main__': app = QApplication() window = Main() window.show() app.exec()
方法2:路径检查绕过Qt解析
在用户选择文件后,直接使用对话框返回的路径字符串,避免Qt尝试解析重解析点:
import os from PySide6.QtWidgets import QApplication, QDialog, QPushButton, QFileDialog, QLineEdit, QVBoxLayout LOCAL_APPS_PATH = os.path.expandvars("%LocalAppData%\\Microsoft\\WindowsApps") class Main(QDialog): def __init__(self): super().__init__() self.button = QPushButton("Browse") self.le = QLineEdit() self.lo = QVBoxLayout() self.lo.addWidget(self.button) self.lo.addWidget(self.le) self.setLayout(self.lo) self.button.clicked.connect(self.open_browser) def open_browser(self): self.le.clear() dialog = QFileDialog(self, "Open") dialog.setFileMode(QFileDialog.ExistingFile) if dialog.exec(): selected_files = dialog.selectedFiles() if selected_files: path = selected_files[0] # 直接使用路径,不依赖Qt的解析结果 self.le.setText(path) if __name__ == '__main__': app = QApplication() window = Main() window.show() app.exec()
方案说明
- 方法1通过Windows底层API直接获取选中路径,完全绕过Qt的错误处理,能稳定返回重解析点路径;
- 方法2简化了逻辑,直接使用对话框返回的路径字符串,避免Qt触发重解析点的错误检查;
- 两种方案均保留了Windows原生文件对话框,符合用户操作习惯。
内容的提问来源于stack exchange,提问作者ptsavol
相关产品推荐
相关产品推荐

