Application console for Tkinter program?

Terry Reedy tjreedy at udel.edu
Sat Mar 5 05:15:16 EST 2016


On 3/5/2016 2:52 AM, Christian Gollwitzer wrote:

> is there an easy way to add an application console to a Tkinter program?

Right now, you should turn the question around.  Is there an easy way to 
run a tkinter program within an interactive console?  Answer: yes, two 
ways, after removing the runshell stuff and mainloop call*.

1. Call your program mytk.py.  In your system console, run 'python -i 
myth.py'.  When the code ends, control passes to the console running 
python.  Statements like 'print(nvar.get())' will be executed in the 
main namespace of the still running program.

2. Load (or write) the file into an IDLE Editor and hit F5 (Run -> Run 
module on the menu).  This simulates the console command above.

* The tk loop is started with the Tk() call.  Most things work without 
the blocking mainloop() call.  When this is true, the mainloop call 
serves mainly to keep the program running instead of exiting.  The -i 
option does the same.

If you need mainloop(), then add

     def quit(): # or quit(self):
         root.exit()
     b = tk.Button(root, command=quit)
     b.grid()  # or pack or place

The root.quit() call ends the blocking mainloop call and allows console 
entry.  I believe a subsequent root.mainloop() in the console will work 
when needed.

> For instance, can you embed IDLE into a program such that when a button
> is pressed, it pops up a REPL window where the running program can be
> examined?

If the REPL window is defined in an imported module, the problem is 
linking the main namespace of the tkinter program with the REPL loop in 
such a way that commands entered into the REPL are executed in the main 
module, not in the REPL module.

> Say, there is a simple program like:
>
> ====================
> import Tkinter as tk
>
> def runshell():
>      from idlelib.PyShell import main
>      main()
>
> root=tk.Tk()
> nvar=tk.StringVar(root)
> en=tk.Entry(textvariable=nvar)
> en.pack()
>
> btn=tk.Button(text="Shell", command=runshell)
> btn.pack()
>
> root.mainloop()
> ====================
>
> I want the button to popup a shell window, and then nvar.get() should
> give me whatever is currently written in the entry. The code above does
> not work as intended, it pops up a shell, but:
>
> 1) I can't reach the variables from the main program, i.e. print(nvar)
> gives me a NameError

This is the linkage problem I mentioned.

> 2) If you click the Shell button twice, it locks up the program, because
> main() obviously starts it's own mainloop

IDLE executes user code in a separate process, linked by sockets, so 
that execution of IDLE GUI code and user code do not interfere with each 
other.  I would like to refactor IDLE so that the Shell window would 
contain a Shell Frame (or LabelledFrame) that could also be used as pane 
in a single-window version of IDLE.  It would be possible to create a 
Shell frame without starting a new mainloop.

It might be possible to adapt such a component as an embedded console. 
An imported frame should not interfere with the main-module code or code 
in other modules.  The main problems are a) namespace linkage (mentioned 
before), b) the need for sys.stdin/out/err to not be None, and c) for 
capturing exceptions in code entered in the console, so as to not crash 
the main program.

-- 
Terry Jan Reedy




More information about the Python-list mailing list