1# tree.rb -- 2# 3# This demonstration script creates a toplevel window containing a Ttk 4# tree widget. 5# 6# based on "Id: tree.tcl,v 1.4 2007/12/13 15:27:07 dgp Exp" 7 8if defined?($tree_demo) && $tree_demo 9 $tree_demo.destroy 10 $tree_demo = nil 11end 12 13$tree_demo = TkToplevel.new {|w| 14 title("Directory Browser") 15 iconname("tree") 16 positionWindow(w) 17} 18 19base_frame = TkFrame.new($tree_demo).pack(:fill=>:both, :expand=>true) 20 21## Explanatory text 22Ttk::Label.new(base_frame, :font=>$font, :wraplength=>'4i', 23 :justify=>:left, :anchor=>'n', :padding=>[10, 2, 10, 6], 24 :text=><<EOL).pack(:fill=>:x) 25Ttk is the new Tk themed widget set. \ 26One of the widgets it includes is a tree widget, \ 27which allows the user to browse a hierarchical data-set such as a filesystem. \ 28The tree widget not only allows for the tree part itself, \ 29but it also supports an arbitrary number of additional columns \ 30which can show additional data (in this case, the size of the files \ 31found in your filesystem). \ 32You can also change the width of the columns \ 33by dragging the boundary between them. 34EOL 35 36## See Code / Dismiss 37Ttk::Frame.new(base_frame) {|frame| 38 sep = Ttk::Separator.new(frame) 39 Tk.grid(sep, :columnspan=>4, :row=>0, :sticky=>'ew', :pady=>2) 40 TkGrid('x', 41 Ttk::Button.new(frame, :text=>'See Code', 42 :image=>$image['view'], :compound=>:left, 43 :command=>proc{showCode 'tree'}), 44 Ttk::Button.new(frame, :text=>'Dismiss', 45 :image=>$image['delete'], :compound=>:left, 46 :command=>proc{ 47 $tree_demo.destroy 48 $tree_demo = nil 49 }), 50 :padx=>4, :pady=>4) 51 grid_columnconfigure(0, :weight=>1) 52 pack(:side=>:bottom, :fill=>:x) 53} 54 55## Code to populate the roots of the tree (can be more than one on Windows) 56def populate_roots(tree) 57 TkComm.simplelist(Tk.tk_call('file', 'volumes')).sort.each{|dir| 58 populate_tree(tree, tree.insert(nil, :end, :text=>dir, 59 :values=>[dir, 'directory'])) 60 } 61end 62 63## Code to populate a node of the tree 64def populate_tree(tree, node) 65 return if tree.get(node, :type) != 'directory' 66 67 path = tree.get(node, :fullpath) 68 tree.delete(tree.children(node)) 69 Dir.glob("#{path}/*").sort.each{|f| 70 type = File.ftype(f) rescue nil 71 id = tree.insert(node, :end, 72 :text=>File.basename(f), :values=>[f, type]).id 73 if type == 'directory' 74 ## Make it so that this node is openable 75 tree.insert(id, 0, :text=>'dummy') 76 tree.itemconfigure(id, :text=>File.basename(f)) 77 elsif type == 'file' 78 size = File.size(f) 79 if size >= 1024*1024*1024 80 size = '%.1f GB' % (size.to_f/1024/1024/1024) 81 elsif size >= 1024*1024 82 size = '%.1f MB' % (size.to_f/1024/1024) 83 elsif size >= 1024 84 size = '%.1f KB' % (size.to_f/1024) 85 else 86 size = '%.1f bytes' % (size.to_f/1024) 87 end 88 tree.set(id, :size, size) 89 end 90 } 91 92 # Stop this code from rerunning on the current node 93 tree.set(node, :type, 'processed_directory') 94end 95 96## Create the tree and set it up 97tree = Ttk::Treeview.new(base_frame, :columns=>%w(fullpath type size), 98 :displaycolumns=>['size']) 99if Tk.windowingsystem != 'aqua' 100 vsb = tree.yscrollbar(Ttk::Scrollbar.new(base_frame)) 101 hsb = tree.xscrollbar(Ttk::Scrollbar.new(base_frame)) 102else 103 vsb = tree.yscrollbar(Tk::Scrollbar.new(base_frame)) 104 hsb = tree.xscrollbar(Tk::Scrollbar.new(base_frame)) 105end 106 107tree.heading_configure('#0', :text=>'Directory Structure') 108tree.heading_configure('size', :text=>'File Size') 109tree.column_configure('size', :stretch=>0, :width=>70) 110populate_roots(tree) 111tree.bind('<TreeviewOpen>', '%W'){|w| populate_tree(w, w.focus_item)} 112 113## Arrange the tree and its scrollbars in the toplevel 114container = Ttk::Frame.new(base_frame).pack(:fill=>:both, :expand=>true) 115container.lower 116Tk.grid(tree, vsb, :in=>container, :sticky=>'nsew') 117Tk.grid(hsb, :in=>container, :sticky=>'nsew') 118container.grid_columnconfigure(0, :weight=>1) 119container.grid_rowconfigure(0, :weight=>1) 120