Python3 using tkinter as the interface file tree filetreewidget

Source: Internet
Author: User
Tags drawtext glob

# XXX to do:
#-Popup menu
#-Support partial or total redisplay
#-Key bindings (instead of quick-n-dirty bindings on canvas ):
#-Up/down arrow keys to move focus around
#-Ditto for page up/down, home/end
#-Left/right arrows to expand/Collapse & move out/in
#-More Doc strings
#-Add icons for "file", "module", "class", "method"; better "Python" icon
#-Callback for selection ???
#-Multiple-item selection
#-Tooltips
#-Redo geometry without magic numbers
#-Keep track of object IDs to allow more careful cleaning
#-Optimize tree redraw after expand of subnode

Import OS
From tkinter import *
Import imp

From idlelib import zoomheight
From idlelib. confighandler import idleconf

Icondir = "icons"

# Look for icons subdirectory in the same directory as this module
Try:
_ Icondir = OS. Path. Join (OS. Path. dirname (_ file _), icondir)
Failed t nameerror:
_ Icondir = icondir
If OS. Path. isdir (_ icondir ):
Icondir = _ icondir
Elif not OS. Path. isdir (icondir ):
Raise runtimeerror ("can't find icon directory (% R)" % (icondir ,))

Def listicons (icondir = icondir ):
"Utility to display the available icons ."""
Root = TK ()
Import glob
List = glob. glob (OS. Path. Join (icondir, "*. GIF "))
List. Sort ()
Images = []
Row = column = 0
For file in list:
Name = OS. Path. splitext (OS. Path. basename (File) [0]
Image = photoimage (file = file, Master = root)
Images. append (image)
Label = label (root, image = image, BD = 1, relief = "Raised ")
Label. Grid (ROW = row, column = column)
Label = label (root, text = Name)
Label. Grid (ROW = row + 1, column = column)
Column = column + 1
If column> = 10:
Row = row + 2
Column = 0
Root. Images = Images

Class treenode:

Def _ init _ (self, canvas, parent, item ):
Self. Canvas = canvas
Self. Parent = parent
Self. Item = item
Self. State = 'collapsed'
Self. Selected = false
Self. Children = []
Self. x = self. Y = none
Self. iconimages ={}# cache of photoimage instances for icons

Def destroy (Self ):
For C in self. Children [:]:
Self. Children. Remove (c)
C. Destroy ()
Self. Parent = none

Def geticonimage (self, name ):
Try:
Return self. iconimages [name]
Failed t keyerror:
Pass
File, ext = OS. Path. splitext (name)
EXT = ext or ". GIF"
Fullname = OS. Path. Join (icondir, file + ext)
Image = photoimage (Master = self. Canvas, file = fullname)
Self. iconimages [name] = image
Return Image

Def select (self, event = none ):
If self. Selected:
Return
Self. deselectall ()
Self. Selected = true
Self. Canvas. Delete (self. image_id)
Self. drawicon ()
Self. drawtext ()

Def deselect (self, event = none ):
If not self. Selected:
Return
Self. Selected = false
Self. Canvas. Delete (self. image_id)
Self. drawicon ()
Self. drawtext ()

Def deselectall (Self ):
If self. Parent:
Self. Parent. deselectall ()
Else:
Self. deselecttree ()

Def deselecttree (Self ):
If self. Selected:
Self. deselect ()
For child in self. Children:
Child. deselecttree ()

Def flip (self, event = none ):
If self. State = 'expanded ':
Self. Collapse ()
Else:
Self. Expand ()
Self. item. ondoubleclick ()
Return "break"

Def expand (self, event = none ):
If not self. item. _ isexpandable ():
Return
If self. State! = 'Expanded ':
Self. State = 'expanded'
Self. Update ()
Self. View ()

Def collapse (self, event = none ):
If self. State! = 'Collapsed ':
Self. State = 'collapsed'
Self. Update ()

Def view (Self ):
Top = self. Y-2
Bottom = self. lastvisiblechild (). Y + 17
Height = bottom-top
Visible_top = self. Canvas. canvasy (0)
Visible_height = self. Canvas. winfo_height ()
Visible_bottom = self. Canvas. canvasy (visible_height)
If visible_top <= top and bottom <= visible_bottom:
Return
X0, y0, X1, Y1 = self. Canvas. _ getints (self. Canvas ['scrollregion'])
If top> = visible_top and height <= visible_height:
Fraction = Top + height-visible_height
Else:
Fraction = Top
Fraction = float (fraction)/Y1
Self. Canvas. yview_moveto (fraction)

Def lastvisiblechild (Self ):
If self. Children and self. State = 'expanded ':
Return self. Children [-1]. lastvisiblechild ()
Else:
Return self

Def Update (Self ):
If self. Parent:
Self. Parent. Update ()
Else:
Oldcursor = self. Canvas ['cursor ']
Self. Canvas ['cursor '] = "watch"
Self. Canvas. Update ()
Self. Canvas. Delete (All) # XXX cocould be more subtle
Self. Draw (7, 2)
X0, y0, X1, Y1 = self. Canvas. bBox (all)
Self. Canvas. Configure (scrollregion = (0, 0, X1, Y1 ))
Self. Canvas ['cursor '] = oldcursor

Def draw (self, x, y ):
# XXX This hard-codes too plugin geometry constants!
Self. X, self. Y = x, y
Self. drawicon ()
Self. drawtext ()
If self. State! = 'Expanded ':
Return y + 17
# Draw children
If not self. Children:
Sublist = self. item. _ getsublist ()
If not sublist:
# _ Isexpandable () was mistaken; that's allowed
Return y + 17
For item in sublist:
Child = self. _ class _ (self. Canvas, self, item)
Self. Children. append (child)
Cx = x + 20
Cy = Y + 17
Cylast = 0
For child in self. Children:
Cylast = cy
Self. Canvas. create_line (x + 9, Cy + 7, CX, Cy + 7, fill = "gray50 ")
Cy = Child. Draw (CX, CY)
If child. item. _ isexpandable ():
If child. State = 'expanded ':
Iconname = "minusnode"
Callback = Child. Collapse
Else:
Iconname = "plusnode"
Callback = Child. Expand
Image = self. geticonimage (iconname)
Id = self. Canvas. create_image (x + 9, cylast + 7, image = image)
# XXX This leaks bindings until canvas is deleted:
Self. Canvas. tag_bind (ID, "<1>", callback)
Self. Canvas. tag_bind (ID, "<double-1>", Lambda X: None)
Id = self. Canvas. create_line (x + 9, Y + 10, x + 9, cylast + 7,
# Stipple = "gray50", # XXX seems broken in TK 8.0.x
Fill = "gray50 ")
Self. Canvas. tag_lower (ID) # XXX. Lower (ID) before Python 1.5.2
Return cy

Def drawicon (Self ):
If self. Selected:
Imagename = (self. item. getselectediconname () or
Self. item. geticonname () or
"Openfolder ")
Else:
Imagename = self. item. geticonname () or "folder"
Image = self. geticonimage (imagename)
Id = self. Canvas. create_image (self. X, self. Y, anchor = "nw", image = image)
Self. image_id = ID
Self. Canvas. tag_bind (ID, "<1>", self. Select)
Self. Canvas. tag_bind (ID, "<double-1>", self. Flip)

Def drawtext (Self ):
Textx = self. x + 20-1
Texty = self. Y-1
Labeltext = self. item. getlabeltext ()
If labeltext:
Id = self. Canvas. create_text (textx, texty, anchor = "nw ",
TEXT = labeltext)
Self. Canvas. tag_bind (ID, "<1>", self. Select)
Self. Canvas. tag_bind (ID, "<double-1>", self. Flip)
X0, y0, X1, Y1 = self. Canvas. bBox (ID)
Textx = max (x1, 200) + 10
TEXT = self. item. gettext () or "<no text>"
Try:
Self. Entry
T attributeerror:
Pass
Else:
Self. edit_finish ()
Try:
Label = self. Label
T attributeerror:
# Padding carefully selected (on Windows) to match entry Widget:
Self. Label = label (self. Canvas, text = text, BD = 0, padx = 2, pady = 2)
Theme = idleconf. getoption ('main', 'Theme ', 'name ')
If self. Selected:
Self. Label. Configure (idleconf. gethighlight (theme, 'hilite '))
Else:
Self. Label. Configure (idleconf. gethighlight (theme, 'normal '))
Id = self. Canvas. create_window (textx, texty,
Anchor = "nw", window = self. Label)
Self. Label. BIND ("<1>", self. select_or_edit)
Self. Label. BIND ("<double-1>", self. Flip)
Self. text_id = ID

Def select_or_edit (self, event = none ):
If self. Selected and self. item. iseditable ():
Self. Edit (Event)
Else:
Self. Select (Event)

Def edit (self, event = none ):
Self. Entry = entry (self. Label, BD = 0, highlightthickness = 1, width = 0)
Self. Entry. insert (0, self. Label ['text'])
Self. Entry. selection_range (0, end)
Self. Entry. Pack (ipadx = 5)
Self. Entry. focus_set ()
Self. Entry. BIND ("<return>", self. edit_finish)
Self. Entry. BIND ("<escape>", self. edit_cancel)

Def edit_finish (self, event = none ):
Try:
Entry = self. Entry
Del self. Entry
T attributeerror:
Return
TEXT = entry. Get ()
Entry. Destroy ()
If text and text! = Self. item. gettext ():
Self. item. settext (text)
TEXT = self. item. gettext ()
Self. Label ['text'] = text
Self. drawtext ()
Self. Canvas. focus_set ()

Def edit_cancel (self, event = none ):
Try:
Entry = self. Entry
Del self. Entry
T attributeerror:
Return
Entry. Destroy ()
Self. drawtext ()
Self. Canvas. focus_set ()

Class treeitem:

"Abstract class representing tree items.

Methods shocould typically be overridden, otherwise a default action
Is used.

"""

Def _ init _ (Self ):
"Constructor. Do whatever you need to do ."""

Def gettext (Self ):
"" Return text string to display ."""

Def getlabeltext (Self ):
"Return label text string to display in front of text (if any )."""

Expandable = none

Def _ isexpandable (Self ):
"Do not override! Called by treenode ."""
If self. expandable is none:
Self. expandable = self. isexpandable ()
Return self. Expandable

Def isexpandable (Self ):
"" Return whether there are subitems ."""
Return 1

Def _ getsublist (Self ):
"Do not override! Called by treenode ."""
If not self. isexpandable ():
Return []
Sublist = self. getsublist ()
If not sublist:
Self. expandable = 0
Return sublist

Def iseditable (Self ):
"Return whether the item's text may be edited ."""

Def settext (self, text ):
"Change the item's text (if it is editable )."""

Def geticonname (Self ):
"Return name of icon to be displayed normally ."""

Def getselectediconname (Self ):
"Return name of icon to be displayed when selected ."""

Def getsublist (Self ):
"" Return list of items forming sublist ."""

Def ondoubleclick (Self ):
"Called on a double-click on the item ."""

# Example application

Class filetreeitem (treeitem ):

"Example treeitem subclass -- browse the file system ."""

Def _ init _ (self, PATH ):
Self. Path = path

Def gettext (Self ):
Return OS. Path. basename (self. Path) or self. Path

Def iseditable (Self ):
Return OS. Path. basename (self. Path )! = ""

Def settext (self, text ):
Newpath = OS. Path. dirname (self. Path)
Newpath = OS. Path. Join (newpath, text)
If OS. Path. dirname (newpath )! = OS. Path. dirname (self. Path ):
Return
Try:
OS. Rename (self. Path, newpath)
Self. Path = newpath
Failed t OS. Error:
Pass

Def geticonname (Self ):
If not self. isexpandable ():
Return "Python" # XXX wish there was a "file" icon

Def isexpandable (Self ):
Return OS. Path. isdir (self. Path)

Def getsublist (Self ):
Try:
Names = OS. listdir (self. Path)
Failed t OS. Error:
Return []
Names. Sort (Key = OS. Path. normcase)
Sublist = []
For name in names:
Item = filetreeitem (OS. Path. Join (self. Path, name ))
Sublist. append (item)
Return sublist

# A canvas widget with scroll bars and some useful bindings

Class scrolledcanvas:
Def _ init _ (self, Master, ** opts ):
If 'yscrollincrement 'not in opts:
Opts ['maid] = 17
Self. Master = Master
Self. Frame = frame (master)
Self. Frame. rowconfigure (0, Weight = 1)
Self. Frame. columnconfigure (0, Weight = 1)
Self. Canvas = canvas (self. Frame, ** opts)
Self. Canvas. Grid (ROW = 0, column = 0, sticky = "nsew ")
Self. vbar = scrollbar (self. Frame, name = "vbar ")
Self. vbar. Grid (ROW = 0, column = 1, sticky = "neuron ")
Self. hbar = scrollbar (self. Frame, name = "hbar", orient = "horizontal ")
Self. hbar. Grid (ROW = 1, column = 0, sticky = "EWS ")
Self. Canvas ['yscrollcommand'] = self. vbar. Set
Self. vbar ['command'] = self. Canvas. yview
Self. Canvas ['xscrollcommand'] = self. hbar. Set
Self. hbar ['command'] = self. Canvas. xview
Self. Canvas. BIND ("<key-Prior>", self. page_up)
Self. Canvas. BIND ("<key-Next>", self. page_down)
Self. Canvas. BIND ("<key-up>", self. unit_up)
Self. Canvas. BIND ("<key-down>", self. unit_down)
# If isinstance (master, toplevel) or isinstance (master, TK ):
Self. Canvas. BIND ("<alt-key-2>", self. zoom_height)
Self. Canvas. focus_set ()
Def page_up (self, event ):
Self. Canvas. yview_scroll (-1, "page ")
Return "break"
Def page_down (self, event ):
Self. Canvas. yview_scroll (1, "page ")
Return "break"
Def unit_up (self, event ):
Self. Canvas. yview_scroll (-1, "unit ")
Return "break"
Def unit_down (self, event ):
Self. Canvas. yview_scroll (1, "unit ")
Return "break"
Def zoom_height (self, event ):
Zoomheight. zoom_height (self. Master)
Return "break"

# Testing functions

Def test ():
From idlelib import pyshell
Root = toplevel (pyshell. Root)
Root. Configure (BD = 0, BG = "yellow ")
Root. focus_set ()
SC = scrolledcanvas (root, BG = "white", highlightthickness = 0, takefocus = 1)
SC. Frame. Pack (expand = 1, fill = "both ")
Item = filetreeitem ("C:/Windows/desktop ")
Node = treenode (SC. Canvas, none, item)
Node. Expand ()

Def Test2 ():
# Test w/o scrolling canvas
Root = TK ()
Root. Configure (BD = 0)
Canvas = canvas (root, BG = "white", highlightthickness = 0)
Canvas. Pack (expand = 1, fill = "both ")
Item = filetreeitem (OS. curdir)
Node = treenode (canvas, none, item)
Node. Update ()
Canvas. focus_set ()

# If _ name _ = '_ main __':
# Test ()

Import tkinter as TK
From idlelib import treewidget

If _ name _ = '_ main __':
Root = Tk. TK ()
Root. Configure (BD = 0)
Canvas = Tk. Canvas (root, BG = "white", highlightthickness = 0)
Canvas. Pack (expand = 1, fill = "both ")
Item = treewidget. filetreeitem ("/")
# Item = ['1', '2', '3']
Node = treewidget. treenode (canvas, none, item)
Node. Update ()
Canvas. focus_set ()
Root. mainloop ()

The following files must be included:

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.