Flask桌面应用程序文件选择器
我正在尝试使用Flask来为一个桌面应用程序构建图形用户界面(也就是在本地服务器上运行的网页应用,里面嵌入了一个浏览器)。目前大部分功能都能正常工作,但我想添加一个文件选择器,让用户可以选择他们电脑上的一个文件夹。我需要这个文件夹的完整路径,所以用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('/')
这确实是个比较奇怪的情况,因为通常你不会在“服务器端”启动图形界面,但我想知道有没有办法解决这个问题,或者有没有其他方法可以用来显示文件选择对话框(最好是每个操作系统的本地对话框)。
2 个回答
我知道我这个回答晚了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
虽然我不太确定为什么程序会卡住(可能是Tk和你用来绘制网页视图的库之间有冲突?),但用户可能会让视图函数的响应时间无限延迟(在理论上,他们一直在“使用”这个视图)。
我建议你让flask的视图函数启动一个单独的线程,然后立即返回。(你可以在对话框后面加上任何你想要的背景。)这个线程负责以本地操作系统的方式处理对话框窗口,当用户选择了某个选项并完成后,再发送另一个flask请求,内部处理选中的文件。
我之前从未在桌面应用中这样做过,但我喜欢在服务器上处理长时间运行的任务时使用类似的方式(可能是启动一个单独的进程,而不是线程,但理论是相似的)。