tkFileDialog在Windows上未将结果转换为Python列表
我在用下面的代码(Python 2.7 和 Python 3.2)来显示一个可以选择多个文件的对话框。在Linux系统上,文件名会以Python列表的形式返回,但在Windows系统上,文件名则是以{C:/Documents and Settings/IE User/My Documents/VPC_EULA.txt} {C:/Documents and Settings/IE User/My Documents/VPC_ReadMe.txt}
的形式返回,也就是一个原始的TCL列表。
这算不算是Python的一个bug呢?有没有人知道怎么把这个原始的TCL列表转换成Python列表的好方法?
if sys.hexversion >= 0x030000F0:
import tkinter.filedialog as filedialog
else:
import tkFileDialog as filedialog
options = {}
options['filetypes'] = [('vnote files', '.vnt') ,('all files', '.*')]
options['multiple'] = 1
filenames = filedialog.askopenfilename(**options)
4 个回答
这个解决办法对我有效:
if sys.hexversion >= 0x030000F0:
import tkinter.filedialog as filedialog
string_type = str
else:
import tkFileDialog as filedialog
string_type = basestring
options = {}
options['filetypes'] = [('vnote files', '.vnt') ,('all files', '.*')]
options['multiple'] = 1
filenames = filedialog.askopenfilename(**options)
if isinstance(filenames, string_type):
# tkinter is not converting the TCL list into a python list...
# see http://stackoverflow.com/questions/9227859/
#
# based on suggestion by Cameron Laird in http://bytes.com/topic/python/answers/536853-tcl-list-python-list
if sys.hexversion >= 0x030000F0:
import tkinter
else:
import Tkinter as tkinter
tk_eval = tkinter.Tk().tk.eval
tcl_list_length = int(tk_eval("set tcl_list {%s}; llength $tcl_list" % filenames))
filenames = [] # change to a list
for i in range(tcl_list_length):
filenames.append(tk_eval("lindex $tcl_list %d" % i))
return filenames
不知道为什么,基于tk_eval的解决办法对我来说不管用。通过tkFileDialog返回的文件名字符串,只有在文件名中有空格的时候,才会用{}括起来,而tcl的文档似乎说所有的列表项都应该用这些括号来分隔。
不管怎样,这里有一个对我有效的解决办法(在Windows 7上使用Python 2.7.3):
def fixlist(filenames):
#do nothing if already a python list
if isinstance(filenames,list): return filenames
#http://docs.python.org/library/re.html
#the re should match: {text and white space in brackets} AND anynonwhitespacetokens
#*? is a non-greedy match for any character sequence
#\S is non white space
#split filenames string up into a proper python list
result = re.findall("{.*?}|\S+",filenames)
#remove any {} characters from the start and end of the file names
result = [ re.sub("^{|}$","",i) for i in result ]
return result
这个问题是Tcl、Tk和Python之间一个“有趣”的互动。它们各自的工作都很合理,但组合在一起时却出现了问题。根本原因在于Tcl和Python对数据类型的理解差别很大,这导致Tcl把某个值看作列表,而Python却把它当成字符串(而Tk中的代码假设不需要特别注意Python的处理)。可以说,Python的接口应该利用它知道Tcl会返回一个列表这一点来隐藏这个问题,但实际上并没有做到,所以你就陷入了困境。
我可以(而且应该!)在Tk中修复这个问题,但我不知道这个修复要多久才能传递到你那里。
[编辑]:这个问题现在已经修复了(通过这个补丁),在Tk 8.5的维护版本和主开发版本中都有。除非你从我们的fossil仓库中获取源代码并自己编译,否则我无法预测你何时能得到修复后的版本。