]> granicus.if.org Git - python/commitdiff
Issue #3965: Allow repeated calls to turtle.Screen, by making it a
authorMartin v. Löwis <martin@v.loewis.de>
Mon, 29 Sep 2008 22:09:07 +0000 (22:09 +0000)
committerMartin v. Löwis <martin@v.loewis.de>
Mon, 29 Sep 2008 22:09:07 +0000 (22:09 +0000)
true singleton object.

Reviewed by Gregor Lingl.

Demo/turtle/turtleDemo.py
Doc/library/turtle.rst
Lib/lib-tk/turtle.py
Misc/NEWS

index 245eaa71c1193261346b0ec0ce5d61e871d6bad1..5e744efe469ae05543056353a1e98ca3cd07dbe3 100644 (file)
@@ -94,8 +94,8 @@ class DemoWindow(object):
         left_frame.pack(side=LEFT, fill=BOTH, expand=0)
         self.graph_frame = g_frame = Frame(root)
 
-        turtle.Screen._root = g_frame
-        turtle.Screen._canvas = turtle.ScrolledCanvas(g_frame, 800, 600, 1000, 800)
+        turtle._Screen._root = g_frame
+        turtle._Screen._canvas = turtle.ScrolledCanvas(g_frame, 800, 600, 1000, 800)
         #xturtle.Screen._canvas.pack(expand=1, fill="both")
         self.screen = _s_ = turtle.Screen()
         self.scanvas = _s_._canvas
index 67064d186aa175995755d19ac52e55aa291f2481..5f9bf184958bfa6117c4661eec00e5095718ad44 100644 (file)
@@ -40,10 +40,10 @@ The object-oriented interface uses essentially two+two classes:
    :class:`ScrolledCanvas` as argument.  It should be used when :mod:`turtle` is
    used as part of some application.
 
-   Derived from :class:`TurtleScreen` is the subclass :class:`Screen`.  Screen
-   is implemented as sort of singleton, so there can exist only one instance of
-   Screen at a time.  It should be used when :mod:`turtle` is used as a
-   standalone tool for doing graphics.
+   The function :func:`Screen` returns a singleton object of a
+   :class:`TurtleScreen` subclass. This function should be used when
+   :mod:`turtle` is used as a standalone tool for doing graphics.
+   As a singleton object, inheriting from its class is not possible.
 
    All methods of TurtleScreen/Screen also exist as functions, i.e. as part of
    the procedure-oriented interface.
index cd6dbe831fe62d3fbf0f7327b1c44f1576292938..001b210f98c2e37a062c9c40eb360e47178f00ce 100644 (file)
@@ -2422,7 +2422,7 @@ class RawTurtle(TPen, TNavigator):
                  shape=_CFG["shape"],
                  undobuffersize=_CFG["undobuffersize"],
                  visible=_CFG["visible"]):
-        if isinstance(canvas, Screen):
+        if isinstance(canvas, _Screen):
             self.screen = canvas
         elif isinstance(canvas, TurtleScreen):
             if canvas not in RawTurtle.screens:
@@ -3539,29 +3539,33 @@ class RawTurtle(TPen, TNavigator):
 
 RawPen = RawTurtle
 
-###  Screen - Klasse  ########################
+###  Screen - Singleton  ########################
 
-class Screen(TurtleScreen):
+def Screen():
+    """Return the singleton screen object.
+    If none exists at the moment, create a new one and return it,
+    else return the existing one."""
+    if Turtle._screen is None:
+        Turtle._screen = _Screen()
+    return Turtle._screen
+
+class _Screen(TurtleScreen):
 
     _root = None
     _canvas = None
     _title = _CFG["title"]
 
-    # Borg-Idiom
-
-    _shared_state = {}
-
-    def __new__(cls, *args, **kwargs):
-        obj = object.__new__(cls, *args, **kwargs)
-        obj.__dict__ = cls._shared_state
-        return obj
-
     def __init__(self):
