mirror of https://github.com/python/cpython
Issue #3965: Allow repeated calls to turtle.Screen, by making it a
true singleton object. Reviewed by Gregor Lingl.
This commit is contained in:
parent
e144873071
commit
e563aa4383
|
@ -94,8 +94,8 @@ class DemoWindow(object):
|
||||||
left_frame.pack(side=LEFT, fill=BOTH, expand=0)
|
left_frame.pack(side=LEFT, fill=BOTH, expand=0)
|
||||||
self.graph_frame = g_frame = Frame(root)
|
self.graph_frame = g_frame = Frame(root)
|
||||||
|
|
||||||
turtle.Screen._root = g_frame
|
turtle._Screen._root = g_frame
|
||||||
turtle.Screen._canvas = turtle.ScrolledCanvas(g_frame, 800, 600, 1000, 800)
|
turtle._Screen._canvas = turtle.ScrolledCanvas(g_frame, 800, 600, 1000, 800)
|
||||||
#xturtle.Screen._canvas.pack(expand=1, fill="both")
|
#xturtle.Screen._canvas.pack(expand=1, fill="both")
|
||||||
self.screen = _s_ = turtle.Screen()
|
self.screen = _s_ = turtle.Screen()
|
||||||
self.scanvas = _s_._canvas
|
self.scanvas = _s_._canvas
|
||||||
|
|
|
@ -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
|
:class:`ScrolledCanvas` as argument. It should be used when :mod:`turtle` is
|
||||||
used as part of some application.
|
used as part of some application.
|
||||||
|
|
||||||
Derived from :class:`TurtleScreen` is the subclass :class:`Screen`. Screen
|
The function :func:`Screen` returns a singleton object of a
|
||||||
is implemented as sort of singleton, so there can exist only one instance of
|
:class:`TurtleScreen` subclass. This function should be used when
|
||||||
Screen at a time. It should be used when :mod:`turtle` is used as a
|
:mod:`turtle` is used as a standalone tool for doing graphics.
|
||||||
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
|
All methods of TurtleScreen/Screen also exist as functions, i.e. as part of
|
||||||
the procedure-oriented interface.
|
the procedure-oriented interface.
|
||||||
|
|
|
@ -2422,7 +2422,7 @@ class RawTurtle(TPen, TNavigator):
|
||||||
shape=_CFG["shape"],
|
shape=_CFG["shape"],
|
||||||
undobuffersize=_CFG["undobuffersize"],
|
undobuffersize=_CFG["undobuffersize"],
|
||||||
visible=_CFG["visible"]):
|
visible=_CFG["visible"]):
|
||||||
if isinstance(canvas, Screen):
|
if isinstance(canvas, _Screen):
|
||||||
self.screen = canvas
|
self.screen = canvas
|
||||||
elif isinstance(canvas, TurtleScreen):
|
elif isinstance(canvas, TurtleScreen):
|
||||||
if canvas not in RawTurtle.screens:
|
if canvas not in RawTurtle.screens:
|
||||||
|
@ -3539,29 +3539,33 @@ class RawTurtle(TPen, TNavigator):
|
||||||
|
|
||||||
RawPen = RawTurtle
|
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
|
_root = None
|
||||||
_canvas = None
|
_canvas = None
|
||||||
_title = _CFG["title"]
|
_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):
|
def __init__(self):
|
||||||
if Screen._root is None:
|
# XXX there is no need for this code to be conditional,
|
||||||
Screen._root = self._root = _Root()
|
# as there will be only a single _Screen instance, anyway
|
||||||
self._root.title(Screen._title)
|
# 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)
|
self._root.ondestroy(self._destroy)
|
||||||
if Screen._canvas is None:
|
if _Screen._canvas is None:
|
||||||
width = _CFG["width"]
|
width = _CFG["width"]
|
||||||
height = _CFG["height"]
|
height = _CFG["height"]
|
||||||
canvwidth = _CFG["canvwidth"]
|
canvwidth = _CFG["canvwidth"]
|
||||||
|
@ -3569,10 +3573,9 @@ class Screen(TurtleScreen):
|
||||||
leftright = _CFG["leftright"]
|
leftright = _CFG["leftright"]
|
||||||
topbottom = _CFG["topbottom"]
|
topbottom = _CFG["topbottom"]
|
||||||
self._root.setupcanvas(width, height, canvwidth, canvheight)
|
self._root.setupcanvas(width, height, canvwidth, canvheight)
|
||||||
Screen._canvas = self._root._getcanvas()
|
_Screen._canvas = self._root._getcanvas()
|
||||||
self.setup(width, height, leftright, topbottom)
|
self.setup(width, height, leftright, topbottom)
|
||||||
TurtleScreen.__init__(self, Screen._canvas)
|
TurtleScreen.__init__(self, _Screen._canvas)
|
||||||
Turtle._screen = self
|
|
||||||
|
|
||||||
def setup(self, width=_CFG["width"], height=_CFG["height"],
|
def setup(self, width=_CFG["width"], height=_CFG["height"],
|
||||||
startx=_CFG["leftright"], starty=_CFG["topbottom"]):
|
startx=_CFG["leftright"], starty=_CFG["topbottom"]):
|
||||||
|
@ -3626,17 +3629,17 @@ class Screen(TurtleScreen):
|
||||||
Example (for a Screen instance named screen):
|
Example (for a Screen instance named screen):
|
||||||
>>> screen.title("Welcome to the turtle-zoo!")
|
>>> screen.title("Welcome to the turtle-zoo!")
|
||||||
"""
|
"""
|
||||||
if Screen._root is not None:
|
if _Screen._root is not None:
|
||||||
Screen._root.title(titlestring)
|
_Screen._root.title(titlestring)
|
||||||
Screen._title = titlestring
|
_Screen._title = titlestring
|
||||||
|
|
||||||
def _destroy(self):
|
def _destroy(self):
|
||||||
root = self._root
|
root = self._root
|
||||||
if root is Screen._root:
|
if root is _Screen._root:
|
||||||
Turtle._pen = None
|
Turtle._pen = None
|
||||||
Turtle._screen = None
|
Turtle._screen = None
|
||||||
Screen._root = None
|
_Screen._root = None
|
||||||
Screen._canvas = None
|
_Screen._canvas = None
|
||||||
TurtleScreen._RUNNING = True
|
TurtleScreen._RUNNING = True
|
||||||
root.destroy()
|
root.destroy()
|
||||||
|
|
||||||
|
@ -3728,7 +3731,7 @@ def write_docstringdict(filename="turtle_docstringdict"):
|
||||||
docsdict = {}
|
docsdict = {}
|
||||||
|
|
||||||
for methodname in _tg_screen_functions:
|
for methodname in _tg_screen_functions:
|
||||||
key = "Screen."+methodname
|
key = "_Screen."+methodname
|
||||||
docsdict[key] = eval(key).__doc__
|
docsdict[key] = eval(key).__doc__
|
||||||
for methodname in _tg_turtle_functions:
|
for methodname in _tg_turtle_functions:
|
||||||
key = "Turtle."+methodname
|
key = "Turtle."+methodname
|
||||||
|
@ -3842,14 +3845,14 @@ def _screen_docrevise(docstr):
|
||||||
|
|
||||||
|
|
||||||
for methodname in _tg_screen_functions:
|
for methodname in _tg_screen_functions:
|
||||||
pl1, pl2 = getmethparlist(eval('Screen.' + methodname))
|
pl1, pl2 = getmethparlist(eval('_Screen.' + methodname))
|
||||||
if pl1 == "":
|
if pl1 == "":
|
||||||
print ">>>>>>", pl1, pl2
|
print ">>>>>>", pl1, pl2
|
||||||
continue
|
continue
|
||||||
defstr = ("def %(key)s%(pl1)s: return _getscreen().%(key)s%(pl2)s" %
|
defstr = ("def %(key)s%(pl1)s: return _getscreen().%(key)s%(pl2)s" %
|
||||||
{'key':methodname, 'pl1':pl1, 'pl2':pl2})
|
{'key':methodname, 'pl1':pl1, 'pl2':pl2})
|
||||||
exec defstr
|
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:
|
for methodname in _tg_turtle_functions:
|
||||||
pl1, pl2 = getmethparlist(eval('Turtle.' + methodname))
|
pl1, pl2 = getmethparlist(eval('Turtle.' + methodname))
|
||||||
|
|
|
@ -23,6 +23,9 @@ Core and Builtins
|
||||||
Library
|
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
|
- 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
|
was used with cProfile that returned an object that could not be converted
|
||||||
into a float.
|
into a float.
|
||||||
|
|
Loading…
Reference in New Issue