[Tutor] full screen turtle.py

Gregor Lingl glingl@aon.at
Tue Feb 11 17:41:27 2003


This is a multi-part message in MIME format.
--------------010101010100010208010001
Content-Type: text/plain; charset=us-ascii; format=flowed
Content-Transfer-Encoding: 7bit

reavey schrieb:

> is there a way to display a full screen when turtle.py initializes? 

As a default-canvas is created the first time when you call an arbitrary 
turtle-graphics
function, there is no way to pass information about its size to the canvas.

But:

(1) There is the possibility to create turtle-objects on your own 
Tkinter-Canvas
which may have any size you want. more precisely, you have to create
an object of the RawPen class, which goes like this:

 >>> from Tkinter import Canvas
 >>> cv = Canvas(width=800, height=600)
 >>> cv.pack()
 >>> t = RawPen(cv)
 >>> t.forward(100)

you may reset the size of cv with something like:

 >>> cv["width"]=400
 >>> cv["height"] = 500

and recenter t by calling t.reset  (which works essentially the same way
you used when resizing the default-canvas manually)

(2) Another way to accomplish what you want ist do decide to rewrite
the reset-function of the turtle-module in order to pass information
about the size of the canvas. (If these arguments are not given, it 
works the old way):

First you have to change the reset-method of RawPen  (approx line 40):

    def reset(self, width = None, height = None):
        canvas = self._canvas
        if width: canvas["width"] = width
        if height: canvas["height"] = height
        self._canvas.update()
        # .... and so on. as before

Then you have to modify the reset - function (approx line 350):

def reset(width=None, height=None): _getpen().reset(width,height)

I've attached a modified turtle.py

With these changes the following will be possible:

 >>> from turtle import *
 >>> reset(800,600)
 >>> forward(50)
 >>> reset(200,200)

Regards, Gregor

P.S. I didn't extensively test these changes, so maybe there will be
some unwanted side-effects, especially when using RawPen.
Maybe I'll have a look at this sometimes later ...  

>
> The first canvas takes up a small portion of the display (around 10%).
> When I hit the expand button on the canvas it doesn't recenter.
> The drawing still uses the inititial canvas coordinates.
>
> btw: this is not a problem using the interactive interpreter as a 
> turtle.reset()
>        issued after you expand works as expected.
>
> thanks
> re-v
>
>
> _______________________________________________
> Tutor maillist  -  Tutor@python.org
> http://mail.python.org/mailman/listinfo/tutor
>
>



--------------010101010100010208010001
Content-Type: text/plain;
 name="turtle.py"
Content-Transfer-Encoding: 8bit
Content-Disposition: inline;
 filename="turtle.py"

# LogoMation-like turtle graphics

from math import * # Also for export
import Tkinter
class Error(Exception):
    pass

