1 import Tkinter as tk
2 import threading, Queue
3
4
5 WIDE = 200
6 HIGH = 200
7
8 REAL_FROM = -2
9 REAL_TO = 1
10 IMAG_FROM = -1.5
11 IMAG_TO = 1.5
12
13 N = 64
14
15
16 class MandelbrotWorker(threading.Thread):
17 def __init__(self, aQueue, imgWidth, imgHeight, bounds, **kwargs):
18 threading.Thread.__init__(self)
19 self.setDaemon(1)
20 self.imgWidth = imgWidth
21 self.imgHeight = imgHeight
22 self.fwidth = float(imgWidth)
23 self.fheight = float(imgHeight)
24 self.mapLeft = bounds[0]
25 self.mapTop = bounds[3]
26 self.mapWidth = bounds[1] - bounds[0]
27 self.mapHeight = bounds[3] - bounds[2]
28 self.resultQueue = aQueue
29 self.n = N
30 self.start()
31
32 def run(self):
33 for x in xrange(self.imgWidth):
34 for y in xrange(self.imgHeight):
35 percx = x/self.fwidth
36 percy = y/self.fheight
37 xp = self.mapLeft + percx*self.mapWidth
38 yp = self.mapTop - percy*self.mapHeight
39 o = complex(0,0)
40 z = complex(xp,yp)
41 colorcode = 0
42 for trials in xrange(self.n):
43 if abs(o) <= 2.0:
44 o = o**2 + z
45 else:
46 colorcode = trials
47 break
48 self.resultQueue.put((x,y,colorcode))
49
50
51 class ThreadedFractal(tk.Toplevel):
52 def __init__(self, master):
53 tk.Toplevel.__init__(self, master)
54 self.protocol('WM_DELETE_WINDOW', self.on_close)
55 self.status = tk.Label(self)
56 self.status.pack(fill='x')
57 self.display = tk.Label(self)
58 self.display.pack()
59 self.img = tk.PhotoImage(width=WIDE, height=HIGH)
60 self.display.config(image=self.img)
61 self.count = 0
62 self.totalPixels = WIDE*HIGH
63 self.queue = Queue.Queue()
64 self.rgb = []
65 self.make_colours()
66 self.go()
67
68 def make_colours(self):
69 for i in xrange(N):
70 r = i*7%200 + 55
71 g = i*9%200 + 55
72 b = i*11%200 + 55
73 colour = '#%02x%02x%02x' %(r,g,b)
74 self.rgb.append(colour)
75
76 def scheduler(self):
77 self.after(0, self.poll)
78
79 def go(self):
80 self.workerThread = MandelbrotWorker(self.queue, WIDE, HIGH,
81 (REAL_FROM,REAL_TO,IMAG_FROM,IMAG_TO))
82 self.after(500, self.poll)
83
84 def poll(self):
85 if self.count < self.totalPixels:
86 try:
87 x,y,code = self.queue.get_nowait()
88 except Queue.Empty:
89 pass
90 else:
91 colour = self.rgb[code]
92 self.img.put(colour, to=(x,y))
93 self.count += 1
94 self.status.config(text='%s of %s pixels' %(self.count,
95 self.totalPixels))
96 self.after_idle(self.scheduler)
97
98 def on_close(self):
99 self.master.destroy()
100
101
102 root = tk.Tk()
103 root.withdraw()
104 app = ThreadedFractal(root)
105 app.mainloop()
106