[Python-de] FileLight in Python + Tk

Mathias Uebel mathias.uebel at meeloon.de
Fr Jun 27 12:19:56 UTC 2008


Hallo Leute,

ich habe mal wieder etwas zum _Auseinandernehmen_!
Ich bin Autodidakt und habe also Niemanden, dem ich das Vorlegen kann.
Darum bitte ich hier um Kritik, Anregungen ... Ich will etwas lernen.

Offen ist:
- Wenn das Fenster verschoben wird, erscheinen die ToolTip-Fenster an 
der früheren Position. Wie bekomme ich das in Griff?
- Es fehlt eine Progressbar, bzw. es würde reichen, wenn sich der Cursor 
in 'watch' ändert. Da fehlt mir auch der Ansatz.

Bis denne

P.S: Ich erlaube, dass man sich über mein englisch lustig macht.

#! /usr/bin/env python
# -*- coding: utf-8 -*-

# filelight in Python and tk ;-)

try:
	import sys, os
	from math import *
	from Tkinter import *
	import Canvas
except:
	print """Folgenden Module sind unbedingt erforderlich: ... """
	sys.exit(1)

# sort a list[list] as a model
# aus dem forum http://www.unixboard.de/vb3/showthread.php?t=16795
lcmp = lambda idx: lambda b, a: (a[idx] < b[idx]) and -1 or (a[idx] >
b[idx]) and 1 or 0

def HumanValue(value):
	"""human-readable Values"""
	if value > 1024 * 1024 * 1024:
		return "%d GB" % (value / 1024 / 1024 / 1024)
	if value > 1024 * 1024:
		return "%d MB" % (value / 1024 / 1024)
	if value > 1024:
		return "%d KB" % (value / 1024)
	return "%d B" % value

class PathWalk(object):
	"""walk the path recursiv and add the filesize"""
	def __init__(self, POINT=os.environ['HOME']): #getcwd()):
		self.POINT = POINT
		self.oldPOINT = ""
		self.Action()

	def Action(self):
		"""walk the File tree"""
		# only if is a new access
		if self.POINT != self.oldPOINT:
			self.Progress = 0
			self.SUMME = 0
			self.FILELIST_files = []
			self.FILELIST_dirs = []
			for item in os.listdir(self.POINT):
				#print item
				# all files in root-dir
				LIST = []
				if os.path.isfile(os.path.join(self.POINT, item)):
					#print int(os.path.getsize(os.path.join(POINT, item)))
					value = int(os.path.getsize(os.path.join(self.POINT, item)))
					LIST.append(value)
					self.SUMME += value
					LIST.append(item)
					LIST.append('File')
					self.FILELIST_files.append(LIST)
					self.Progress += 1
				# walk the path and add the size
				LIST = []
				if os.path.isdir(os.path.join(self.POINT, item)):
					value = 0
					for root, dirs, files in os.walk(os.path.join(self.POINT, item),
True, None):
						#print sum([os.path.getsize(os.path.join(root, name)) for name in
files]), root
						for name in files:
							if os.path.isfile(os.path.join(root, name)):
								value += int(os.path.getsize(os.path.join(root, name)))
							self.Progress += 1
					LIST.append(value)
					self.SUMME += value
					LIST.append(item)
					LIST.append('Dir')
					self.FILELIST_dirs.append(LIST)
					self.Progress += 1
		self.oldPOINT = self.POINT
		return 0

	def FileListFiles(self):
		self.FILELIST_files.sort(cmp=lcmp(0))
		return self.FILELIST_files

	def FileListDirs(self):
		self.FILELIST_dirs.sort(cmp=lcmp(0))
		return self.FILELIST_dirs
		
	def FileList(self):
		self.FILELIST = self.FILELIST_dirs + self.FILELIST_files
		self.FILELIST.sort(cmp=lcmp(0))
		return self.FILELIST

	def FileSumme(self):
		return self.SUMME


