1

I'm currently writing a module (myModule) that can create a tkinter canvas and attach a turtle to it. That part of the module is done. However, for some reason, turtle still opens another window when it gets attached to the tkinter canvas. I would like to avoid this, but i don't know how, and the turtle documentation is horrible.

Here is the relevant part of what I've made so far:

#myModule
import tkinter as tk
import turtle as tr
import inspect as ins
from functools import partial

_root = None
_canvas = None
_turtle = None
d = None

def openWindow():
    global _root
    global d

    if d == None:
        myFrame = sys._getframe()
        aboveFrameName = myFrame.f_back.f_back.f_back.f_globals["__name__"] #This doesnt make sense, but it works.
        userModule = sys.modules[aboveFrameName]
        d = userModule.__dict__

    _root = tk.Tk()


def attachCanvas():
    global _canvas
    if _root == None:
        openWindow()

    _canvas = tk.Canvas(_root, bd = 0, highlightthickness = 0, width = 500, height = 500)
    _canvas.pack()


def attachTurtle():
    global _turtle
    global _canvas
    global _screen
    global d
    if _canvas == None:
        attachCanvas()

    _turtle = tr.RawTurtle(_canvas)

    for key in tr.__dict__.keys():
        obj = None
        if key in tr.TNavigator.__dict__.keys():  #Checks if the object also exists in TNavigator
            obj = getattr(tr.TNavigator, key)
            if hasattr(obj, "__call__") and ("self" in ins.getargspec(obj)[0]): #Checks if the function 
                                                                                 uses a self argument
                obj = partial(obj, _turtle) #Pass in the turtle we just created automatically
        else:
            obj = getattr(tr, key)
        d[key] = obj   #Transfer object reference from myModule to userProgram

    return _turtle


def mainloop():
    tk.mainloop()


#userProgram
from myModule import *

attachTurtle()
forward(100)
mainloop()

Note: Lets say trM is the turtle module and trI is an instance of RawTurtle.

I have noticed for example that trM.forward(10) is applied on the default screen , and trI.forward(x) is applied on the tkinter screen. Additionally functions such as forward(x) (after having done from turtle import *) are actually calling trM.TNavigator.forward(trI, x).

Turtle has confused me enough for me to code up a recursive object inspector, but i still can't tell what needs to change.

ChaoTech
  • 29
  • 4
  • Relevant [python-turtle-get-tkinter-root](https://stackoverflow.com/questions/34004152/python-turtle-get-tkinter-root) – stovfl Oct 17 '19 at 10:56

1 Answers1

0

Okay, I found where i went wrong.

The fix is to use:

if elem != "mainloop":
    d[elem] = obj

Instead of just d[elem] = obj

Turns out that the default window is created when turtle's mainloop() is called.

In theory, mainloop() in userProgram is the mainloop() in myModule. Unfortunately, because of attachTurtle() (and more specifically d[elem] = obj) this definition gets overwritten with turtle's mainloop(). So the fix is just to prevent attachTurtle() from changing mainloop().

The lesson to be learned is to check what definitions you are creating, in case you're overwriting an important one.

I can't believe I went digging in the source code when the solution was this simple

ChaoTech
  • 29
  • 4