-        if Screen._root is None:
-            Screen._root = self._root = _Root()
-            self._root.title(Screen._title)
+        # XXX there is no need for this code to be conditional,
+        # as there will be only a single _Screen instance, anyway
+        # XXX actually, the turtle demo is injecting root window,
+        # so perhaps the conditional creation of a root should be
+        # preserved (perhaps by passing it as an optional parameter)
+        if _Screen._root is None:
+            _Screen._root = self._root = _Root()
+            self._root.title(_Screen._title)
             self._root.ondestroy(self._destroy)
-        if Screen._canvas is None:
+        if _Screen._canvas is None:
             width = _CFG["width"]
             height = _CFG["height"]
             canvwidth = _CFG["canvwidth"]
@@ -3569,10 +3573,9 @@ class Screen(TurtleScreen):
             leftright = _CFG["leftright"]
             topbottom = _CFG["topbottom"]
             self._root.setupcanvas(width, height, canvwidth, canvheight)
-            Screen._canvas = self._root._getcanvas()
+            _Screen._canvas = self._root._getcanvas()
             self.setup(width, height, leftright, topbottom)
-        TurtleScreen.__init__(self, Screen._canvas)
-        Turtle._screen = self
+        TurtleScreen.__init__(self, _Screen._canvas)
 
     def setup(self, width=_CFG["width"], height=_CFG["height"],
               startx=_CFG["leftright"], starty=_CFG["topbottom"]):
@@ -3626,17 +3629,17 @@ class Screen(TurtleScreen):
         Example (for a Screen instance named screen):
         >>> screen.title("Welcome to the turtle-zoo!")
         """
-        if Screen._root is not None:
-            Screen._root.title(titlestring)
-        Screen._title = titlestring
+        if _Screen._root is not None:
+            _Screen._root.title(titlestring)
+        _Screen._title = titlestring
 
     def _destroy(self):
         root = self._root
-        if root is Screen._root:
+        if root is _Screen._root:
             Turtle._pen = None
             Turtle._screen = None
-            Screen._root = None
-            Screen._canvas = None
+            _Screen._root = None
+            _Screen._canvas = None
         TurtleScreen._RUNNING = True
         root.destroy()
 
@@ -3728,7 +3731,7 @@ def write_docstringdict(filename="turtle_docstringdict"):
     docsdict = {}
 
     for methodname in _tg_screen_functions:
-        key = "Screen."+methodname
+        key = "_Screen."+methodname
         docsdict[key] = eval(key).__doc__
     for methodname in _tg_turtle_functions:
         key = "Turtle."+methodname
@@ -3842,14 +3845,14 @@ def _screen_docrevise(docstr):
 
 
 for methodname in _tg_screen_functions:
-    pl1, pl2 = getmethparlist(eval('Screen.' + methodname))
+    pl1, pl2 = getmethparlist(eval('_Screen.' + methodname))
     if pl1 == "":
         print ">>>>>>", pl1, pl2
         continue
     defstr = ("def %(key)s%(pl1)s: return _getscreen().%(key)s%(pl2)s" %
                                    {'key':methodname, 'pl1':pl1, 'pl2':pl2})
     exec defstr
-    eval(methodname).__doc__ = _screen_docrevise(eval('Screen.'+methodname).__doc__)
+    eval(methodname).__doc__ = _screen_docrevise(eval('_Screen.'+methodname).__doc__)
 
 for methodname in _tg_turtle_functions:
     pl1, pl2 = getmethparlist(eval('Turtle.' + methodname))
index 466160f67ee84bd068bfde05dcf80e996b5cc7b0..bbbeb91da1128d30317da661da4850df813f7d57 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -23,6 +23,9 @@ Core and Builtins
 Library
 -------
 
+- Issue #3965: Allow repeated calls to turtle.Screen, by making it a
+  true singleton object.
+
 - Issue #3895: It was possible to crash the interpreter when an external timer
   was used with cProfile that returned an object that could not be converted
   into a float.