Several questions on Tkinter - mainloop, update method, effectiveness etc

141 views Asked by At

Background: I'm trying to write a graphics library for python built on top of Tkinter. I therefore would like to abstract all of Tkinter's functionality from the user and have method calls that modify the root window sequentially in a Processing-like manner. e.g my library (let's call it mylib) would enable you to write code like this:

from mylib import * #this would be my library
window(400, 400) #open a new window to add objects to
color('red') #set the color of all subsequent items to red
circle(radius=5, centerx = 0, centery=0) #make a red circle
line(10,10, 20, 20) #red line going from (10, 10) to (20, 20)
color('blue')
line(50, 50, 100, 100) #blue line

I thought of implementing it like this:

try:
    from tkinter import *
except:
    from Tkinter import *

_root = Tk()


class MyCanvas(Canvas):
    def __init__(self, width=400, height=400):
        master = Toplevel(_root)
        Canvas.__init__(self, master, width=width, height=height)
        self.pack()
        self.items = []
        self.width = width
        self.height = height
        _root.mainloop()


global _c
_c = None

def window():
    _c = MyCanvas()
    _c.pack()

def line(a,b,c,d):
    #config code goes here
    _c.create_line(a,b,c,d)

#test
window()
line(10, 10, 50, 50)

That didn't work because Python wouldn't get out of mainloop() so I tried this instead: try: from tkinter import * except: from Tkinter import *

_root = Tk()


class MyCanvas(Canvas):
    def __init__(self, width=400, height=400):
        master = Toplevel(_root)
        Canvas.__init__(self, master, width=width, height=height)
        self.pack()
        self.items = []
        self.width = width
        self.height = height



global _c
_c = None

def window():
    _c = MyCanvas()
    _c.pack()

def line(a,b,c,d):
    #config code goes here
    _c.create_line(a,b,c,d)
    _root.update_idletasks()

#test
window()
line(10, 10, 50, 50)

But that didn't work too - it just froze. And I tried replacing update_idletasks with update. The window froze again. How do I use update properly?

Is there a way to accomplish this using mainloop() without having the user explicitly call it?

Or is there a way to edit widgets in mainloop? I thought about using after but I didn't see how that would solve the problem.

If no answer exits given these constraints would writing the package in PyOpenGL be useful or portable ? Should I write the module using C from scratch? Does anything else exist? Help me!!!

Sorry for the long question. I've been at this for hours now to no avail.

1

There are 1 answers

2
patthoyts On

It looks to me like you might be better off writing this as a tcl implementation and using wish as the executable. WHat you seem to be doing is defining a domain specific language (DSL) that you will interpret into commands that drive Tk. There doesn't seem to be anything that particularly requires python here.

You need a mainloop. Any windowing application has to have an event pump that obtains messages from the system and dispatches them to your windows as necessary. All such applications have to end up at a point where the main UI thread just pumps this message queue. In the case of the Tk wish executable, this is built into the interpreter. Wish sources your script then runs the event loop. You could emulate that in a python library by loading the client code and calling the application main function as an after event. You would probably have to ensure that the client code does not call mainloop to avoid a conflict.

If you've never looked at Tcl/Tk before - you might want to. What you are defining looks not very distant from a Tcl/Tk application really.