Google+ Tools
Make Google+ profile picture
Make Google plus banners for profile
Create and share your Google Plus profile banners.

Profile image for mrk studios Sunjay Varma on September 27, 2010

A simple, yet effective rectangle selection box. :)

Works with a tkinter canvas! Just add the class and set it up like in the example code. The cross heir was my own touch, the RectTracker only draws a box.

Have fun! And please don't just vote down, post what you don't like if you don't like it.

Language
python
Tags

Python Tkinter Canvas Rectangle Selection Box


"""Rect Tracker class for Python Tkinter Canvas"""

def groups(glist, numPerGroup=2):
	result = []

	i = 0
	cur = []
	for item in glist:
		if not i < numPerGroup:
			result.append(cur)
			cur = []
			i = 0

		cur.append(item)
		i += 1

	if cur:
		result.append(cur)

	return result

def average(points):
	aver = [0,0]
	
	for point in points:
		aver[0] += point[0]
		aver[1] += point[1]
		
	return aver[0]/len(points), aver[1]/len(points)

class RectTracker:
	
	def __init__(self, canvas):
		self.canvas = canvas
		self.item = None
		
	def draw(self, start, end, **opts):
		"""Draw the rectangle"""
		return self.canvas.create_rectangle(*(list(start)+list(end)), **opts)
		
	def autodraw(self, **opts):
		"""Setup automatic drawing; supports command option"""
		self.start = None
		self.canvas.bind("<Button-1>", self.__update, '+')
		self.canvas.bind("<B1-Motion>", self.__update, '+')
		self.canvas.bind("<ButtonRelease-1>", self.__stop, '+')
		
		self._command = opts.pop('command', lambda *args: None)
		self.rectopts = opts
		
	def __update(self, event):
		if not self.start:
			self.start = [event.x, event.y]
			return
		
		if self.item is not None:
			self.canvas.delete(self.item)
		self.item = self.draw(self.start, (event.x, event.y), **self.rectopts)
		self._command(self.start, (event.x, event.y))
		
	def __stop(self, event):
		self.start = None
		self.canvas.delete(self.item)
		self.item = None
		
	def hit_test(self, start, end, tags=None, ignoretags=None, ignore=[]):
		"""
		Check to see if there are items between the start and end
		"""
		ignore = set(ignore)
		ignore.update([self.item])
		
		# first filter all of the items in the canvas
		if isinstance(tags, str):
			tags = [tags]
		
		if tags:
			tocheck = []
			for tag in tags:
				tocheck.extend(self.canvas.find_withtag(tag))
		else:
			tocheck = self.canvas.find_all()
		tocheck = [x for x in tocheck if x != self.item]
		if ignoretags:
			if not hasattr(ignoretags, '__iter__'):
				ignoretags = [ignoretags]
			tocheck = [x for x in tocheck if x not in self.canvas.find_withtag(it) for it in ignoretags]
		
		self.items = tocheck
		
		# then figure out the box
		xlow = min(start[0], end[0])
		xhigh = max(start[0], end[0])
		
		ylow = min(start[1], end[1])
		yhigh = max(start[1], end[1])
		
		items = []
		for item in tocheck:
			if item not in ignore:
				x, y = average(groups(self.canvas.coords(item)))
				if (xlow < x < xhigh) and (ylow < y < yhigh):
					items.append(item)
	
		return items

def main():
	from random import shuffle
	
	canv = Canvas(width=500, height=500)
	canv.create_rectangle(50, 50, 250, 150, fill='red')
	canv.pack(fill=BOTH, expand=YES)
	
	rect = RectTracker(canv)
	# draw some base rectangles
	rect.draw([50,50], [250, 150], fill='red', tags=('red', 'box'))
	rect.draw([300,300], [400, 450], fill='green', tags=('gre', 'box'))
	
	# just for fun
	x, y = None, None
	def cool_design(event):
		global x, y
		kill_xy()
		
		dashes = [3, 2]
		x = canv.create_line(event.x, 0, event.x, 1000, dash=dashes, tags='no')
		y = canv.create_line(0, event.y, 1000, event.y, dash=dashes, tags='no')
		
	def kill_xy(event=None):
		canv.delete('no')
	
	canv.bind('<Motion>', cool_design, '+')
	
	# command
	def onDrag(start, end):
		global x,y
		items = rect.hit_test(start, end)
		for x in rect.items:
			if x not in items:
				canv.itemconfig(x, fill='grey')
			else:
				canv.itemconfig(x, fill='blue')
	
	rect.autodraw(fill="", width=2, command=onDrag)
	
	mainloop()

if __name__ == '__main__':
	try:
		from tkinter import *
	except ImportError:
		from Tkinter import *
	main()

Comments

blog comments powered by Disqus