这篇文章主要目的有两个

1. 实现如下效果

2. turtle源码分析,关键函数分析

python turtle原点 turtle坐标原点默认_Turtle


  1. turtle坐标系   turtle使用的是数学当中的直角坐标系,其原点坐标为(0,0)

python turtle原点 turtle坐标原点默认_ide_02

在这张图中,可以想想一下有一个小乌龟位于原点(0,0)位置处,然后根据你的调用进行移动;

疑问一:小乌龟初始移动方向哪?

class TNavigator(object):
     """Navigation part of the RawTurtle.
    Implements methods for turtle movement.
    """
    START_ORIENTATION = {
        "standard": Vec2D(1.0, 0.0),
        "world"   : Vec2D(1.0, 0.0),
        "logo"    : Vec2D(0.0, 1.0)  }
    DEFAULT_MODE = "standard"
    DEFAULT_ANGLEOFFSET = 0
    DEFAULT_ANGLEORIENT = 1

    def __init__(self, mode=DEFAULT_MODE):
        self._angleOffset = self.DEFAULT_ANGLEOFFSET
        self._angleOrient = self.DEFAULT_ANGLEORIENT
        self._mode = mode
        self.undobuffer = None
        self.degrees()
        self._mode = None
        self._setmode(mode)
        TNavigator.reset(self)

我们知道Turtle是继承自TNavigator类,在这个类中,定义了一个DEFAULT_MODE = “standard”的属性;
在构造TNavigator类的时候,会调用init方法,此时会传入DEFAULT_MODE,这个值就表示小乌龟默认的移动方向;该值表示默认小乌龟默认向东移动;

疑问二:怎么改变小乌龟初始移动方向?

# coding=utf-8

import turtle

turtle.mode("logo");
rectangleTurtle = turtle.Turtle(); 
rectangleTurtle.forward(100);

turtle.done()

如上,我们可以通过调用mode并传入方向参数来改变小乌龟的初始运行轨迹;其实这个和调用right或left效果是一样的,效果如下

python turtle原点 turtle坐标原点默认_Python_03

疑问三:怎么关闭小乌龟在移动时产生的动画效果

# coding=utf-8

import turtle

turtle.mode("logo");
rectangleTurtle = turtle.Turtle(); 
rectangleTurtle.tracer(False)
rectangleTurtle.tracer(8, 25)
rectangleTurtle.forward(100);
rectangleTurtle.tracer(True)
turtle.done()

我们通过tracer传入false即可关闭动画效果,在绘制完成之后注意恢复为true

疑问四:怎么关闭小乌龟的箭头

# coding=utf-8

import turtle

turtle.mode("logo");
rectangleTurtle = turtle.Turtle();
rectangleTurtle.hideturtle(); 
rectangleTurtle.tracer(False)
rectangleTurtle.tracer(8, 25)
rectangleTurtle.forward(100);
rectangleTurtle.tracer(True)
turtle.done()

如上可以通过hideturtle方法来让箭头消失;同理可以调用showturtle方法把箭头再显示出来


疑问五:小乌龟绘制的屏幕是怎么产生的,默认大小是是多少

class Turtle(RawTurtle):
    """RawTurtle auto-creating (scrolled) canvas.

    When a Turtle object is created or a function derived from some
    Turtle method is called a TurtleScreen object is automatically created.
    """
    _pen = None
    _screen = None

    def __init__(self,
                 shape=_CFG["shape"],
                 undobuffersize=_CFG["undobuffersize"],
                 visible=_CFG["visible"]):
        if Turtle._screen is None:
            Turtle._screen = Screen()
        RawTurtle.__init__(self, Turtle._screen,
                           shape=shape,
                           undobuffersize=undobuffersize,
                           visible=visible)

在构建Turtle对象的时候,可以发现调用了Screen()方法完成对Turtle._screen属性的赋值

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

在Screen方法中,我们可以发现,他是构造_Screen类来完成赋值的,其类代码如下

class _Screen(TurtleScreen):

    _root = None
    _canvas = None
    _title = _CFG["title"]

    def __init__(self):
        # 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:
            width = _CFG["width"]
            height = _CFG["height"]
            canvwidth = _CFG["canvwidth"]
            canvheight = _CFG["canvheight"]
            leftright = _CFG["leftright"]
            topbottom = _CFG["topbottom"]
            self._root.setupcanvas(width, height, canvwidth, canvheight)
            _Screen._canvas = self._root._getcanvas()
            TurtleScreen.__init__(self, _Screen._canvas)
            self.setup(width, height, leftright, topbottom)
            .....