class RawPen:

    def __init__(self, canvas):
        self._canvas = canvas
        self._items = []
        self._tracing = 1
        self._arrow = 0
        self._set_fullcircle(360.0) # alter self.degrees() Aufruf
        self.reset()

    # Das ist die alte degrees - Funktion
    # doch ohne Standardwert
    def _set_fullcircle(self, fullcircle):
        self._fullcircle = fullcircle
        self._invradian = pi / (fullcircle * 0.5)

    # nur noetig, wenn nicht eh schon Gradmass eingestellt
    def degrees(self):
        if self._fullcircle == 360.0:
            return
        self._set_fullcircle(360.0)
        self._angle = self._angle / self._invradian

    # nur noetig wenn nicht eh schon Bogenmass eingestellt
    def radians(self):
        # Die folgende Anweisung koennte unterbleiben, da
        # in diesem Fall self._invradian den Wert 1 hat.
        # Finde es so aber klarer
        if self._fullcircle == 2.0*pi:
            return
        self._angle = self._angle * self._invradian
        self._set_fullcircle(2.0*pi)

    def reset(self, width = None, height = None):
        canvas = self._canvas
        if width: canvas["width"] = width
        if height: canvas["height"] = height
        self._canvas.update()
        width = canvas.winfo_width()
        height = canvas.winfo_height()
        if width <= 1:
            width = canvas['width']
        if height <= 1:
            height = canvas['height']
        self._origin = float(width)/2.0, float(height)/2.0
        self._position = self._origin
        self._angle = 0.0
        self._drawing = 1
        self._width = 1
        self._color = "black"
        self._filling = 0
        self._path = []
        self._tofill = []
        self.clear()
        canvas._root().tkraise()

    def clear(self):
        self.fill(0)
        canvas = self._canvas
        items = self._items
        self._items = []
        for item in items:
            canvas.delete(item)
        self._delete_turtle()
        self._draw_turtle()


    def tracer(self, flag):
        self._tracing = flag
        if not self._tracing:
            self._delete_turtle()
        self._draw_turtle()

    def forward(self, distance):
        x0, y0 = start = self._position
        x1 = x0 + distance * cos(self._angle*self._invradian)
        y1 = y0 - distance * sin(self._angle*self._invradian)
        self._goto(x1, y1)

    def backward(self, distance):
        self.forward(-distance)

    def left(self, angle):
        self._angle = (self._angle + angle) % self._fullcircle
        self._draw_turtle()

    def right(self, angle):
        self.left(-angle)

    def up(self):
        self._drawing = 0

    def down(self):
        self._drawing = 1

    def width(self, width):
        self._width = float(width)

    def color(self, *args):
        if not args:
            raise Error, "no color arguments"
        if len(args) == 1:
            color = args[0]
            if type(color) == type(""):
                # Test the color first
                try:
                    id = self._canvas.create_line(0, 0, 0, 0, fill=color)
                except Tkinter.TclError:
                    raise Error, "bad color string: %s" % `color`
                self._set_color(color)
                return
            try:
                r, g, b = color
            except:
                raise Error, "bad color sequence: %s" % `color`
        else:
            try:
                r, g, b = args
            except:
                raise Error, "bad color arguments: %s" % `args`
        assert 0 <= r <= 1
        assert 0 <= g <= 1
        assert 0 <= b <= 1
        x = 255.0
        y = 0.5
        self._set_color("#%02x%02x%02x" % (int(r*x+y), int(g*x+y), int(b*x+y)))

    def _set_color(self,color):
        self._color = color
        self._draw_turtle()


    def write(self, arg, move=0):
        x, y = start = self._position
        x = x-1 # correction -- calibrated for Windows
        item = self._canvas.create_text(x, y,
                                        text=str(arg), anchor="sw",
                                        fill=self._color)
        self._items.append(item)
        if move:
            x0, y0, x1, y1 = self._canvas.bbox(item)
            self._goto(x1, y1)
        self._draw_turtle()

    def fill(self, flag):
        if self._filling:
            path = tuple(self._path)
            smooth = self._filling < 0
            if len(path) > 2:
                item = self._canvas._create('polygon', path,
                                            {'fill': self._color,
                                             'smooth': smooth})
                self._items.append(item)
                self._canvas.lower(item)
                if self._tofill:
                    for item in self._tofill:
                        self._canvas.itemconfigure(item, fill=self._color)
                        self._items.append(item)
        self._path = []
        self._tofill = []
        self._filling = flag
        if flag:
            self._path.append(self._position)

    def circle(self, radius, extent=None):
        if extent is None:
            extent = self._fullcircle
        x0, y0 = self._position
        xc = x0 - radius * sin(self._angle * self._invradian)
        yc = y0 - radius * cos(self._angle * self._invradian)
        # weil self._angle eventuell im Bogenmass vorliegt:
        # 90.0 ----> self._fullcircle / 4
        if radius >= 0.0:
            start = self._angle - self._fullcircle / 4
        else:
            start = self._angle + self._fullcircle / 4
            extent = -extent
        ## start und extent für den Bogen werden
        ## c_start und arc_extent zugewiesen
        ## weil sie für Canvas.create_arc unbedingt
        ## im Gradmass angegeben werden muessen
        if self._fullcircle == 2 * pi:
            arc_start = start * 180.0 / pi
            arc_extent = extent * 180.0 / pi
        else:
            arc_start = start
            arc_extent = extent

        if self._filling:
            if abs(extent) >= self._fullcircle:
                item = self._canvas.create_oval(xc-radius, yc-radius,
                                                xc+radius, yc+radius,
                                                width=self._width,
                                                outline="")
                self._tofill.append(item)
            item = self._canvas.create_arc(xc-radius, yc-radius,
                                           xc+radius, yc+radius,
                                           style="chord",
                                           start=arc_start,
                                           extent=arc_extent,
                                           width=self._width,
                                           outline="")
            self._tofill.append(item)
        if self._drawing:
            if abs(extent) >= self._fullcircle:
                item = self._canvas.create_oval(xc-radius, yc-radius,
                                                xc+radius, yc+radius,
                                                width=self._width,
                                                outline=self._color)
                self._items.append(item)
            # print xc-radius,yc-radius,xc+radius,yc+radius
            # print start, extent, self._width, self._color
            item = self._canvas.create_arc(xc-radius, yc-radius,
                                           xc+radius, yc+radius,
                                           style="arc",
                                           start=arc_start,
                                           extent=arc_extent,
                                           width=self._width,
                                           outline=self._color)
            self._items.append(item)
        angle = start + extent
        x1 = xc + abs(radius) * cos(angle * self._invradian)
        y1 = yc - abs(radius) * sin(angle * self._invradian)
        self._angle = (self._angle + extent) % self._fullcircle
        self._position = x1, y1
        if self._filling:
            self._path.append(self._position)
        self._draw_turtle()

    def goto(self, *args):
        if len(args) == 1:
            try:
                x, y = args[0]
            except:
                raise Error, "bad point argument: %s" % `args[0]`
        else:
            try:
                x, y = args
            except:
                raise Error, "bad coordinates: %s" % `args[0]`
        x0, y0 = self._origin
        self._goto(x0+x, y0-y)

    def _goto(self, x1, y1):
        x0, y0 = start = self._position
        self._position = map(float, (x1, y1))
        if self._filling:
            self._path.append(self._position)
        if self._drawing:
            if self._tracing:
                dx = float(x1 - x0)
                dy = float(y1 - y0)
                distance = hypot(dx, dy)
                nhops = int(distance)
                item = self._canvas.create_line(x0, y0, x0, y0,
                                                width=self._width,
                                                capstyle="round",
                                                fill=self._color)
                try:
                    for i in range(1, 1+nhops):
                        x, y = x0 + dx*i/nhops, y0 + dy*i/nhops
                        self._canvas.coords(item, x0, y0, x, y)
                        self._draw_turtle((x,y))
                        self._canvas.update()
                        self._canvas.after(10)
                    # in case nhops==0
                    self._canvas.coords(item, x0, y0, x1, y1)
                    self._canvas.itemconfigure(item, arrow="none")
                except Tkinter.TclError:
                    # Probably the window was closed!
                    return
            else:
                item = self._canvas.create_line(x0, y0, x1, y1,
                                                width=self._width,
                                                capstyle="round",
                                                fill=self._color)
            self._items.append(item)
        self._draw_turtle()

    def _draw_turtle(self,position=[]):
        if not self._tracing:
            return
        if position == []:
            position = self._position
        x,y = position
        distance = 8
        dx = distance * cos(self._angle*self._invradian)
        dy = distance * sin(self._angle*self._invradian)
        self._delete_turtle()
        self._arrow = self._canvas.create_line(x-dx,y+dy,x,y,
                                          width=self._width,
                                          arrow="last",
                                          capstyle="round",
                                          fill=self._color)
        self._canvas.update()

    def _delete_turtle(self):
        if self._arrow != 0:
            self._canvas.delete(self._arrow)
        self._arrow = 0

