diff options
Diffstat (limited to 'Lib/idlelib')
-rw-r--r-- | Lib/idlelib/AutoComplete.py | 2 | ||||
-rw-r--r-- | Lib/idlelib/AutoCompleteWindow.py | 17 | ||||
-rw-r--r-- | Lib/idlelib/EditorWindow.py | 30 | ||||
-rw-r--r-- | Lib/idlelib/FileList.py | 2 | ||||
-rw-r--r-- | Lib/idlelib/IOBinding.py | 12 | ||||
-rw-r--r-- | Lib/idlelib/NEWS.txt | 20 | ||||
-rw-r--r-- | Lib/idlelib/PyShell.py | 3 | ||||
-rw-r--r-- | Lib/idlelib/WidgetRedirector.py | 102 | ||||
-rw-r--r-- | Lib/idlelib/aboutDialog.py | 40 | ||||
-rw-r--r-- | Lib/idlelib/configDialog.py | 102 | ||||
-rw-r--r-- | Lib/idlelib/run.py | 13 | ||||
-rw-r--r-- | Lib/idlelib/tabbedpages.py | 478 | ||||
-rw-r--r-- | Lib/idlelib/textView.py | 57 |
13 files changed, 710 insertions, 168 deletions
diff --git a/Lib/idlelib/AutoComplete.py b/Lib/idlelib/AutoComplete.py index b187741..b2b1657 100644 --- a/Lib/idlelib/AutoComplete.py +++ b/Lib/idlelib/AutoComplete.py @@ -27,7 +27,7 @@ class AutoComplete: menudefs = [ ('edit', [ - ("Show completions", "<<force-open-completions>>"), + ("Show Completions", "<<force-open-completions>>"), ]) ] diff --git a/Lib/idlelib/AutoCompleteWindow.py b/Lib/idlelib/AutoCompleteWindow.py index 785979e..ca9109b 100644 --- a/Lib/idlelib/AutoCompleteWindow.py +++ b/Lib/idlelib/AutoCompleteWindow.py @@ -283,20 +283,9 @@ class AutoCompleteWindow: self._selection_changed() return "break" - elif keysym == "Return" and not state: - # If start is a prefix of the selection, or there was an indication - # that the user used the completion window, put the selected - # completion in the text, and close the list. - # Otherwise, close the window and let the event through. - cursel = int(self.listbox.curselection()[0]) - if self.completions[cursel][:len(self.start)] == self.start or \ - self.userwantswindow: - self._change_start(self.completions[cursel]) - self.hide_window() - return "break" - else: - self.hide_window() - return + elif keysym == "Return": + self.hide_window() + return elif (self.mode == COMPLETE_ATTRIBUTES and keysym in ("period", "space", "parenleft", "parenright", "bracketleft", diff --git a/Lib/idlelib/EditorWindow.py b/Lib/idlelib/EditorWindow.py index a0a7b47..0cd668a 100644 --- a/Lib/idlelib/EditorWindow.py +++ b/Lib/idlelib/EditorWindow.py @@ -386,7 +386,7 @@ class EditorWindow(object): def help_dialog(self, event=None): fn=os.path.join(os.path.abspath(os.path.dirname(__file__)),'help.txt') - textView.TextViewer(self.top,'Help',fn) + textView.view_file(self.top,'Help',fn) def python_docs(self, event=None): if sys.platform[:3] == 'win': @@ -408,6 +408,7 @@ class EditorWindow(object): def paste(self,event): self.text.event_generate("<<Paste>>") + self.text.see("insert") return "break" def select_all(self, event=None): @@ -549,7 +550,8 @@ class EditorWindow(object): def close_hook(self): if self.flist: - self.flist.close_edit(self) + self.flist.unregister_maybe_terminate(self) + self.flist = None def set_close_hook(self, close_hook): self.close_hook = close_hook @@ -828,22 +830,21 @@ class EditorWindow(object): if self.io.filename: self.update_recent_files_list(new_file=self.io.filename) WindowList.unregister_callback(self.postwindowsmenu) - if self.close_hook: - self.close_hook() - self.flist = None - colorizing = 0 self.unload_extensions() - self.io.close(); self.io = None - self.undo = None # XXX + self.io.close() + self.io = None + self.undo = None if self.color: - colorizing = self.color.colorizing - doh = colorizing and self.top - self.color.close(doh) # Cancel colorization + self.color.close(False) + self.color = None self.text = None self.tkinter_vars = None - self.per.close(); self.per = None - if not colorizing: - self.top.destroy() + self.per.close() + self.per = None + self.top.destroy() + if self.close_hook: + # unless override: unregister from flist, terminate if last window + self.close_hook() def load_extensions(self): self.extensions = {} @@ -1501,6 +1502,7 @@ def test(): filename = None edit = EditorWindow(root=root, filename=filename) edit.set_close_hook(root.quit) + edit.text.bind("<<close-all-windows>>", edit.close_event) root.mainloop() root.destroy() diff --git a/Lib/idlelib/FileList.py b/Lib/idlelib/FileList.py index 2f5053f..53e30b4 100644 --- a/Lib/idlelib/FileList.py +++ b/Lib/idlelib/FileList.py @@ -55,7 +55,7 @@ class FileList: break return "break" - def close_edit(self, edit): + def unregister_maybe_terminate(self, edit): try: key = self.inversedict[edit] except KeyError: diff --git a/Lib/idlelib/IOBinding.py b/Lib/idlelib/IOBinding.py index b970dba..b4de84e 100644 --- a/Lib/idlelib/IOBinding.py +++ b/Lib/idlelib/IOBinding.py @@ -485,13 +485,23 @@ class IOBinding: self.text.insert("end-1c", "\n") def print_window(self, event): + m = tkMessageBox.Message( + title="Print", + message="Print to Default Printer", + icon=tkMessageBox.QUESTION, + type=tkMessageBox.OKCANCEL, + default=tkMessageBox.OK, + master=self.text) + reply = m.show() + if reply != tkMessageBox.OK: + self.text.focus_set() + return "break" tempfilename = None saved = self.get_saved() if saved: filename = self.filename # shell undo is reset after every prompt, looks saved, probably isn't if not saved or filename is None: - # XXX KBK 08Jun03 Wouldn't it be better to ask the user to save? (tfd, tempfilename) = tempfile.mkstemp(prefix='IDLE_tmp_') filename = tempfilename os.close(tfd) diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt index 460b5b5..0966152 100644 --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -30,6 +30,24 @@ What's New in IDLE 2.6a1? *Release date: XX-XXX-200X* UNRELEASED, but merged into 3.0a1 +- tabpage.py updated: tabbedPages.py now supports multiple dynamic rows + of tabs. Patch 1612746 Tal Einat. + +- Add confirmation dialog before printing. Patch 1717170 Tal Einat. + +- Show paste position if > 80 col. Patch 1659326 Tal Einat. + +- Update cursor color without restarting. Patch 1725576 Tal Einat. + +- Allow keyboard interrupt only when user code is executing in subprocess. + Patch 1225 Tal Einat (reworked from IDLE-Spoon). + +- configDialog cleanup. Patch 1730217 Tal Einat. + +- textView cleanup. Patch 1718043 Tal Einat. + +- Clean up EditorWindow close. + - Corrected some bugs in AutoComplete. Also, Page Up/Down in ACW implemented; mouse and cursor selection in ACWindow implemented; double Tab inserts current selection and closes ACW (similar to double-click and Return); scroll @@ -51,6 +69,8 @@ What's New in IDLE 2.6a1? - Bug #813342: Start the IDLE subprocess with -Qnew if the parent is started with that option. +- Honor the "Cancel" action in the save dialog (Debian bug #299092) + - Some syntax errors were being caught by tokenize during the tabnanny check, resulting in obscure error messages. Do the syntax check first. Bug 1562716, 1562719 diff --git a/Lib/idlelib/PyShell.py b/Lib/idlelib/PyShell.py index 3f9f567..097818f 100644 --- a/Lib/idlelib/PyShell.py +++ b/Lib/idlelib/PyShell.py @@ -296,9 +296,6 @@ class ModifiedColorDelegator(ColorDelegator): "stdout": idleConf.GetHighlight(theme, "stdout"), "stderr": idleConf.GetHighlight(theme, "stderr"), "console": idleConf.GetHighlight(theme, "console"), - ### KBK 10Aug07: None tag doesn't seem to serve a purpose and - ### breaks in py3k. Comment out for now. - #None: idleConf.GetHighlight(theme, "normal"), }) class ModifiedUndoDelegator(UndoDelegator): diff --git a/Lib/idlelib/WidgetRedirector.py b/Lib/idlelib/WidgetRedirector.py index 459fea7..3df5a9a 100644 --- a/Lib/idlelib/WidgetRedirector.py +++ b/Lib/idlelib/WidgetRedirector.py @@ -1,17 +1,38 @@ from Tkinter import * - class WidgetRedirector: - """Support for redirecting arbitrary widget subcommands.""" + """Support for redirecting arbitrary widget subcommands. + + Some Tk operations don't normally pass through Tkinter. For example, if a + character is inserted into a Text widget by pressing a key, a default Tk + binding to the widget's 'insert' operation is activated, and the Tk library + processes the insert without calling back into Tkinter. + + Although a binding to <Key> could be made via Tkinter, what we really want + to do is to hook the Tk 'insert' operation itself. + When a widget is instantiated, a Tcl command is created whose name is the + same as the pathname widget._w. This command is used to invoke the various + widget operations, e.g. insert (for a Text widget). We are going to hook + this command and provide a facility ('register') to intercept the widget + operation. + + In IDLE, the function being registered provides access to the top of a + Percolator chain. At the bottom of the chain is a call to the original + Tk widget operation. + + """ def __init__(self, widget): - self.dict = {} - self.widget = widget - self.tk = tk = widget.tk - w = widget._w + self._operations = {} + self.widget = widget # widget instance + self.tk = tk = widget.tk # widget's root + w = widget._w # widget's (full) Tk pathname self.orig = w + "_orig" + # Rename the Tcl command within Tcl: tk.call("rename", w, self.orig) + # Create a new Tcl command whose name is the widget's pathname, and + # whose action is to dispatch on the operation passed to the widget: tk.createcommand(w, self.dispatch) def __repr__(self): @@ -19,74 +40,87 @@ class WidgetRedirector: self.widget._w) def close(self): - for name in list(self.dict.keys()): - self.unregister(name) + for operation in list(self._operations): + self.unregister(operation) widget = self.widget; del self.widget orig = self.orig; del self.orig tk = widget.tk w = widget._w tk.deletecommand(w) + # restore the original widget Tcl command: tk.call("rename", orig, w) - def register(self, name, function): - if name in self.dict: - previous = dict[name] - else: - previous = OriginalCommand(self, name) - self.dict[name] = function - setattr(self.widget, name, function) - return previous - - def unregister(self, name): - if name in self.dict: - function = self.dict[name] - del self.dict[name] - if hasattr(self.widget, name): - delattr(self.widget, name) + def register(self, operation, function): + self._operations[operation] = function + setattr(self.widget, operation, function) + return OriginalCommand(self, operation) + + def unregister(self, operation): + if operation in self._operations: + function = self._operations[operation] + del self._operations[operation] + if hasattr(self.widget, operation): + delattr(self.widget, operation) return function else: return None - def dispatch(self, cmd, *args): - m = self.dict.get(cmd) + def dispatch(self, operation, *args): + '''Callback from Tcl which runs when the widget is referenced. + + If an operation has been registered in self._operations, apply the + associated function to the args passed into Tcl. Otherwise, pass the + operation through to Tk via the original Tcl function. + + Note that if a registered function is called, the operation is not + passed through to Tk. Apply the function returned by self.register() + to *args to accomplish that. For an example, see ColorDelegator.py. + + ''' + m = self._operations.get(operation) try: if m: return m(*args) else: - return self.tk.call((self.orig, cmd) + args) + return self.tk.call((self.orig, operation) + args) except TclError: return "" class OriginalCommand: - def __init__(self, redir, name): + def __init__(self, redir, operation): self.redir = redir - self.name = name + self.operation = operation self.tk = redir.tk self.orig = redir.orig self.tk_call = self.tk.call - self.orig_and_name = (self.orig, self.name) + self.orig_and_operation = (self.orig, self.operation) def __repr__(self): - return "OriginalCommand(%r, %r)" % (self.redir, self.name) + return "OriginalCommand(%r, %r)" % (self.redir, self.operation) def __call__(self, *args): - return self.tk_call(self.orig_and_name + args) + return self.tk_call(self.orig_and_operation + args) def main(): root = Tk() + root.wm_protocol("WM_DELETE_WINDOW", root.quit) text = Text() text.pack() text.focus_set() redir = WidgetRedirector(text) - global orig_insert + global previous_tcl_fcn def my_insert(*args): print("insert", args) - orig_insert(*args) - orig_insert = redir.register("insert", my_insert) + previous_tcl_fcn(*args) + previous_tcl_fcn = redir.register("insert", my_insert) + root.mainloop() + redir.unregister("insert") # runs after first 'close window' + redir.close() root.mainloop() + root.destroy() if __name__ == "__main__": main() diff --git a/Lib/idlelib/aboutDialog.py b/Lib/idlelib/aboutDialog.py index e0a6558..43a1313 100644 --- a/Lib/idlelib/aboutDialog.py +++ b/Lib/idlelib/aboutDialog.py @@ -111,45 +111,31 @@ class AboutDialog(Toplevel): idle_credits_b.pack(side=LEFT, padx=10, pady=10) def ShowLicense(self): - self.display_printer_text(license, 'About - License') + self.display_printer_text('About - License', license) def ShowCopyright(self): - self.display_printer_text(copyright, 'About - Copyright') + self.display_printer_text('About - Copyright', copyright) def ShowPythonCredits(self): - self.display_printer_text(credits, 'About - Python Credits') + self.display_printer_text('About - Python Credits', credits) def ShowIDLECredits(self): - self.ViewFile('About - Credits','CREDITS.txt') + self.display_file_text('About - Credits', 'CREDITS.txt', 'iso-8859-1') def ShowIDLEAbout(self): - self.ViewFile('About - Readme', 'README.txt') + self.display_file_text('About - Readme', 'README.txt') def ShowIDLENEWS(self): - self.ViewFile('About - NEWS', 'NEWS.txt') + self.display_file_text('About - NEWS', 'NEWS.txt') - def display_printer_text(self, printer, title): + def display_printer_text(self, title, printer): printer._Printer__setup() - data = '\n'.join(printer._Printer__lines) - textView.TextViewer(self, title, None, data) - - def ViewFile(self, viewTitle, viewFile, encoding=None): - fn = os.path.join(os.path.abspath(os.path.dirname(__file__)), viewFile) - if encoding: - import codecs - try: - textFile = codecs.open(fn, 'r') - except IOError: - import tkMessageBox - tkMessageBox.showerror(title='File Load Error', - message='Unable to load file %r .' % (fn,), - parent=self) - return - else: - data = textFile.read() - else: - data = None - textView.TextViewer(self, viewTitle, fn, data=data) + text = '\n'.join(printer._Printer__lines) + textView.view_text(self, title, text) + + def display_file_text(self, title, filename, encoding=None): + fn = os.path.join(os.path.abspath(os.path.dirname(__file__)), filename) + textView.view_file(self, title, fn, encoding) def Ok(self, event=None): self.destroy() diff --git a/Lib/idlelib/configDialog.py b/Lib/idlelib/configDialog.py index ad3071a..d00b579 100644 --- a/Lib/idlelib/configDialog.py +++ b/Lib/idlelib/configDialog.py @@ -15,7 +15,7 @@ import copy from idlelib.configHandler import idleConf from idlelib.dynOptionMenuWidget import DynOptionMenu -from idlelib.tabpage import TabPageSet +from idlelib.tabbedpages import TabbedPageSet from idlelib.keybindingDialog import GetKeysDialog from idlelib.configSectionNameDialog import GetCfgSectionNameDialog from idlelib.configHelpSourceEdit import GetHelpSourceDialog @@ -24,6 +24,8 @@ class ConfigDialog(Toplevel): def __init__(self,parent,title): Toplevel.__init__(self, parent) + self.wm_withdraw() + self.configure(borderwidth=5) self.geometry("+%d+%d" % (parent.winfo_rootx()+20, parent.winfo_rooty()+30)) @@ -58,31 +60,37 @@ class ConfigDialog(Toplevel): #self.bind('<F1>',self.Help) #context help self.LoadConfigs() self.AttachVarCallbacks() #avoid callbacks during LoadConfigs + + self.wm_deiconify() self.wait_window() def CreateWidgets(self): - self.tabPages = TabPageSet(self, - pageNames=['Fonts/Tabs','Highlighting','Keys','General']) - self.tabPages.ChangePage()#activates default (first) page - frameActionButtons = Frame(self) + self.tabPages = TabbedPageSet(self, + page_names=['Fonts/Tabs','Highlighting','Keys','General']) + frameActionButtons = Frame(self,pady=2) #action buttons self.buttonHelp = Button(frameActionButtons,text='Help', - command=self.Help,takefocus=FALSE) + command=self.Help,takefocus=FALSE, + padx=6,pady=3) self.buttonOk = Button(frameActionButtons,text='Ok', - command=self.Ok,takefocus=FALSE) + command=self.Ok,takefocus=FALSE, + padx=6,pady=3) self.buttonApply = Button(frameActionButtons,text='Apply', - command=self.Apply,takefocus=FALSE) + command=self.Apply,takefocus=FALSE, + padx=6,pady=3) self.buttonCancel = Button(frameActionButtons,text='Cancel', - command=self.Cancel,takefocus=FALSE) + command=self.Cancel,takefocus=FALSE, + padx=6,pady=3) self.CreatePageFontTab() self.CreatePageHighlight() self.CreatePageKeys() self.CreatePageGeneral() - self.buttonHelp.pack(side=RIGHT,padx=5,pady=5) - self.buttonOk.pack(side=LEFT,padx=5,pady=5) - self.buttonApply.pack(side=LEFT,padx=5,pady=5) - self.buttonCancel.pack(side=LEFT,padx=5,pady=5) + self.buttonHelp.pack(side=RIGHT,padx=5) + self.buttonOk.pack(side=LEFT,padx=5) + self.buttonApply.pack(side=LEFT,padx=5) + self.buttonCancel.pack(side=LEFT,padx=5) frameActionButtons.pack(side=BOTTOM) + Frame(self, border=0).pack(side=BOTTOM,pady=2) self.tabPages.pack(side=TOP,expand=TRUE,fill=BOTH) def CreatePageFontTab(self): @@ -94,16 +102,17 @@ class ConfigDialog(Toplevel): self.editFont=tkFont.Font(self,('courier',10,'normal')) ##widget creation #body frame - frame=self.tabPages.pages['Fonts/Tabs']['page'] + frame=self.tabPages.pages['Fonts/Tabs'].frame #body section frames - frameFont=Frame(frame,borderwidth=2,relief=GROOVE) - frameIndent=Frame(frame,borderwidth=2,relief=GROOVE) + frameFont=LabelFrame(frame,borderwidth=2,relief=GROOVE, + text=' Base Editor Font ') + frameIndent=LabelFrame(frame,borderwidth=2,relief=GROOVE, + text=' Indentation Width ') #frameFont - labelFontTitle=Label(frameFont,text='Set Base Editor Font') frameFontName=Frame(frameFont) frameFontParam=Frame(frameFont) labelFontNameTitle=Label(frameFontName,justify=LEFT, - text='Font :') + text='Font Face :') self.listFontName=Listbox(frameFontName,height=5,takefocus=FALSE, exportselection=FALSE) self.listFontName.bind('<ButtonRelease-1>',self.OnListFontButtonRelease) @@ -124,14 +133,13 @@ class ConfigDialog(Toplevel): labelSpaceNumTitle=Label(frameIndentSize, justify=LEFT, text='Python Standard: 4 Spaces!') self.scaleSpaceNum=Scale(frameIndentSize, variable=self.spaceNum, - label='Indentation Width', orient='horizontal', + orient='horizontal', tickinterval=2, from_=2, to=16) #widget packing #body - frameFont.pack(side=LEFT,padx=5,pady=10,expand=TRUE,fill=BOTH) - frameIndent.pack(side=LEFT,padx=5,pady=10,fill=Y) + frameFont.pack(side=LEFT,padx=5,pady=5,expand=TRUE,fill=BOTH) + frameIndent.pack(side=LEFT,padx=5,pady=5,fill=Y) #frameFont - labelFontTitle.pack(side=TOP,anchor=W,padx=5,pady=5) frameFontName.pack(side=TOP,padx=5,pady=5,fill=X) frameFontParam.pack(side=TOP,padx=5,pady=5,fill=X) labelFontNameTitle.pack(side=TOP,anchor=W) @@ -143,7 +151,7 @@ class ConfigDialog(Toplevel): frameFontSample.pack(side=TOP,padx=5,pady=5,expand=TRUE,fill=BOTH) self.labelFontSample.pack(expand=TRUE,fill=BOTH) #frameIndent - frameIndentSize.pack(side=TOP,padx=5,pady=5,fill=BOTH) + frameIndentSize.pack(side=TOP,fill=X) labelSpaceNumTitle.pack(side=TOP,anchor=W,padx=5) self.scaleSpaceNum.pack(side=TOP,padx=5,fill=X) return frame @@ -158,10 +166,12 @@ class ConfigDialog(Toplevel): self.highlightTarget=StringVar(self) ##widget creation #body frame - frame=self.tabPages.pages['Highlighting']['page'] + frame=self.tabPages.pages['Highlighting'].frame #body section frames - frameCustom=Frame(frame,borderwidth=2,relief=GROOVE) - frameTheme=Frame(frame,borderwidth=2,relief=GROOVE) + frameCustom=LabelFrame(frame,borderwidth=2,relief=GROOVE, + text=' Custom Highlighting ') + frameTheme=LabelFrame(frame,borderwidth=2,relief=GROOVE, + text=' Highlighting Theme ') #frameCustom self.textHighlightSample=Text(frameCustom,relief=SOLID,borderwidth=1, font=('courier',12,''),cursor='hand2',width=21,height=10, @@ -189,7 +199,6 @@ class ConfigDialog(Toplevel): text.config(state=DISABLED) self.frameColourSet=Frame(frameCustom,relief=SOLID,borderwidth=1) frameFgBg=Frame(frameCustom) - labelCustomTitle=Label(frameCustom,text='Set Custom Highlighting') buttonSetColour=Button(self.frameColourSet,text='Choose Colour for :', command=self.GetColour,highlightthickness=0) self.optMenuHighlightTarget=DynOptionMenu(self.frameColourSet, @@ -202,7 +211,6 @@ class ConfigDialog(Toplevel): buttonSaveCustomTheme=Button(frameCustom, text='Save as New Custom Theme',command=self.SaveAsNewTheme) #frameTheme - labelThemeTitle=Label(frameTheme,text='Select a Highlighting Theme') labelTypeTitle=Label(frameTheme,text='Select : ') self.radioThemeBuiltin=Radiobutton(frameTheme,variable=self.themeIsBuiltin, value=1,command=self.SetThemeType,text='a Built-in Theme') @@ -216,10 +224,9 @@ class ConfigDialog(Toplevel): command=self.DeleteCustomTheme) ##widget packing #body - frameCustom.pack(side=LEFT,padx=5,pady=10,expand=TRUE,fill=BOTH) - frameTheme.pack(side=LEFT,padx=5,pady=10,fill=Y) + frameCustom.pack(side=LEFT,padx=5,pady=5,expand=TRUE,fill=BOTH) + frameTheme.pack(side=LEFT,padx=5,pady=5,fill=Y) #frameCustom - labelCustomTitle.pack(side=TOP,anchor=W,padx=5,pady=5) self.frameColourSet.pack(side=TOP,padx=5,pady=5,expand=TRUE,fill=X) frameFgBg.pack(side=TOP,padx=5,pady=0) self.textHighlightSample.pack(side=TOP,padx=5,pady=5,expand=TRUE, @@ -230,7 +237,6 @@ class ConfigDialog(Toplevel): self.radioBg.pack(side=RIGHT,anchor=W) buttonSaveCustomTheme.pack(side=BOTTOM,fill=X,padx=5,pady=5) #frameTheme - labelThemeTitle.pack(side=TOP,anchor=W,padx=5,pady=5) labelTypeTitle.pack(side=TOP,anchor=W,padx=5,pady=5) self.radioThemeBuiltin.pack(side=TOP,anchor=W,padx=5) self.radioThemeCustom.pack(side=TOP,anchor=W,padx=5,pady=2) @@ -248,13 +254,14 @@ class ConfigDialog(Toplevel): self.keyBinding=StringVar(self) ##widget creation #body frame - frame=self.tabPages.pages['Keys']['page'] + frame=self.tabPages.pages['Keys'].frame #body section frames - frameCustom=Frame(frame,borderwidth=2,relief=GROOVE) - frameKeySets=Frame(frame,borderwidth=2,relief=GROOVE) + frameCustom=LabelFrame(frame,borderwidth=2,relief=GROOVE, + text=' Custom Key Bindings ') + frameKeySets=LabelFrame(frame,borderwidth=2,relief=GROOVE, + text=' Key Set ') #frameCustom frameTarget=Frame(frameCustom) - labelCustomTitle=Label(frameCustom,text='Set Custom Key Bindings') labelTargetTitle=Label(frameTarget,text='Action - Key(s)') scrollTargetY=Scrollbar(frameTarget) scrollTargetX=Scrollbar(frameTarget,orient=HORIZONTAL) @@ -270,7 +277,6 @@ class ConfigDialog(Toplevel): buttonSaveCustomKeys=Button(frameCustom, text='Save as New Custom Key Set',command=self.SaveAsNewKeySet) #frameKeySets - labelKeysTitle=Label(frameKeySets,text='Select a Key Set') labelTypeTitle=Label(frameKeySets,text='Select : ') self.radioKeysBuiltin=Radiobutton(frameKeySets,variable=self.keysAreBuiltin, value=1,command=self.SetKeysType,text='a Built-in Key Set') @@ -287,7 +293,6 @@ class ConfigDialog(Toplevel): frameCustom.pack(side=LEFT,padx=5,pady=5,expand=TRUE,fill=BOTH) frameKeySets.pack(side=LEFT,padx=5,pady=5,fill=Y) #frameCustom - labelCustomTitle.pack(side=TOP,anchor=W,padx=5,pady=5) buttonSaveCustomKeys.pack(side=BOTTOM,fill=X,padx=5,pady=5) self.buttonNewKeys.pack(side=BOTTOM,fill=X,padx=5,pady=5) frameTarget.pack(side=LEFT,padx=5,pady=5,expand=TRUE,fill=BOTH) @@ -299,7 +304,6 @@ class ConfigDialog(Toplevel): scrollTargetY.grid(row=1,column=1,sticky=NS) scrollTargetX.grid(row=2,column=0,sticky=EW) #frameKeySets - labelKeysTitle.pack(side=TOP,anchor=W,padx=5,pady=5) labelTypeTitle.pack(side=TOP,anchor=W,padx=5,pady=5) self.radioKeysBuiltin.pack(side=TOP,anchor=W,padx=5) self.radioKeysCustom.pack(side=TOP,anchor=W,padx=5,pady=2) @@ -320,23 +324,24 @@ class ConfigDialog(Toplevel): self.helpBrowser=StringVar(self) #widget creation #body - frame=self.tabPages.pages['General']['page'] + frame=self.tabPages.pages['General'].frame #body section frames - frameRun=Frame(frame,borderwidth=2,relief=GROOVE) - frameSave=Frame(frame,borderwidth=2,relief=GROOVE) + frameRun=LabelFrame(frame,borderwidth=2,relief=GROOVE, + text=' Startup Preferences ') + frameSave=LabelFrame(frame,borderwidth=2,relief=GROOVE, + text=' Autosave Preferences ') frameWinSize=Frame(frame,borderwidth=2,relief=GROOVE) frameParaSize=Frame(frame,borderwidth=2,relief=GROOVE) frameEncoding=Frame(frame,borderwidth=2,relief=GROOVE) - frameHelp=Frame(frame,borderwidth=2,relief=GROOVE) + frameHelp=LabelFrame(frame,borderwidth=2,relief=GROOVE, + text=' Additional Help Sources ') #frameRun - labelRunTitle=Label(frameRun,text='Startup Preferences') labelRunChoiceTitle=Label(frameRun,text='At Startup') radioStartupEdit=Radiobutton(frameRun,variable=self.startupEdit, value=1,command=self.SetKeysType,text="Open Edit Window") radioStartupShell=Radiobutton(frameRun,variable=self.startupEdit, value=0,command=self.SetKeysType,text='Open Shell Window') #frameSave - labelSaveTitle=Label(frameSave,text='Autosave Preference') labelRunSaveTitle=Label(frameSave,text='At Start of Run (F5) ') radioSaveAsk=Radiobutton(frameSave,variable=self.autoSave, value=0,command=self.SetKeysType,text="Prompt to Save") @@ -367,7 +372,6 @@ class ConfigDialog(Toplevel): #frameHelp frameHelpList=Frame(frameHelp) frameHelpListButtons=Frame(frameHelpList) - labelHelpListTitle=Label(frameHelpList,text='Additional Help Sources:') scrollHelpList=Scrollbar(frameHelpList) self.listHelp=Listbox(frameHelpList,height=5,takefocus=FALSE, exportselection=FALSE) @@ -389,12 +393,10 @@ class ConfigDialog(Toplevel): frameEncoding.pack(side=TOP,padx=5,pady=5,fill=X) frameHelp.pack(side=TOP,padx=5,pady=5,expand=TRUE,fill=BOTH) #frameRun - labelRunTitle.pack(side=TOP,anchor=W,padx=5,pady=5) labelRunChoiceTitle.pack(side=LEFT,anchor=W,padx=5,pady=5) radioStartupShell.pack(side=RIGHT,anchor=W,padx=5,pady=5) radioStartupEdit.pack(side=RIGHT,anchor=W,padx=5,pady=5) #frameSave - labelSaveTitle.pack(side=TOP,anchor=W,padx=5,pady=5) labelRunSaveTitle.pack(side=LEFT,anchor=W,padx=5,pady=5) radioSaveAuto.pack(side=RIGHT,anchor=W,padx=5,pady=5) radioSaveAsk.pack(side=RIGHT,anchor=W,padx=5,pady=5) @@ -415,7 +417,6 @@ class ConfigDialog(Toplevel): #frameHelp frameHelpListButtons.pack(side=RIGHT,padx=5,pady=5,fill=Y) frameHelpList.pack(side=TOP,padx=5,pady=5,expand=TRUE,fill=BOTH) - labelHelpListTitle.pack(side=TOP,anchor=W) scrollHelpList.pack(side=RIGHT,anchor=W,fill=Y) self.listHelp.pack(side=LEFT,anchor=E,expand=TRUE,fill=BOTH) self.buttonHelpListEdit.pack(side=TOP,anchor=W,pady=5) @@ -1116,12 +1117,15 @@ class ConfigDialog(Toplevel): def ActivateConfigChanges(self): "Dynamically apply configuration changes" winInstances = self.parent.instance_dict.keys() + theme = idleConf.CurrentTheme() + cursor_color = idleConf.GetHighlight(theme, 'cursor', fgBg='fg') for instance in winInstances: instance.ResetColorizer() instance.ResetFont() instance.set_notabs_indentwidth() instance.ApplyKeybindings() instance.reset_help_menu_entries() + instance.text.configure(insertbackground=cursor_color) def Cancel(self): self.destroy() diff --git a/Lib/idlelib/run.py b/Lib/idlelib/run.py index 4ba5198..9fbe0e9 100644 --- a/Lib/idlelib/run.py +++ b/Lib/idlelib/run.py @@ -38,10 +38,11 @@ else: # Thread shared globals: Establish a queue between a subthread (which handles # the socket) and the main thread (which runs user code), plus global -# completion and exit flags: +# completion, exit and interruptable (the main thread) flags: exit_now = False quitting = False +interruptable = False def main(del_exitfunc=False): """Start the Python execution server in a subprocess @@ -278,9 +279,14 @@ class Executive(object): self.autocomplete = AutoComplete.AutoComplete() def runcode(self, code): + global interruptable try: self.usr_exc_info = None - exec(code, self.locals) + interruptable = True + try: + exec(code, self.locals) + finally: + interruptable = False except: self.usr_exc_info = sys.exc_info() if quitting: @@ -294,7 +300,8 @@ class Executive(object): flush_stdout() def interrupt_the_server(self): - thread.interrupt_main() + if interruptable: + thread.interrupt_main() def start_the_debugger(self, gui_adap_oid): return RemoteDebugger.start_debugger(self.rpchandler, gui_adap_oid) diff --git a/Lib/idlelib/tabbedpages.py b/Lib/idlelib/tabbedpages.py new file mode 100644 index 0000000..98f6a27 --- /dev/null +++ b/Lib/idlelib/tabbedpages.py @@ -0,0 +1,478 @@ +"""An implementation of tabbed pages using only standard Tkinter. + +Originally developed for use in IDLE. Based on tabpage.py. + +Classes exported: +TabbedPageSet -- A Tkinter implementation of a tabbed-page widget. +TabBarSet -- A widget containing tabs (buttons) in one or more rows. + +""" +from Tkinter import * + +class InvalidNameError(Exception): pass +class AlreadyExistsError(Exception): pass + + +class TabBarSet(Frame): + """A widget containing tabs (buttons) in one or more rows. + + Only one tab may be selected at a time. + + """ + def __init__(self, page_set, select_command, + tabs=None, n_rows=1, max_tabs_per_row=5, + expand_tabs=False, **kw): + """Constructor arguments: + + select_command -- A callable which will be called when a tab is + selected. It is called with the name of the selected tab as an + argument. + + tabs -- A list of strings, the names of the tabs. Should be specified in + the desired tab order. The first tab will be the default and first + active tab. If tabs is None or empty, the TabBarSet will be initialized + empty. + + n_rows -- Number of rows of tabs to be shown. If n_rows <= 0 or is + None, then the number of rows will be decided by TabBarSet. See + _arrange_tabs() for details. + + max_tabs_per_row -- Used for deciding how many rows of tabs are needed, + when the number of rows is not constant. See _arrange_tabs() for + details. + + """ + Frame.__init__(self, page_set, **kw) + self.select_command = select_command + self.n_rows = n_rows + self.max_tabs_per_row = max_tabs_per_row + self.expand_tabs = expand_tabs + self.page_set = page_set + + self._tabs = {} + self._tab2row = {} + if tabs: + self._tab_names = list(tabs) + else: + self._tab_names = [] + self._selected_tab = None + self._tab_rows = [] + + self.padding_frame = Frame(self, height=2, + borderwidth=0, relief=FLAT, + background=self.cget('background')) + self.padding_frame.pack(side=TOP, fill=X, expand=False) + + self._arrange_tabs() + + def add_tab(self, tab_name): + """Add a new tab with the name given in tab_name.""" + if not tab_name: + raise InvalidNameError("Invalid Tab name: '%s'" % tab_name) + if tab_name in self._tab_names: + raise AlreadyExistsError("Tab named '%s' already exists" %tab_name) + + self._tab_names.append(tab_name) + self._arrange_tabs() + + def remove_tab(self, tab_name): + """Remove the tab with the name given in tab_name.""" + if not tab_name in self._tab_names: + raise KeyError("No such Tab: '%s" % page_name) + + self._tab_names.remove(tab_name) + self._arrange_tabs() + + def select_tab(self, tab_name): + """Select the tab with the name given in tab_name.""" + if tab_name == self._selected_tab: + return + if tab_name is not None and tab_name not in self._tabs: + raise KeyError("No such Tab: '%s" % page_name) + + # deselect the current selected tab + if self._selected_tab is not None: + self._tabs[self._selected_tab].set_normal() + self._selected_tab = None + + if tab_name is not None: + # activate the tab named tab_name + self._selected_tab = tab_name + tab = self._tabs[tab_name] + tab.set_selected() + # move the tab row with the selected tab to the bottom + tab_row = self._tab2row[tab] + tab_row.pack_forget() + tab_row.pack(side=TOP, fill=X, expand=0) + + def _add_tab_row(self, tab_names, expand_tabs): + if not tab_names: + return + + tab_row = Frame(self) + tab_row.pack(side=TOP, fill=X, expand=0) + tab_row.tab_set = self + self._tab_rows.append(tab_row) + + for tab_name in tab_names: + def tab_command(select_command=self.select_command, + tab_name=tab_name): + return select_command(tab_name) + tab = TabBarSet.TabButton(tab_row, tab_name, tab_command) + if expand_tabs: + tab.pack(side=LEFT, fill=X, expand=True) + else: + tab.pack(side=LEFT) + self._tabs[tab_name] = tab + self._tab2row[tab] = tab_row + + tab.is_last_in_row = True + + def _reset_tab_rows(self): + while self._tab_rows: + tab_row = self._tab_rows.pop() + tab_row.destroy() + self._tab2row = {} + + def _arrange_tabs(self): + """ + Arrange the tabs in rows, in the order in which they were added. + + If n_rows >= 1, this will be the number of rows used. Otherwise the + number of rows will be calculated according to the number of tabs and + max_tabs_per_row. In this case, the number of rows may change when + adding/removing tabs. + + """ + # remove all tabs and rows + for tab_name in self._tabs.keys(): + self._tabs.pop(tab_name).destroy() + self._reset_tab_rows() + + if not self._tab_names: + return + + if self.n_rows is not None and self.n_rows > 0: + n_rows = self.n_rows + else: + # calculate the required number of rows + n_rows = (len(self._tab_names) - 1) // self.max_tabs_per_row + 1 + + i = 0 + expand_tabs = self.expand_tabs or n_rows > 1 + for row_index in xrange(n_rows): + # calculate required number of tabs in this row + n_tabs = (len(self._tab_names) - i - 1) // (n_rows - row_index) + 1 + tab_names = self._tab_names[i:i + n_tabs] + i += n_tabs + self._add_tab_row(tab_names, expand_tabs) + + # re-select selected tab so it is properly displayed + selected = self._selected_tab + self.select_tab(None) + if selected in self._tab_names: + self.select_tab(selected) + + class TabButton(Frame): + """A simple tab-like widget.""" + + bw = 2 # borderwidth + + def __init__(self, tab_row, name, command): + """Constructor arguments: + + name -- The tab's name, which will appear in its button. + + command -- The command to be called upon selection of the tab. It + is called with the tab's name as an argument. + + """ + Frame.__init__(self, tab_row, borderwidth=self.bw) + self.button = Radiobutton(self, text=name, command=command, + padx=5, pady=1, takefocus=FALSE, indicatoron=FALSE, + highlightthickness=0, selectcolor='', borderwidth=0) + self.button.pack(side=LEFT, fill=X, expand=True) + + self.tab_set = tab_row.tab_set + + self.is_last_in_row = False + + self._init_masks() + self.set_normal() + + def set_selected(self): + """Assume selected look""" + for widget in self, self.mskl.ml, self.mskr.mr: + widget.config(relief=RAISED) + self._place_masks(selected=True) + + def set_normal(self): + """Assume normal look""" + for widget in self, self.mskl.ml, self.mskr.mr: + widget.config(relief=RAISED) + self._place_masks(selected=False) + + def _init_masks(self): + page_set = self.tab_set.page_set + background = page_set.pages_frame.cget('background') + # mask replaces the middle of the border with the background color + self.mask = Frame(page_set, borderwidth=0, relief=FLAT, + background=background) + # mskl replaces the bottom-left corner of the border with a normal + # left border + self.mskl = Frame(page_set, borderwidth=0, relief=FLAT, + background=background) + self.mskl.ml = Frame(self.mskl, borderwidth=self.bw, + relief=RAISED) + self.mskl.ml.place(x=0, y=-self.bw, + width=2*self.bw, height=self.bw*4) + # mskr replaces the bottom-right corner of the border with a normal + # right border + self.mskr = Frame(page_set, borderwidth=0, relief=FLAT, + background=background) + self.mskr.mr = Frame(self.mskr, borderwidth=self.bw, + relief=RAISED) + + def _place_masks(self, selected=False): + height = self.bw + if selected: + height += self.bw + + self.mask.place(in_=self, + relx=0.0, x=0, + rely=1.0, y=0, + relwidth=1.0, width=0, + relheight=0.0, height=height) + + self.mskl.place(in_=self, + relx=0.0, x=-self.bw, + rely=1.0, y=0, + relwidth=0.0, width=self.bw, + relheight=0.0, height=height) + + page_set = self.tab_set.page_set + if selected and ((not self.is_last_in_row) or + (self.winfo_rootx() + self.winfo_width() < + page_set.winfo_rootx() + page_set.winfo_width()) + ): + # for a selected tab, if its rightmost edge isn't on the + # rightmost edge of the page set, the right mask should be one + # borderwidth shorter (vertically) + height -= self.bw + + self.mskr.place(in_=self, + relx=1.0, x=0, + rely=1.0, y=0, + relwidth=0.0, width=self.bw, + relheight=0.0, height=height) + + self.mskr.mr.place(x=-self.bw, y=-self.bw, + width=2*self.bw, height=height + self.bw*2) + + # finally, lower the tab set so that all of the frames we just + # placed hide it + self.tab_set.lower() + +class TabbedPageSet(Frame): + """A Tkinter tabbed-pane widget. + + Constains set of 'pages' (or 'panes') with tabs above for selecting which + page is displayed. Only one page will be displayed at a time. + + Pages may be accessed through the 'pages' attribute, which is a dictionary + of pages, using the name given as the key. A page is an instance of a + subclass of Tk's Frame widget. + + The page widgets will be created (and destroyed when required) by the + TabbedPageSet. Do not call the page's pack/place/grid/destroy methods. + + Pages may be added or removed at any time using the add_page() and + remove_page() methods. + + """ + class Page(object): + """Abstract base class for TabbedPageSet's pages. + + Subclasses must override the _show() and _hide() methods. + + """ + uses_grid = False + + def __init__(self, page_set): + self.frame = Frame(page_set, borderwidth=2, relief=RAISED) + + def _show(self): + raise NotImplementedError + + def _hide(self): + raise NotImplementedError + + class PageRemove(Page): + """Page class using the grid placement manager's "remove" mechanism.""" + uses_grid = True + + def _show(self): + self.frame.grid(row=0, column=0, sticky=NSEW) + + def _hide(self): + self.frame.grid_remove() + + class PageLift(Page): + """Page class using the grid placement manager's "lift" mechanism.""" + uses_grid = True + + def __init__(self, page_set): + super(TabbedPageSet.PageLift, self).__init__(page_set) + self.frame.grid(row=0, column=0, sticky=NSEW) + self.frame.lower() + + def _show(self): + self.frame.lift() + + def _hide(self): + self.frame.lower() + + class PagePackForget(Page): + """Page class using the pack placement manager's "forget" mechanism.""" + def _show(self): + self.frame.pack(fill=BOTH, expand=True) + + def _hide(self): + self.frame.pack_forget() + + def __init__(self, parent, page_names=None, page_class=PageLift, + n_rows=1, max_tabs_per_row=5, expand_tabs=False, + **kw): + """Constructor arguments: + + page_names -- A list of strings, each will be the dictionary key to a + page's widget, and the name displayed on the page's tab. Should be + specified in the desired page order. The first page will be the default + and first active page. If page_names is None or empty, the + TabbedPageSet will be initialized empty. + + n_rows, max_tabs_per_row -- Parameters for the TabBarSet which will + manage the tabs. See TabBarSet's docs for details. + + page_class -- Pages can be shown/hidden using three mechanisms: + + * PageLift - All pages will be rendered one on top of the other. When + a page is selected, it will be brought to the top, thus hiding all + other pages. Using this method, the TabbedPageSet will not be resized + when pages are switched. (It may still be resized when pages are + added/removed.) + + * PageRemove - When a page is selected, the currently showing page is + hidden, and the new page shown in its place. Using this method, the + TabbedPageSet may resize when pages are changed. + + * PagePackForget - This mechanism uses the pack placement manager. + When a page is shown it is packed, and when it is hidden it is + unpacked (i.e. pack_forget). This mechanism may also cause the + TabbedPageSet to resize when the page is changed. + + """ + Frame.__init__(self, parent, kw) + + self.page_class = page_class + self.pages = {} + self._pages_order = [] + self._current_page = None + self._default_page = None + + self.columnconfigure(0, weight=1) + self.rowconfigure(1, weight=1) + + self.pages_frame = Frame(self) + self.pages_frame.grid(row=1, column=0, sticky=NSEW) + if self.page_class.uses_grid: + self.pages_frame.columnconfigure(0, weight=1) + self.pages_frame.rowconfigure(0, weight=1) + + # the order of the following commands is important + self._tab_set = TabBarSet(self, self.change_page, n_rows=n_rows, + max_tabs_per_row=max_tabs_per_row, + expand_tabs=expand_tabs) + if page_names: + for name in page_names: + self.add_page(name) + self._tab_set.grid(row=0, column=0, sticky=NSEW) + + self.change_page(self._default_page) + + def add_page(self, page_name): + """Add a new page with the name given in page_name.""" + if not page_name: + raise InvalidNameError("Invalid TabPage name: '%s'" % page_name) + if page_name in self.pages: + raise AlreadyExistsError( + "TabPage named '%s' already exists" % page_name) + + self.pages[page_name] = self.page_class(self.pages_frame) + self._pages_order.append(page_name) + self._tab_set.add_tab(page_name) + + if len(self.pages) == 1: # adding first page + self._default_page = page_name + self.change_page(page_name) + + def remove_page(self, page_name): + """Destroy the page whose name is given in page_name.""" + if not page_name in self.pages: + raise KeyError("No such TabPage: '%s" % page_name) + + self._pages_order.remove(page_name) + + # handle removing last remaining, default, or currently shown page + if len(self._pages_order) > 0: + if page_name == self._default_page: + # set a new default page + self._default_page = self._pages_order[0] + else: + self._default_page = None + + if page_name == self._current_page: + self.change_page(self._default_page) + + self._tab_set.remove_tab(page_name) + page = self.pages.pop(page_name) + page.frame.destroy() + + def change_page(self, page_name): + """Show the page whose name is given in page_name.""" + if self._current_page == page_name: + return + if page_name is not None and page_name not in self.pages: + raise KeyError("No such TabPage: '%s'" % page_name) + + if self._current_page is not None: + self.pages[self._current_page]._hide() + self._current_page = None + + if page_name is not None: + self._current_page = page_name + self.pages[page_name]._show() + + self._tab_set.select_tab(page_name) + +if __name__ == '__main__': + # test dialog + root=Tk() + tabPage=TabbedPageSet(root, page_names=['Foobar','Baz'], n_rows=0, + expand_tabs=False, + ) + tabPage.pack(side=TOP, expand=TRUE, fill=BOTH) + Label(tabPage.pages['Foobar'].frame, text='Foo', pady=20).pack() + Label(tabPage.pages['Foobar'].frame, text='Bar', pady=20).pack() + Label(tabPage.pages['Baz'].frame, text='Baz').pack() + entryPgName=Entry(root) + buttonAdd=Button(root, text='Add Page', + command=lambda:tabPage.add_page(entryPgName.get())) + buttonRemove=Button(root, text='Remove Page', + command=lambda:tabPage.remove_page(entryPgName.get())) + labelPgName=Label(root, text='name of page to add/remove:') + buttonAdd.pack(padx=5, pady=5) + buttonRemove.pack(padx=5, pady=5) + labelPgName.pack(padx=5) + entryPgName.pack(padx=5) + root.mainloop() diff --git a/Lib/idlelib/textView.py b/Lib/idlelib/textView.py index 917a6cc..0e7e663 100644 --- a/Lib/idlelib/textView.py +++ b/Lib/idlelib/textView.py @@ -6,13 +6,12 @@ from Tkinter import * import tkMessageBox class TextViewer(Toplevel): + """A simple text viewer dialog for IDLE + """ - simple text viewer dialog for idle - """ - def __init__(self, parent, title, fileName, data=None): - """If data exists, load it into viewer, otherwise try to load file. + def __init__(self, parent, title, text): + """Show the given text in a scrollable window with a 'close' button - fileName - string, should be an absoulute filename """ Toplevel.__init__(self, parent) self.configure(borderwidth=5) @@ -33,23 +32,10 @@ class TextViewer(Toplevel): #key bindings for this dialog self.bind('<Return>',self.Ok) #dismiss dialog self.bind('<Escape>',self.Ok) #dismiss dialog - if data: - self.textView.insert(0.0, data) - else: - self.LoadTextFile(fileName) + self.textView.insert(0.0, text) self.textView.config(state=DISABLED) self.wait_window() - def LoadTextFile(self, fileName): - textFile = None - try: - textFile = open(fileName, 'r') - except IOError: - tkMessageBox.showerror(title='File Load Error', - message='Unable to load file %r .' % (fileName,)) - else: - self.textView.insert(0.0,textFile.read()) - def CreateWidgets(self): frameText = Frame(self, relief=SUNKEN, height=700) frameButtons = Frame(self) @@ -70,9 +56,38 @@ class TextViewer(Toplevel): def Ok(self, event=None): self.destroy() + +def view_text(parent, title, text): + TextViewer(parent, title, text) + +def view_file(parent, title, filename, encoding=None): + try: + if encoding: + import codecs + textFile = codecs.open(filename, 'r') + else: + textFile = open(filename, 'r') + except IOError: + import tkMessageBox + tkMessageBox.showerror(title='File Load Error', + message='Unable to load file %r .' % filename, + parent=parent) + else: + return view_text(parent, title, textFile.read()) + + if __name__ == '__main__': #test the dialog root=Tk() - Button(root,text='View', - command=lambda:TextViewer(root,'Text','./textView.py')).pack() + root.title('textView test') + filename = './textView.py' + text = file(filename, 'r').read() + btn1 = Button(root, text='view_text', + command=lambda:view_text(root, 'view_text', text)) + btn1.pack(side=LEFT) + btn2 = Button(root, text='view_file', + command=lambda:view_file(root, 'view_file', filename)) + btn2.pack(side=LEFT) + close = Button(root, text='Close', command=root.destroy) + close.pack(side=RIGHT) root.mainloop() |