| #!/usr/bin/env python | |
| import sys | |
| import os | |
| from Tkinter import * | |
| from idlelib.Percolator import Percolator | |
| from idlelib.ColorDelegator import ColorDelegator | |
| from idlelib.textView import view_file | |
| import turtle | |
| import time | |
| demo_dir = os.getcwd() | |
| if "turtleDemo.py" not in os.listdir(demo_dir): | |
| print "Directory of turtleDemo must be current working directory!" | |
| print "But in your case this is", demo_dir | |
| sys.exit() | |
| STARTUP = 1 | |
| READY = 2 | |
| RUNNING = 3 | |
| DONE = 4 | |
| EVENTDRIVEN = 5 | |
| menufont = ("Arial", 12, NORMAL) | |
| btnfont = ("Arial", 12, 'bold') | |
| txtfont = ('Lucida Console', 8, 'normal') | |
| def getExampleEntries(): | |
| entries1 = [entry for entry in os.listdir(demo_dir) if | |
| entry.startswith("tdemo_") and | |
| not entry.endswith(".pyc")] | |
| entries2 = [] | |
| for entry in entries1: | |
| if entry.endswith(".py"): | |
| entries2.append(entry) | |
| else: | |
| path = os.path.join(demo_dir, entry) | |
| sys.path.append(path) | |
| subdir = [entry] | |
| scripts = [script for script in os.listdir(path) if | |
| script.startswith("tdemo_") and | |
| script.endswith(".py")] | |
| entries2.append(subdir+scripts) | |
| return entries2 | |
| help_entries = ( # (help_label, help_file) | |
| ('Turtledemo help', "demohelp.txt"), | |
| ('About turtledemo', "about_turtledemo.txt"), | |
| ('About turtle module', "about_turtle.txt"), | |
| ) | |
| class DemoWindow(object): | |
| def __init__(self, filename=None): | |
| self.root = root = turtle._root = Tk() | |
| root.title('Python turtle-graphics examples') | |
| root.wm_protocol("WM_DELETE_WINDOW", self._destroy) | |
| root.grid_rowconfigure(1, weight=1) | |
| root.grid_columnconfigure(0, weight=1) | |
| root.grid_columnconfigure(1, minsize=90, weight=1) | |
| root.grid_columnconfigure(2, minsize=90, weight=1) | |
| root.grid_columnconfigure(3, minsize=90, weight=1) | |
| self.mBar = Frame(root, relief=RAISED, borderwidth=2) | |
| self.ExamplesBtn = self.makeLoadDemoMenu() | |
| self.OptionsBtn = self.makeHelpMenu() | |
| self.mBar.grid(row=0, columnspan=4, sticky='news') | |
| pane = PanedWindow(orient=HORIZONTAL, sashwidth=5, | |
| sashrelief=SOLID, bg='#ddd') | |
| pane.add(self.makeTextFrame(pane)) | |
| pane.add(self.makeGraphFrame(pane)) | |
| pane.grid(row=1, columnspan=4, sticky='news') | |
| self.output_lbl = Label(root, height= 1, text=" --- ", bg="#ddf", | |
| font=("Arial", 16, 'normal'), borderwidth=2, | |
| relief=RIDGE) | |
| self.start_btn = Button(root, text=" START ", font=btnfont, | |
| fg="white", disabledforeground = "#fed", | |
| command=self.startDemo) | |
| self.stop_btn = Button(root, text=" STOP ", font=btnfont, | |
| fg="white", disabledforeground = "#fed", | |
| command=self.stopIt) | |
| self.clear_btn = Button(root, text=" CLEAR ", font=btnfont, | |
| fg="white", disabledforeground="#fed", | |
| command = self.clearCanvas) | |
| self.output_lbl.grid(row=2, column=0, sticky='news', padx=(0,5)) | |
| self.start_btn.grid(row=2, column=1, sticky='ew') | |
| self.stop_btn.grid(row=2, column=2, sticky='ew') | |
| self.clear_btn.grid(row=2, column=3, sticky='ew') | |
| Percolator(self.text).insertfilter(ColorDelegator()) | |
| self.dirty = False | |
| self.exitflag = False | |
| if filename: | |
| self.loadfile(filename) | |
| self.configGUI(NORMAL, DISABLED, DISABLED, DISABLED, | |
| "Choose example from menu", "black") | |
| self.state = STARTUP | |
| def onResize(self, event): | |
| cwidth = self._canvas.winfo_width() | |
| cheight = self._canvas.winfo_height() | |
| self._canvas.xview_moveto(0.5*(self.canvwidth-cwidth)/self.canvwidth) | |
| self._canvas.yview_moveto(0.5*(self.canvheight-cheight)/self.canvheight) | |
| def makeTextFrame(self, root): | |
| self.text_frame = text_frame = Frame(root) | |
| self.text = text = Text(text_frame, name='text', padx=5, | |
| wrap='none', width=45) | |
| self.vbar = vbar = Scrollbar(text_frame, name='vbar') | |
| vbar['command'] = text.yview | |
| vbar.pack(side=LEFT, fill=Y) | |
| self.hbar = hbar = Scrollbar(text_frame, name='hbar', orient=HORIZONTAL) | |
| hbar['command'] = text.xview | |
| hbar.pack(side=BOTTOM, fill=X) | |
| text['font'] = txtfont | |
| text['yscrollcommand'] = vbar.set | |
| text['xscrollcommand'] = hbar.set | |
| text.pack(side=LEFT, fill=BOTH, expand=1) | |
| return text_frame | |
| def makeGraphFrame(self, root): | |
| turtle._Screen._root = root | |
| self.canvwidth = 1000 | |
| self.canvheight = 800 | |
| turtle._Screen._canvas = self._canvas = canvas = turtle.ScrolledCanvas( | |
| root, 800, 600, self.canvwidth, self.canvheight) | |
| canvas.adjustScrolls() | |
| canvas._rootwindow.bind('<Configure>', self.onResize) | |
| canvas._canvas['borderwidth'] = 0 | |
| self.screen = _s_ = turtle.Screen() | |
| turtle.TurtleScreen.__init__(_s_, _s_._canvas) | |
| self.scanvas = _s_._canvas | |
| turtle.RawTurtle.screens = [_s_] | |
| return canvas | |
| def configGUI(self, menu, start, stop, clear, txt="", color="blue"): | |
| self.ExamplesBtn.config(state=menu) | |
| self.start_btn.config(state=start, | |
| bg="#d00" if start == NORMAL else "#fca") | |
| self.stop_btn.config(state=stop, | |
| bg="#d00" if stop == NORMAL else "#fca") | |
| self.clear_btn.config(state=clear, | |
| bg="#d00" if clear == NORMAL else"#fca") | |
| self.output_lbl.config(text=txt, fg=color) | |
| def makeLoadDemoMenu(self): | |
| CmdBtn = Menubutton(self.mBar, text='Examples', | |
| underline=0, font=menufont) | |
| CmdBtn.pack(side=LEFT, padx="2m") | |
| CmdBtn.menu = Menu(CmdBtn) | |
| for entry in getExampleEntries(): | |
| def loadexample(x): | |
| def emit(): | |
| self.loadfile(x) | |
| return emit | |
| if isinstance(entry,str): | |
| CmdBtn.menu.add_command(label=entry[6:-3], underline=0, | |
| font=menufont, | |
| command=loadexample(entry)) | |
| else: | |
| _dir, entries = entry[0], entry[1:] | |
| CmdBtn.menu.choices = Menu(CmdBtn.menu) | |
| for e in entries: | |
| CmdBtn.menu.choices.add_command( | |
| label=e[6:-3], underline=0, font=menufont, | |
| command = loadexample(os.path.join(_dir,e))) | |
| CmdBtn.menu.add_cascade( | |
| label=_dir[6:], menu = CmdBtn.menu.choices, font=menufont) | |
| CmdBtn['menu'] = CmdBtn.menu | |
| return CmdBtn | |
| def makeHelpMenu(self): | |
| CmdBtn = Menubutton(self.mBar, text='Help', underline=0, font = menufont) | |
| CmdBtn.pack(side=LEFT, padx='2m') | |
| CmdBtn.menu = Menu(CmdBtn) | |
| for help_label, help_file in help_entries: | |
| def show(help_label=help_label, help_file=help_file): | |
| view_file(self.root, help_label, os.path.join(demo_dir, help_file)) | |
| CmdBtn.menu.add_command(label=help_label, font=menufont, command=show) | |
| CmdBtn['menu'] = CmdBtn.menu | |
| return CmdBtn | |
| def refreshCanvas(self): | |
| if not self.dirty: return | |
| self.screen.clear() | |
| self.dirty=False | |
| def loadfile(self,filename): | |
| self.refreshCanvas() | |
| if os.path.exists(filename) and not os.path.isdir(filename): | |
| # load and display file text | |
| f = open(filename,'r') | |
| chars = f.read() | |
| f.close() | |
| self.text.delete("1.0", "end") | |
| self.text.insert("1.0",chars) | |
| direc, fname = os.path.split(filename) | |
| self.root.title(fname[6:-3]+" - a Python turtle graphics example") | |
| self.module = __import__(fname[:-3]) | |
| self.configGUI(NORMAL, NORMAL, DISABLED, DISABLED, | |
| "Press start button", "red") | |
| self.state = READY | |
| def startDemo(self): | |
| self.refreshCanvas() | |
| self.dirty = True | |
| turtle.TurtleScreen._RUNNING = True | |
| self.configGUI(DISABLED, DISABLED, NORMAL, DISABLED, | |
| "demo running...", "black") | |
| self.screen.clear() | |
| self.screen.mode("standard") | |
| self.state = RUNNING | |
| try: | |
| result = self.module.main() | |
| if result == "EVENTLOOP": | |
| self.state = EVENTDRIVEN | |
| else: | |
| self.state = DONE | |
| except turtle.Terminator: | |
| if self.root is None: | |
| return | |
| self.state = DONE | |
| result = "stopped!" | |
| if self.state == DONE: | |
| self.configGUI(NORMAL, NORMAL, DISABLED, NORMAL, | |
| result) | |
| elif self.state == EVENTDRIVEN: | |
| self.exitflag = True | |
| self.configGUI(DISABLED, DISABLED, NORMAL, DISABLED, | |
| "use mouse/keys or STOP", "red") | |
| def clearCanvas(self): | |
| self.refreshCanvas() | |
| self.scanvas.config(cursor="") | |
| self.configGUI(NORMAL, NORMAL, DISABLED, DISABLED) | |
| def stopIt(self): | |
| if self.exitflag: | |
| self.clearCanvas() | |
| self.exitflag = False | |
| self.configGUI(NORMAL, NORMAL, DISABLED, DISABLED, | |
| "STOPPED!", "red") | |
| turtle.TurtleScreen._RUNNING = False | |
| else: | |
| turtle.TurtleScreen._RUNNING = False | |
| def _destroy(self): | |
| turtle.TurtleScreen._RUNNING = False | |
| self.root.destroy() | |
| self.root = None | |
| #sys.exit() | |
| def main(): | |
| demo = DemoWindow() | |
| demo.root.mainloop() | |
| if __name__ == '__main__': | |
| main() |