class MainWin(Frame, PathWalk):
	"""window, main"""
	def __init__(self, POINT, parent=None):		
		PathWalk.__init__(self, POINT)

		# window width, height and circle radius
		self.win_width = 380
		self.win_height = 380
		self.canvas_width = 380
		self.canvas_height = 380
		self.circle_rad = 160
		
		Frame.__init__(self)
		self['width'] = self.win_width
		self['height'] = self.win_height
		#self['bg'] = "white"
		self.master.title(":~$ du -Python")
		self.pack()
		self.myMenu()
		self.myEntry()
		self.myButtons()
		self.myCanvas()
		self.Paint()

	def myMenu(self):
		"""Menu on Top"""
		myBar = Menu(self.master)
		myFileM = Menu(myBar)
		myFileM.add_command(label="Open")
		myFileM.add_command(label="Close", command=self.myClose)
		myHelpM = Menu(myBar)
		myHelpM.add_command(label="Help", command=self.myHelp)
		myHelpM.add_command(label="Over Us", command=self.myAbout)
		myBar.add_cascade(label="File", menu=myFileM)
		myBar.add_cascade(label="Help", menu=myHelpM)
		self.master.config(menu=myBar)

	def myEntry(self):
		""" """
		self.EntryPoint = Entry(self, width=44, bg='white')
		self.EntryPoint.bind("<Return>", lambda e:
self.GoToNode(self.EntryPoint.get()))
		self.EntryPoint.grid(row=0, column=0)
		
	def myButtons(self):
		"""Buttons """
		myButton = Button(self, text='/ ', command=lambda: self.GoToNode('/'))
		myButton.grid(row=0, column=1)

		myButton = Button(self, text='home', command=lambda:
self.GoToNode(os.environ['HOME']))
		myButton.grid(row=0, column=2)

		myButton = Button(self, text='Up', command=self.WalkUp)
		myButton.grid(row=0, column=3)

	def GoToNode(self, *args):
		"""go the tree up """
		self.POINT = args[0]
		try:
			self.Action()
			self.Paint()
		except:
			pass

	def WalkUp(self, *args):
		"""go the tree up """
		#
		if self.POINT == os.sep: return 0;
		# remove the first slash
		point = self.POINT[1:].split(os.sep)
		# remove the first empty entry
		if len(point) >= 1:
			# remove the last entry in path
			point.remove(point[-1])
		# build a new path
		new = ""
		for item in point:
			#if item is empty: continue
			new += "%s%s" % (os.sep, item)
		if new =="":
			new = os.sep
		# new start
		self.POINT = new
		self.Action()
		self.Paint()

	def MouseOverCallback(self, event):
		# Translates a window x,y coordinates to a canvas coordinate
		x, y = self.canvas.canvasx(event.x), self.canvas.canvasy(event.y)
		# Returns tuple containing the object id
		id = self.canvas.find_closest(x,y)[0]
		#print id
		for item in self.NewFileList:
			if id == item[-1]:
				self.ToolTipWin(x, y, item)
				
	def MouseKlickCallback(self, event):
		# Translates a window x,y coordinates to a canvas coordinate
		x, y = self.canvas.canvasx(event.x), self.canvas.canvasy(event.y)
		# Returns tuple containing the object id
		id = self.canvas.find_closest(x,y)[0]
		#print id
		for item in self.NewFileList:
			if id == item[-1]:
				# build a new path
				self.POINT = os.path.join(self.POINT, item[1])
				self.Action()
				self.Paint()

	def ToolTipWin(self, x, y, item=[]):
		try:
			self.tipwindow.destroy()
		except:
			pass		
		self.tipwindow = Toplevel(self, width=100, height=20)
		self.tipwindow.wm_overrideredirect(1)
		self.tipwindow.wm_geometry("+%d+%d" % (x + 20, y + 95))
		# label
		txt = "%s: %s\nFilesize: %s" % (item[2], item[1], HumanValue(item[0]))
		label = Label(self.tipwindow, text=txt, justify=LEFT,
					background="#ffffe0", relief=SOLID, borderwidth=1,
					font=("tahoma", "10", "normal"))
		label.pack(ipadx=1)

		# if is a dir then change the cursor
		if item[2] == "Dir":
			self.canvas['cursor'] = "hand1";
		else:
			self.canvas['cursor'] = "";

	def DelToolTip(self, *args):
		try:
			self.tipwindow.destroy()
		except:
			pass

	def myCanvas(self):
		# create a canvas
		self.canvas = Canvas.Canvas(self,
						width=self.canvas_width,
						height=self.canvas_height)
		#self.canvas['bg'] = "white"
		self.canvas.bind("<Leave>", self.DelToolTip)
		self.canvas.grid(columnspan=4, row=1, column=0)

	def Paint(self):
		"""Action"""
		# destroy all ToolTipWindows
		try:
			self.tipwindow.destroy()
		except:
			pass

		# set the new entry
		self.EntryPoint.delete(0, END)
		self.EntryPoint.insert(0, self.POINT)

		# remove all old canvas
		for item in self.canvas.find_all():
			self.canvas.delete(item)

		# colors for the arcs
		Color = [	'#00008B', '#8B0000', '#FFD700', '#006400',	
				'#FF4500', '#DC143C', '#7FFF00', '#00FFFF',		
				'#808080', '#008080', '#CCCC80', '#FFCC80',
				'#808000', '#008000', '#CCCC00', '#FFCC00',
				'#8080CC', '#0080CC', '#CCCCCC', '#FFCCCC',
				'#8080FF', '#0080FF', '#CCCCFF', '#FFCCFF']
		# from filesize to 360 grad and 2pi
		self.NewFileList = []
		c = 0	# color value
		for file in self.FileList():
			self.NewFileList.append([	
					file[0], 							# filesize
					file[1], 							# name
					file[2], 							# mark 'd' or 'f'
					float((file[0] * 360)  / self.FileSumme()), 	# 100% = 360
					float((file[0] * 2 * pi) / self.FileSumme()),	# 100% = 2 x pi
(Kreisumfang)
					Color[c],							# color
					''								#
					])
			c += 1
			# if end of color list: beginn the list
			if c == 24: c = 0;

		# start values of arcs
		color = item1 = z = 0
		center_x = self.win_width / 2
		center_y = self.win_height/2

		for item2 in self.NewFileList:
			# create a arc
			arc = Canvas.Arc(self.canvas,
						center_x - self.circle_rad,
						center_y - self.circle_rad,
						center_x + self.circle_rad,
						center_y + self.circle_rad,
						width=1, outline='black', fill=item2[5],
						start = item1 + 90,
						extent = item2[3],
						style = PIESLICE )
			# if this a file, then color with gray
			if item2[2] == "File": arc['stipple'] = "gray75";
			# old value = old value + new value
			item1 = item1 + item2[3]

			# arc id in self.NewFileList
			item2[6] = arc.id
			# mouse over binding
			arc.bind("<Motion>", self.MouseOverCallback)
			# mouse klick binding; if this a Dir
			if item2[2] == "Dir":
				arc.bind("<Button-1>", self.MouseKlickCallback)
		
		# center circle with sum of filesize
		SumRadius = 40
		SumOval = Canvas.Oval(self.canvas,
						self.win_width/2 - SumRadius,
						self.win_height/2 - SumRadius,
						self.win_width/2 + SumRadius,
						self.win_height/2 + SumRadius,
						width=0, outline='gray', fill = '#EFEFEF',
						)
		# bind a command
		SumOval.bind("<Button-1>", self.WalkUp)

		SumText = Canvas.CanvasText(self.canvas,
						self.win_width/2,
						self.win_height/2
						)
		SumText.insert(0, 'Klick: Up\n')
		SumText.insert(END, HumanValue(self.FileSumme()))
		SumText.bind("<Button-1>", self.WalkUp)

	def myHelp(self):
		"""View the help message"""
		print "hier kommt das help"

	def myAbout(self):
		"""view the about message"""
		print "hier kommt das about"

	def myClose(self):
		"""close this application"""
		sys.exit(0)

print "----------------"

#win = MainWin(os.sep)
win = MainWin(os.getcwd())

if __name__ == "__main__":
	win.mainloop()


# end