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()
我已经为下面的代码苦苦挣扎了一整天了。
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()