我正在尝试使用python 和 Tkinter GUI创建一个双窗格文件浏览器,我将在单击按钮时添加“比较目录”、“比较文件”等功能。
(最终的 GUI 看起来有点像这个名为Meld https://en.wikipedia.org/wiki/Meld_(software)的工具)
作为第一步,我正在尝试创建一个Tree()类(其脚本是用 Tree_browser.py 编写的)。然后我将它导入import Tree_browser
到dircmp_utility.py中。(我还将编写另一个名为dircmp.py的目录/文件比较脚本)
现在我的问题是我对类和 oops 概念不熟悉,并且仍在努力学习和理解。因此,在互联网上花费了一些时间(YouTube、StackOverflow、geeks for geeks 等)之后,我尝试了下面的代码,我得到了下面显示的错误。
有人可以告诉我为什么会收到此错误以及我的代码中的错误是什么
即使定义了 self、autoscroll()、populate_roots(),它也会抛出一个错误,说明它们没有定义。为什么是这样??
树浏览器.py
import os
import glob
import tkinter as tk
from tkinter import ttk
class Tree():
def __init__(self,root):
self.frame = tk.Frame(root)
self.frame.pack()
def populate_tree(self, tree, node):
if tree.set(node, "type") != 'directory':
return
path = tree.set(node, "fullpath")
tree.delete(*tree.get_children(node))
parent = tree.parent(node)
special_dirs = [] if parent else glob.glob('.') + glob.glob('..')
for p in special_dirs + os.listdir(path):
ptype = None
p = os.path.join(path, p).replace('\\', '/')
if os.path.isdir(p): ptype = "directory"
elif os.path.isfile(p): ptype = "file"
fname = os.path.split(p)[1]
id = tree.insert(node, "end", text=fname, values=[p, ptype])
if ptype == 'directory':
if fname not in ('.', '..'):
tree.insert(id, 0, text="dummy")
tree.item(id, text=fname)
elif ptype == 'file':
size = os.stat(p).st_size
tree.set(id, "size", "%d bytes" % size)
def populate_roots(self, tree):
self.dir = os.path.abspath('.').replace('\\', '/')
self.node = tree.insert('', 'end', text=dir, values=[dir, "directory"])
populate_tree(tree, node)
def update_tree(self, event):
tree = event.widget
populate_tree(tree, tree.focus())
def change_dir(self,event):
tree = event.widget
node = tree.focus()
if tree.parent(node):
path = os.path.abspath(tree.set(node, "fullpath"))
if os.path.isdir(path):
os.chdir(path)
tree.delete(tree.get_children(''))
populate_roots(tree)
def autoscroll(self, sbar, first, last):
"""Hide and show scrollbar as needed."""
first, last = float(first), float(last)
if first <= 0 and last >= 1:
sbar.pack_forget()
else:
sbar.pack()
sbar.set(first, last)
vsb = ttk.Scrollbar(orient="vertical")
hsb = ttk.Scrollbar(orient="horizontal")
tree = ttk.Treeview(self.frame, columns=("fullpath", "type", "size"),
displaycolumns="size", yscrollcommand=lambda f, l: autoscroll(vsb, f, l),
xscrollcommand=lambda f, l:autoscroll(hsb, f, l))
tree.pack()
vsb['command'] = tree.yview
hsb['command'] = tree.xview
tree.heading("#0", text="Directory Structure", anchor='w')
tree.heading("size", text="File Size", anchor='w')
tree.column("size", stretch=0, width=100)
populate_roots(tree)
tree.bind('<<TreeviewOpen>>', update_tree)
tree.bind('<Double-Button-1>', change_dir)
# Arrange the tree and its scrollbars in the toplevel
tree.pack(expand=1, fill=BOTH)
vsb.pack(expand=1, fill=Y)
hsb.pack(expand=1, fill=X)
if __name__ == '__main__':
pass
dircmp_utility.py
import Tree_browser
import dircmp
import tkinter
master = tk()
left_frame = Frame(master)
right_frame = Frame(master)
left_frame.pack()
right_frame.pack()
left_tree = Tree(left_frame)
right_tree = Tree(right_frame)
master.mainloop()
运行 dircmp.py 后的错误
Traceback (most recent call last):
File "E:\Python_code_to_compare_two_folders\dircmp_using class\dircmp_utility.py", line 3, in <module>
import Tree_browser
File "E:\Python_code_to_compare_two_folders\dircmp_using class\Tree_browser.py", line 7, in <module>
class Tree():
File "E:\Python_code_to_compare_two_folders\dircmp_using class\Tree_browser.py", line 82, in Tree
populate_roots(tree)
TypeError: populate_roots() missing 1 required positional argument: 'tree'
>>> Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Program Files\Python38\lib\tkinter\__init__.py", line 1883, in __call__
return self.func(*args)
File "E:\Python_code_to_compare_two_folders\dircmp_using class\Tree_browser.py", line 73, in <lambda>
xscrollcommand=lambda f, l:autoscroll(hsb, f, l))
NameError: name 'autoscroll' is not defined
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Program Files\Python38\lib\tkinter\__init__.py", line 1883, in __call__
return self.func(*args)
File "E:\Python_code_to_compare_two_folders\dircmp_using class\Tree_browser.py", line 72, in <lambda>
displaycolumns="size", yscrollcommand=lambda f, l: autoscroll(vsb, f, l),
NameError: name 'autoscroll' is not defined
File "E:\Python_code_to_compare_two_folders\dircmp_using class\Tree_browser.py", line 71, in Tree
tree = ttk.Treeview(self.frame, columns=("fullpath", "type", "size"),
NameError: name 'self' is not defined
更新:发布工作脚本
保留我之前发布的错误代码,以便其他人可以从我的错误中吸取教训。感谢所有确实帮助我编写正确脚本的评论。
树浏览器.py
import os
import glob
import tkinter as tk
from tkinter import ttk
class Tree:
def __init__(self,root):
self.pane = tk.Frame(root, bg="red")
self.frame = tk.Frame(self.pane, bg="blue")
self.vsb = ttk.Scrollbar(self.frame, orient="vertical")
self.hsb = ttk.Scrollbar(self.pane, orient="horizontal")
self.tree = ttk.Treeview(self.frame, columns=("fullpath", "type", "size"),
displaycolumns="size", yscrollcommand=lambda f, l: self.yautoscroll(self.vsb, f, l),
xscrollcommand=lambda f, l: self.xautoscroll(self.hsb, f, l))
self.vsb['command'] = self.tree.yview
self.hsb['command'] = self.tree.xview
self.tree.heading("#0", text="Directory Structure", anchor='w')
self.tree.heading("size", text="File Size", anchor='w')
self.tree.column("size", stretch=0, width=100)
self.populate_roots(self.tree)
self.tree.bind('<<TreeviewOpen>>', self.update_tree)
self.tree.bind('<Double-Button-1>', self.change_dir)
# Arrange the tree and its scrollbars in the toplevel
self.pane.pack(side=tk.BOTTOM, expand=1, fill=tk.BOTH)
self.frame.pack(side=tk.TOP, expand=1, fill=tk.BOTH)
self.tree.pack(side=tk.LEFT, expand=1, fill=tk.BOTH)
self.vsb.pack(expand=1, fill=tk.Y)
self.hsb.pack(expand=1, fill=tk.X)
def populate_tree(self, tree, node):
if self.tree.set(self.node, "type") != 'directory':
return
self.path = self.tree.set(self.node, "fullpath")
self.tree.delete(*self.tree.get_children(self.node))
self.parent = self.tree.parent(self.node)
self.special_dirs = [] if self.parent else glob.glob('.') + glob.glob('..')
for p in self.special_dirs + os.listdir(self.path):
ptype = None
p = os.path.join(self.path, p).replace('\\', '/')
if os.path.isdir(p): ptype = "directory"
elif os.path.isfile(p): ptype = "file"
self.fname = os.path.split(p)[1]
id = tree.insert(self.node, "end", text=self.fname, values=[p, ptype])
if ptype == 'directory':
if self.fname not in ('.', '..'):
self.tree.insert(id, 0, text="dummy", open=True)
self.tree.item(id, text=self.fname)
elif ptype == 'file':
size = os.stat(p).st_size
self.tree.set(id, "size", "%d bytes" % size)
def populate_roots(self, tree):
self.dir = os.path.abspath('.').replace('\\', '/')
self.node = tree.insert('', 'end', text=self.dir, values=[self.dir, "directory"], open=True)
self.populate_tree(self.tree, self.node)
def update_tree(self, event):
self.tree = event.widget
self.node = self.tree.focus()
self.populate_tree(self.tree, self.node)
def change_dir(self,event):
self.tree = event.widget
self.node = self.tree.focus()
if self.tree.parent(self.node):
self.path = os.path.abspath(self.tree.set(self.node, "fullpath"))
if os.path.isdir(self.path):
os.chdir(self.path)
self.tree.delete(self.tree.get_children(''))
self.populate_roots(self.tree)
def yautoscroll(self, sbar, first, last):
"""Hide and show scrollbar as needed."""
self.first, self.last = float(first), float(last)
if self.first <= 0 and self.last >= 1:
sbar.pack_forget()
else:
sbar.pack(side=tk.LEFT, fill=tk.BOTH, expand=0)
sbar.set(self.first, self.last)
def xautoscroll(self, sbar, first, last):
"""Hide and show scrollbar as needed."""
self.first, self.last = float(first), float(last)
if self.first <= 0 and self.last >= 1:
sbar.pack_forget()
else:
sbar.pack(side=tk.LEFT, fill=tk.BOTH, expand=1)
sbar.set(self.first, self.last)
if __name__ == '__main__':
pass
dircmp_utility.py
import tkinter as tk
master = tk.Tk()
left_frame = tk.Frame(master)
right_frame = tk.Frame(master)
left_frame.pack(side=tk.LEFT, expand=1, fill=tk.BOTH)
right_frame.pack(side=tk.LEFT, expand=1, fill=tk.BOTH)
left_tree = Tree(left_frame)
right_tree = Tree(right_frame)
master.mainloop()