当函数用作命令函数时,如何 return 来自函数的值?如何在按下按钮时关闭用户界面?

How to return a value from a function when it is used as a command function? How to close a user interface when a button is pressed?

我是 python 的新手。我用 tkinter 为文件 selection 开发了一个简单的 GUI。当按下一个按钮时,一个打开的文件对话框被激活,用户可以 select 一个文件夹中的文件。这是我的代码:

import tkinter as tk
from tkinter import ttk
from tkinter import filedialog as fd


# %% create a command associated to the window button
def open_file():
    initialDir = '/';
    fileTypes = (('Text files', '*.txt'), ('Csv files', '*.csv'), ('All files', '*.*'));
    Title = 'Choose a file';
    filename = str(fd.askopenfile(title=Title, filetypes=fileTypes));
        
    
# %% create a GUI
window = tk.Tk();
window.title('Tkinter GUI Open File Dialog');
window.resizable(False, False);
window.geometry('300x150');


# %% open file button
open_button = ttk.Button(window, text='Open a File',command=open_file);
open_button.grid(column=0, row=1, sticky='w', padx=10, pady=10)


# %% run window - automatic closing after 10 seconds
window.after(10000,lambda:window.destroy())
window.mainloop();

我想获取 selected 文件的文件名。 此外,我想在按下按钮并且文件名已知时关闭 gui。 谢谢大家!

此时你将其赋值给局部变量filename,但如果你在函数内部添加global filename,那么它将赋值给全局变量。

最好在开始时为全局变量分配一些默认值 - 这样即使您不 select 文件它也会存在。

如果您只需要文件名(而不是对打开文件的引用),则使用 askopenfilename 而不是 askopenfile

如果您单击 Cancel,那么 askopenfilename 应该会给出 None,最好将其保留为 None 而不是转换为字符串。稍后你应该检查 filename 是否是 None 到 运行 代码只有当你真的 selected filename.

import tkinter as tk
from tkinter import ttk
from tkinter import filedialog as fd

filename = None # default value in global variable

# %% create a command associated to the window button
def open_file():
    global filename  # inform function to use global variable instead of local one
    
    initialDir = '/'
    fileTypes = (('Text files', '*.txt'), ('Csv files', '*.csv'), ('All files', '*.*'))
    Title = 'Choose a file'
    
    # use askopenfilename instead of askopenfile to get only name
    
    filename = fd.askopenfilename(title=Title, filetypes=fileTypes)
        
    # destroy GUI
    window.destroy()
    
# %% create a GUI
window = tk.Tk()
window.title('Tkinter GUI Open File Dialog')
window.resizable(False, False)
window.geometry('300x150')

# %% open file button
open_button = ttk.Button(window, text='Open a File',command=open_file)
open_button.grid(column=0, row=1, sticky='w', padx=10, pady=10)

# %% run window - automatic closing after 10 seconds
window.after(10000, window.destroy)
window.mainloop()

if filename:  # check if filename was really selected
    print('selected:', filename)
else:
    print("you didn't select filename")

如果你想保持所有功能,那么它可能需要在所有功能中使用global

import tkinter as tk
from tkinter import ttk
from tkinter import filedialog as fd

def get_filename():
    global filename
    
    filename = None # default value in global variable
    
    # %% create a command associated to the window button
    def open_file():
        global filename  # inform function to use global variable instead of local one
        
        initialDir = '/'
        fileTypes = (('Text files', '*.txt'), ('Csv files', '*.csv'), ('All files', '*.*'))
        Title = 'Choose a file'
        
        # use askopenfilename instead of askopenfile to get only name
        
        filename = fd.askopenfilename(title=Title, filetypes=fileTypes)
            
        window.destroy()
        
    # %% create a GUI
    window = tk.Tk()
    window.title('Tkinter GUI Open File Dialog')
    window.resizable(False, False)
    window.geometry('300x150')
    
    # %% open file button
    open_button = ttk.Button(window, text='Open a File',command=open_file)
    open_button.grid(column=0, row=1, sticky='w', padx=10, pady=10)
    
    # %% run window - automatic closing after 10 seconds
    window.after(10000, window.destroy)
    window.mainloop()
    
    return filename

# --- main ---

filename = get_filename()

if filename:  # check if filename was really selected
    print('selected:', filename)
else:
    print("you didn't select filename")

流行的方法也是创建mainwindow,隐藏它直接运行 askopenfilename没有按钮

import tkinter as tk
from tkinter import ttk
from tkinter import filedialog as fd

def get_filename():
    global filename
    
    filename = None # default value in global variable
    
    # %% create a command associated to the window button
    def open_file():
        global filename  # inform function to use global variable instead of local one
        
        initialDir = '/'
        fileTypes = (('Text files', '*.txt'), ('Csv files', '*.csv'), ('All files', '*.*'))
        Title = 'Choose a file'
        
        # use askopenfilename instead of askopenfile to get only name
        
        filename = fd.askopenfilename(title=Title, filetypes=fileTypes)
            
        window.destroy()
        
    # %% create a GUI
    window = tk.Tk()
    
    #window.iconify()  # minimize to icon
    window.withdraw()  # hide it 
    
    window.after(10000, window.destroy)
    
    open_file()
    
    window.mainloop()
    
    return filename

# --- main ---

filename = get_filename()

if filename:  # check if filename was really selected
    print('selected:', filename)
else:
    print("you didn't select filename")

编辑:

精简版可以运行带参数

import tkinter as tk
from tkinter import filedialog 

def get_filename(title='Choose a file', directory='/', file_types = (('Text files', '*.txt'), ('Csv files', '*.csv'), ('All files', '*.*'))):

    window = tk.Tk()
    
    #window.iconify()  # minimize to icon
    window.withdraw()  # hide it 
    
    filename = filedialog.askopenfilename(title=title, initialdir=directory, filetypes=file_types)
        
    window.destroy()
    
    return filename

# --- main ---

filename = get_filename(directory='/')

if filename:  # check if filename was really selected
    print('selected:', filename)
else:
    print("you didn't select filename")

编辑 Furas 提出的解决方案,以下代码可能代表 UiGetFile Matlab 函数的 Python 版本。唯一的缺点是文件对话框的奇怪行为有时出现在前台有时出现在后台(使用 Spyder 5)。

import tkinter as tk
from tkinter import filedialog

def UiGetFile(fileDialogTitle='Select the file to open', initialDirectory='/', fileTypes = (('Text files', '*.txt'), ('Csv files', '*.csv'), ('All files', '*.*'))):
    filePath = []
    fileName = []    
    window = tk.Tk()    
    #window.iconify()  # minimize to icon
    window.withdraw()  # hide it 
    
    fullname = filedialog.askopenfilename(title=fileDialogTitle, initialdir=initialDirectory, filetypes=fileTypes)        
    window.destroy()
    if fullname:
        allIndices = [i for i, val in enumerate(fullname) if val == '/']
        filePath = fullname[0 : 1+max(allIndices)]
        fileName = fullname[1+max(allIndices) : ]
                   
    return filePath, fileName


# --- main ---
fullname = UiGetFile()
print('File path: ', fullname[0])
print('File name: ', fullname[1])