##  Extensions by g.l.

    def pos(self):
        x, y  = self._position
        ox,oy = self._origin
        return x - ox, oy - y

    def heading(self):
        return self._angle

    def _vector_to(self, *args):
        if len(args) == 2:
            x, y = args
        else:
            arg = args[0]
            if isinstance(arg, RawPen):
                x, y = arg.pos()
            else:
                x, y = arg
        x0, y0 = self.pos()
        return x - x0, y - y0

    def towards(self, *args):
        vx, vy = self._vector_to(*args)
        return (atan2(vy,vx) / self._invradian) % self._fullcircle

    def setheading(self,angle):
        self._angle = angle % self._fullcircle
        self._draw_turtle()


_root = None
_canvas = None
_pen = None

class Pen(RawPen):

    def __init__(self):
        global _root, _canvas
        if _root is None:
            _root = Tkinter.Tk()
            _root.wm_protocol("WM_DELETE_WINDOW", self._destroy)
        if _canvas is None:
            # XXX Should have scroll bars
            _canvas = Tkinter.Canvas(_root, background="white")
            _canvas.pack(expand=1, fill="both")
        RawPen.__init__(self, _canvas)

    def _destroy(self):
        global _root, _canvas, _pen
        root = self._canvas._root()
        if root is _root:
            _pen = None
            _root = None
            _canvas = None
        root.destroy()


def _getpen():
    global _pen
    if not _pen:
        _pen = Pen()
    return _pen

def degrees(): _getpen().degrees()
def radians(): _getpen().radians()
def reset(width=None, height=None): _getpen().reset(width,height)
def clear(): _getpen().clear()
def tracer(flag): _getpen().tracer(flag)
def forward(distance): _getpen().forward(distance)
def backward(distance): _getpen().backward(distance)
def left(angle): _getpen().left(angle)
def right(angle): _getpen().right(angle)
def up(): _getpen().up()
def down(): _getpen().down()
def width(width): _getpen().width(width)
def color(*args): apply(_getpen().color, args)
def write(arg, move=0): _getpen().write(arg, move)
def fill(flag): _getpen().fill(flag)
def circle(radius, extent=None): _getpen().circle(radius, extent)
def goto(*args): apply(_getpen().goto, args)
## Extensions by g.l.
def pos(): return _getpen().pos()
def heading(): return _getpen().heading()
def towards(*args): return apply(_getpen().towards, args)
def setheading(angle): _getpen().setheading(angle)


def demo():
    reset()
    tracer(1)
    up()
    backward(100)
    down()
    # draw 3 squares; the last filled
    width(3)
    for i in range(3):
        if i == 2:
            fill(1)
        for j in range(4):
            forward(20)
            left(90)
        if i == 2:
            color("maroon")
            fill(0)
        up()
        forward(30)
        down()
    width(1)
    color("black")
    # move out of the way
    tracer(0)
    up()
    right(90)
    forward(100)
    right(90)
    forward(100)
    right(180)
    down()
    # some text
    write("startstart", 1)
    write("start", 1)
    color("red")
    # staircase
    for i in range(5):
        forward(20)
        left(90)
        forward(20)
        right(90)
    # filled staircase
    fill(1)
    for i in range(5):
        forward(20)
        left(90)
        forward(20)
        right(90)
    fill(0)
    # more text
    write("end")
    if __name__ == '__main__':
        _root.mainloop()

if __name__ == '__main__':
    # demo()
    pass

--------------010101010100010208010001--