我正在尝试使用 Flask 为桌面应用程序构建 GUI(即在与嵌入式浏览器捆绑在本地运行的服务器上运行的 Web 应用程序)。目前看来一切正常,但我想添加一个文件选择器以允许用户选择计算机上的目录。我需要目录的完整路径,因此使用 HTML/JavaScript 打开对话框将不起作用(由于安全限制)。
我尝试做的是当按下页面上的按钮时启动 Tkinter 文件对话框。问题是,虽然它似乎确实启动了某些东西,但该过程只是冻结(不显示窗口)并且我被迫终止它,之后页面重定向到“/view_1_actions”并且我收到“错误代码:ERR_EMPTY_RESPONSE” “错误(即 Flask 应用程序仅在我杀死看似对话窗口的内容后才会崩溃)。
这是我的代码:
HTML:
<form action="/view_1_actions" method="post">
<input type="submit" name="submit" value="Select"></input>
</form>
Python:
from flask import Flask, request, redirect
from Tkinter import Tk
from tkFileDialog import askdirectory
@app.route('/view_1_actions', methods = ['POST'])
def view_1_actions():
if request.form['submit'] == 'Select':
Tk().withdraw()
dirname = askdirectory()
return redirect('/')
承认这是一个相当奇怪的场景,因为您通常不会在“服务器端”启动图形界面,但我的问题是是否有办法解决这个问题或我可以用来显示文件选择器对话框的替代解决方案(最好是每个操作系统的本机版本)。
虽然我不确定进程冻结(也许 Tk 和您用来绘制 Web 视图的库之间存在冲突?),但用户可以无限期地延迟视图函数的响应(所有而理论上“使用”视图)。
我建议让 Flask 视图函数启动/发送消息到一个单独的线程,然后立即返回。 (在对话框后面使用您想要的任何背景。)另一个线程负责以本机操作系统方式执行对话框窗口,然后当用户选择某些内容并完成时,在内部发送另一个烧瓶请求,该请求将执行它需要执行的任何操作与选定的文件。
我以前从未在桌面应用程序中这样做过,但它的一些变体(可能是一个单独的进程而不是单独的线程,但理论是相似的)是我喜欢在服务器上处理长时间运行的任务的方式。
我知道我在 7 年后回答,但如果有人面临同样的问题,我找到了一个不正确但棘手的解决方案。
在发布请求中,我发送用户以前的文件名。
我使用 tkinter 打开文件对话框。一旦用户选择一个文件,我就会销毁 tkinter。
我可以获取文件路径,而不会出现“主线程不在主循环中”的问题。
import tkinter as tk
from tkinter.filedialog import askopenfilename
@equity.route('api/filedialog', methods = ['POST'])
def open_filedialog():
"""open file dialog to get a file name"""
print(request.json)
filename = 'not found'
root = tk.Tk()
filename = askopenfilename()
root.withdraw()
if filename == 'not found':
root.mainloop()
else:
root.destroy()
#if filename selected new file name
if filename:
return jsonify({'file' : filename}), 200
#else old file name
else:
return jsonify(request.json), 200
我面临着类似的问题,所以我创建了一个名为filedialpy的小包来在python中打开本机文件对话框:https://github.com/e-sollier/filedialpy。它适用于 Linux、Windows 和 macOS,并在 Linux 上使用 zenity 或 kdialog,在 Windows 上使用 pywin32,在 macOS 上使用 applescript。
使用示例:
import filedialpy
f=filedialpy.openFile() # Open a single file (return a string)
d=filedialpy.openDir() # Open a directory (return a string)