Python、Dash:Tkinter 打开文件对话框仅在第一次时工作正常但之后失败

Python, Dash: Tkinter openfile dialog works fine only the first time but fails afterwards

我已经为下面的代码苦苦挣扎了一整天了。

import webbrowser
import dash
from dash import html, dcc
from dash.dependencies import Input, Output, State
from Open_Save_File import open_file_dialog

import tkinter
from tkinter import filedialog as fd

FILE_DIR = 'H:/Codes/'

webbrowser.get('windows-default').open('http://localhost:8050', new=2)

external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)

app.layout = html.Div([
    html.H4('Update my list',
            style={
                'textAlign': 'center'
            }),
    html.Br(),
    html.Hr(),
    
    html.Div([
        html.H5('Excel Directory:', 
                style = {'width': '20%', 'display': 'inline-block', \
                    'text-align': 'left'}),
        html.Div(id='selected_directory', children='No file selected!', \
            style={'width': '30%', 'display': 'inline-block'}),
        html.Button('Browse', id='open_excel_button', \
            n_clicks=0, style={'float': 'right', 'display': 'inline-block'})
    ]),
])

# 1. Callback for open_excel button
@app.callback(
    Output(component_id='selected_directory', component_property='children'),
    Input(component_id='open_excel_button', component_property='n_clicks'),
    prevent_initial_call=True
)
def open_excel_function(open_excel): 
    print ('*** 1A. Callback open_file_dialog')
    ctx = dash.callback_context
    trigger = ctx.triggered[0]['prop_id'].split('.')[0]
    print("***", trigger, "is triggered.")
    root = tkinter.Tk()
    root.withdraw()
    # root.iconbitmap(default='Extras/transparent.ico')
    if trigger == 'open_excel_button':
        file_directory = tkinter.filedialog.askopenfilename(initialdir=FILE_DIR) <-- Source of all evil....
        print('***', file_directory)
    else:
        file_directory = None
    return file_directory

if __name__ == '__main__':
    app.run_server(debug=True, use_reloader=False)  

它应该在使用 Dash 库和 Tkinter 的浏览器中按照 UI 打开:

如果单击“浏览器”按钮,将在指定的初始目录打开一个打开文件对话框:

第一次没问题,下次就会报错:

任何人都可以帮助找出带有 tkinter.filedialog... 的行有什么问题吗?

我尝试过其他解决方案,例如this. 但是我用这个尝试了一切,但不知道如何设置初始目录。 InitialDir 不起作用。

使用 tkinkter,我可以设置初始目录,但出现错误(在工作一次后),如上面的屏幕截图所示。基本上我卡住了。

提前感谢您的指点。

callback

  • 创建 tkinter main window root = tkinter.Tk()
  • 隐藏它root.withdraw()

但是当你退出文件对话框时你永远不会销毁它。

当它再次运行时 callback 然后它会尝试创建第二个主 window 并且它与之前的(隐藏的)主 window.

发生冲突

如果我使用 root.destroy() 那么代码可以正常工作。

app.callback(
    Output(component_id='selected_directory', component_property='children'),
    Input(component_id='open_excel_button', component_property='n_clicks'),
    prevent_initial_call=True
)
def open_excel_function(open_excel): 
    print ('*** 1A. Callback open_file_dialog')
    ctx = dash.callback_context
    trigger = ctx.triggered[0]['prop_id'].split('.')[0]
    print("***", trigger, "is triggered.")

    root = tkinter.Tk()
    root.withdraw()
    # root.iconbitmap(default='Extras/transparent.ico')

    if trigger == 'open_excel_button':
        file_directory = tkinter.filedialog.askopenfilename(initialdir=FILE_DIR)
        print('***', file_directory)
    else:
        file_directory = None

    root.destroy()  # <--- SOLUTION
    
    return file_directory

甚至

def open_excel_function(open_excel): 
    print ('*** 1A. Callback open_file_dialog')
    ctx = dash.callback_context
    trigger = ctx.triggered[0]['prop_id'].split('.')[0]
    print("***", trigger, "is triggered.")

    if trigger == 'open_excel_button':
        root = tkinter.Tk()
        root.withdraw()
       # root.iconbitmap(default='Extras/transparent.ico')

        file_directory = tkinter.filedialog.askopenfilename(initialdir=FILE_DIR)
        print('***', file_directory)

        root.destroy()  # <--- SOLUTION
    else:
        file_directory = None
    
    return file_directory

编辑:

如果你只想获取目录名,那么也许你应该使用 tkinter.filedialog.askdirectory() 而不是 tkinter.filedialog.askopenfilename()