Flask桌面应用程序文件选择器

3 投票
2 回答
3416 浏览
提问于 2025-04-18 07:10

我正在尝试使用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 个回答

1

我知道我这个回答晚了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
2

虽然我不太确定为什么程序会卡住(可能是Tk和你用来绘制网页视图的库之间有冲突?),但用户可能会让视图函数的响应时间无限延迟(在理论上,他们一直在“使用”这个视图)。

我建议你让flask的视图函数启动一个单独的线程,然后立即返回。(你可以在对话框后面加上任何你想要的背景。)这个线程负责以本地操作系统的方式处理对话框窗口,当用户选择了某个选项并完成后,再发送另一个flask请求,内部处理选中的文件。

我之前从未在桌面应用中这样做过,但我喜欢在服务器上处理长时间运行的任务时使用类似的方式(可能是启动一个单独的进程,而不是线程,但理论是相似的)。

撰写回答