1#!/usr/bin/env python 2import sys 3import os 4 5from Tkinter import * 6from idlelib.Percolator import Percolator 7from idlelib.ColorDelegator import ColorDelegator 8from idlelib.textView import view_file 9 10import turtle 11import time 12 13demo_dir = os.getcwd() 14if "turtleDemo.py" not in os.listdir(demo_dir): 15 print "Directory of turtleDemo must be current working directory!" 16 print "But in your case this is", demo_dir 17 sys.exit() 18 19STARTUP = 1 20READY = 2 21RUNNING = 3 22DONE = 4 23EVENTDRIVEN = 5 24 25menufont = ("Arial", 12, NORMAL) 26btnfont = ("Arial", 12, 'bold') 27txtfont = ('Lucida Console', 8, 'normal') 28 29def getExampleEntries(): 30 entries1 = [entry for entry in os.listdir(demo_dir) if 31 entry.startswith("tdemo_") and 32 not entry.endswith(".pyc")] 33 entries2 = [] 34 for entry in entries1: 35 if entry.endswith(".py"): 36 entries2.append(entry) 37 else: 38 path = os.path.join(demo_dir, entry) 39 sys.path.append(path) 40 subdir = [entry] 41 scripts = [script for script in os.listdir(path) if 42 script.startswith("tdemo_") and 43 script.endswith(".py")] 44 entries2.append(subdir+scripts) 45 return entries2 46 47help_entries = ( # (help_label, help_file) 48 ('Turtledemo help', "demohelp.txt"), 49 ('About turtledemo', "about_turtledemo.txt"), 50 ('About turtle module', "about_turtle.txt"), 51 ) 52 53class DemoWindow(object): 54 55 def __init__(self, filename=None): 56 self.root = root = turtle._root = Tk() 57 root.title('Python turtle-graphics examples') 58 root.wm_protocol("WM_DELETE_WINDOW", self._destroy) 59 60 root.grid_rowconfigure(1, weight=1) 61 root.grid_columnconfigure(0, weight=1) 62 root.grid_columnconfigure(1, minsize=90, weight=1) 63 root.grid_columnconfigure(2, minsize=90, weight=1) 64 root.grid_columnconfigure(3, minsize=90, weight=1) 65 66 self.mBar = Frame(root, relief=RAISED, borderwidth=2) 67 self.ExamplesBtn = self.makeLoadDemoMenu() 68 self.OptionsBtn = self.makeHelpMenu() 69 self.mBar.grid(row=0, columnspan=4, sticky='news') 70 71 pane = PanedWindow(orient=HORIZONTAL, sashwidth=5, 72 sashrelief=SOLID, bg='#ddd') 73 pane.add(self.makeTextFrame(pane)) 74 pane.add(self.makeGraphFrame(pane)) 75 pane.grid(row=1, columnspan=4, sticky='news') 76 77 self.output_lbl = Label(root, height= 1, text=" --- ", bg="#ddf", 78 font=("Arial", 16, 'normal'), borderwidth=2, 79 relief=RIDGE) 80 self.start_btn = Button(root, text=" START ", font=btnfont, 81 fg="white", disabledforeground = "#fed", 82 command=self.startDemo) 83 self.stop_btn = Button(root, text=" STOP ", font=btnfont, 84 fg="white", disabledforeground = "#fed", 85 command=self.stopIt) 86 self.clear_btn = Button(root, text=" CLEAR ", font=btnfont, 87 fg="white", disabledforeground="#fed", 88 command = self.clearCanvas) 89 self.output_lbl.grid(row=2, column=0, sticky='news', padx=(0,5)) 90 self.start_btn.grid(row=2, column=1, sticky='ew') 91 self.stop_btn.grid(row=2, column=2, sticky='ew') 92 self.clear_btn.grid(row=2, column=3, sticky='ew') 93 94 Percolator(self.text).insertfilter(ColorDelegator()) 95 self.dirty = False 96 self.exitflag = False 97 if filename: 98 self.loadfile(filename) 99 self.configGUI(NORMAL, DISABLED, DISABLED, DISABLED, 100 "Choose example from menu", "black") 101 self.state = STARTUP 102 103 104 def onResize(self, event): 105 cwidth = self._canvas.winfo_width() 106 cheight = self._canvas.winfo_height() 107 self._canvas.xview_moveto(0.5*(self.canvwidth-cwidth)/self.canvwidth) 108 self._canvas.yview_moveto(0.5*(self.canvheight-cheight)/self.canvheight) 109 110 def makeTextFrame(self, root): 111 self.text_frame = text_frame = Frame(root) 112 self.text = text = Text(text_frame, name='text', padx=5, 113 wrap='none', width=45) 114 115 self.vbar = vbar = Scrollbar(text_frame, name='vbar') 116 vbar['command'] = text.yview 117 vbar.pack(side=LEFT, fill=Y) 118 self.hbar = hbar = Scrollbar(text_frame, name='hbar', orient=HORIZONTAL) 119 hbar['command'] = text.xview 120 hbar.pack(side=BOTTOM, fill=X) 121 122 text['font'] = txtfont 123 text['yscrollcommand'] = vbar.set 124 text['xscrollcommand'] = hbar.set 125 text.pack(side=LEFT, fill=BOTH, expand=1) 126 return text_frame 127 128 def makeGraphFrame(self, root): 129 turtle._Screen._root = root 130 self.canvwidth = 1000 131 self.canvheight = 800 132 turtle._Screen._canvas = self._canvas = canvas = turtle.ScrolledCanvas( 133 root, 800, 600, self.canvwidth, self.canvheight) 134 canvas.adjustScrolls() 135 canvas._rootwindow.bind('<Configure>', self.onResize) 136 canvas._canvas['borderwidth'] = 0 137 138 self.screen = _s_ = turtle.Screen() 139 turtle.TurtleScreen.__init__(_s_, _s_._canvas) 140 self.scanvas = _s_._canvas 141 turtle.RawTurtle.screens = [_s_] 142 return canvas 143 144 def configGUI(self, menu, start, stop, clear, txt="", color="blue"): 145 self.ExamplesBtn.config(state=menu) 146 147 self.start_btn.config(state=start, 148 bg="#d00" if start == NORMAL else "#fca") 149 self.stop_btn.config(state=stop, 150 bg="#d00" if stop == NORMAL else "#fca") 151 self.clear_btn.config(state=clear, 152 bg="#d00" if clear == NORMAL else"#fca") 153 self.output_lbl.config(text=txt, fg=color) 154 155 def makeLoadDemoMenu(self): 156 CmdBtn = Menubutton(self.mBar, text='Examples', 157 underline=0, font=menufont) 158 CmdBtn.pack(side=LEFT, padx="2m") 159 CmdBtn.menu = Menu(CmdBtn) 160 161 for entry in getExampleEntries(): 162 def loadexample(x): 163 def emit(): 164 self.loadfile(x) 165 return emit 166 if isinstance(entry,str): 167 CmdBtn.menu.add_command(label=entry[6:-3], underline=0, 168 font=menufont, 169 command=loadexample(entry)) 170 else: 171 _dir, entries = entry[0], entry[1:] 172 CmdBtn.menu.choices = Menu(CmdBtn.menu) 173 for e in entries: 174 CmdBtn.menu.choices.add_command( 175 label=e[6:-3], underline=0, font=menufont, 176 command = loadexample(os.path.join(_dir,e))) 177 CmdBtn.menu.add_cascade( 178 label=_dir[6:], menu = CmdBtn.menu.choices, font=menufont) 179 180 CmdBtn['menu'] = CmdBtn.menu 181 return CmdBtn 182 183 def makeHelpMenu(self): 184 CmdBtn = Menubutton(self.mBar, text='Help', underline=0, font = menufont) 185 CmdBtn.pack(side=LEFT, padx='2m') 186 CmdBtn.menu = Menu(CmdBtn) 187 188 for help_label, help_file in help_entries: 189 def show(help_label=help_label, help_file=help_file): 190 view_file(self.root, help_label, os.path.join(demo_dir, help_file)) 191 CmdBtn.menu.add_command(label=help_label, font=menufont, command=show) 192 193 CmdBtn['menu'] = CmdBtn.menu 194 return CmdBtn 195 196 def refreshCanvas(self): 197 if not self.dirty: return 198 self.screen.clear() 199 self.dirty=False 200 201 def loadfile(self,filename): 202 self.refreshCanvas() 203 if os.path.exists(filename) and not os.path.isdir(filename): 204 # load and display file text 205 f = open(filename,'r') 206 chars = f.read() 207 f.close() 208 self.text.delete("1.0", "end") 209 self.text.insert("1.0",chars) 210 direc, fname = os.path.split(filename) 211 self.root.title(fname[6:-3]+" - a Python turtle graphics example") 212 self.module = __import__(fname[:-3]) 213 self.configGUI(NORMAL, NORMAL, DISABLED, DISABLED, 214 "Press start button", "red") 215 self.state = READY 216 217 def startDemo(self): 218 self.refreshCanvas() 219 self.dirty = True 220 turtle.TurtleScreen._RUNNING = True 221 self.configGUI(DISABLED, DISABLED, NORMAL, DISABLED, 222 "demo running...", "black") 223 self.screen.clear() 224 self.screen.mode("standard") 225 self.state = RUNNING 226 227 try: 228 result = self.module.main() 229 if result == "EVENTLOOP": 230 self.state = EVENTDRIVEN 231 else: 232 self.state = DONE 233 except turtle.Terminator: 234 if self.root is None: 235 return 236 self.state = DONE 237 result = "stopped!" 238 if self.state == DONE: 239 self.configGUI(NORMAL, NORMAL, DISABLED, NORMAL, 240 result) 241 elif self.state == EVENTDRIVEN: 242 self.exitflag = True 243 self.configGUI(DISABLED, DISABLED, NORMAL, DISABLED, 244 "use mouse/keys or STOP", "red") 245 246 def clearCanvas(self): 247 self.refreshCanvas() 248 self.scanvas.config(cursor="") 249 self.configGUI(NORMAL, NORMAL, DISABLED, DISABLED) 250 251 def stopIt(self): 252 if self.exitflag: 253 self.clearCanvas() 254 self.exitflag = False 255 self.configGUI(NORMAL, NORMAL, DISABLED, DISABLED, 256 "STOPPED!", "red") 257 turtle.TurtleScreen._RUNNING = False 258 else: 259 turtle.TurtleScreen._RUNNING = False 260 261 def _destroy(self): 262 turtle.TurtleScreen._RUNNING = False 263 self.root.destroy() 264 self.root = None 265 #sys.exit() 266 267def main(): 268 demo = DemoWindow() 269 demo.root.mainloop() 270 271if __name__ == '__main__': 272 main() 273