在这个类中几个属性
1. width = _CFG[“width”]
2. height = _CFG[“height”]
3. canvwidth = _CFG[“canvwidth”]
4. canvheight = _CFG[“canvheight”]

这四个属性就是我们屏幕和画布相关的几个属性,其值是字典_CFG

_CFG = {"width" : 0.5,               # Screen
        "height" : 0.75,
        "canvwidth" : 400,
        "canvheight": 300,
        "leftright": None,
        "topbottom": None,
        "mode": "standard",          # TurtleScreen
        "colormode": 1.0,
        "delay": 10,
        "undobuffersize": 1000,      # RawTurtle
        "shape": "classic",
        "pencolor" : "black",
        "fillcolor" : "black",
        "resizemode" : "noresize",
        "visible" : True,
        "language": "english",        # docstrings
        "exampleturtle": "turtle",
        "examplescreen": "screen",
        "title": "Python Turtle Graphics",
        "using_IDLE": False
       }

字典_CFG相关key,value的解释如下
1. “width” : 0.5 : 绘画的屏幕的宽度占据主屏幕宽的一半
2. “height” : 0.75 绘画的屏幕的高度占据主屏幕高的一半
3. “canvwidth” : 400 默认画布的宽度是400像素
4. “canvheight”: 300 默认画布的高度是300像素
5. “title”: “Python Turtle Graphics” 默认的绘制图形的标题是Python Turtle Graphics


通过上面对问题的解答,相信大家对turtle有了个更深刻的认识,那我们该如何实现文章最开始的ui

python turtle原点 turtle坐标原点默认_Turtle_04

分析如下
1. 首先获得屏幕的宽和高 width 和 height
2. 蓝色长方形的顶点坐标应该是(-width - 30,height);这里应该注意到蓝色长方形的顶点坐标不是(-30,15),这是因为turtle采用的是直角坐标系,而不像Android里面,采用的是左手坐标系,android里面view的原点在屏幕的左上角
3. 通过goto的方法将绘制的起点放到(-width - 30,height)
4. 通过计算文字的坐标位置,调用write的方法完成整个图形的绘制

# coding:utf-8
# 引入turtle外部库,turtle是python中一个绘制图像的外部库
import turtle 

# 画长方形的画笔
rectangleTurtle = turtle.Turtle(); 
# 画文字的画笔
# fontT = turtle.Turtle(); 
# 行数
rows = 10;
# 列数     
columns = 9;


def iniTurtle():
#     隐藏箭头
    rectangleTurtle.hideturtle();
    rectangleTurtle.penup();
    rectangleTurtle.getscreen().screensize(600, 400, "white");
    rectangleTurtle.color('blue')
#     通过global可以管理修改全局变量,在函数里定义的变量是局部的,如果此处没有global,相当于新创建了一个变量screenWidth
    global screenWidth; 
    screenWidth = rectangleTurtle.getscreen().getcanvas().canvwidth;
    print screenWidth;
    global screenHeight; 
    screenHeight = rectangleTurtle.getscreen().getcanvas().canvwidth;
    print screenHeight;
    global interval;
    interval = 15;
    global rectangleHeight;
    rectangleHeight = 50;
    global startX;
    startX = screenWidth / 2 - interval;
    print startX;
    global startY;
    startY = screenHeight / 2 - interval;
    print startY;
    rectangleTurtle.goto(-startX, startY);
    rectangleTurtle.pendown();
# 通过penup提笔和pendown落笔这样就可以指定开始绘图的起始位置了,如果不使用penup和pendown方法,
# 那么默认的就会画一条从原点到goto方法指定参数的一条连线


def drawRectangle():
    rectangleTurtle.forward(screenWidth - interval * 2);
    rectangleTurtle.right(90);
    rectangleTurtle.forward(rectangleHeight);
    rectangleTurtle.right(90);
    rectangleTurtle.forward(screenWidth - interval * 2);
    rectangleTurtle.right(90);
    rectangleTurtle.forward(rectangleHeight);
    rectangleTurtle.penup(); 
    rectangleTurtle.goto(-startX + interval * 20, startY - interval * 2.5);
    rectangleTurtle.pendown();
    rectangleTurtle.write("九九乘法口诀表", False, "center");


iniTurtle();
drawRectangle();       

turtle.done();