Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #104086 > unrolled thread

Application console for Tkinter program?

Started byChristian Gollwitzer <auriocus@gmx.de>
First post2016-03-05 08:52 +0100
Last post2016-03-06 07:12 -0500
Articles 6 — 2 participants

Back to article view | Back to comp.lang.python


Contents

  Application console for Tkinter program? Christian Gollwitzer <auriocus@gmx.de> - 2016-03-05 08:52 +0100
    Re: Application console for Tkinter program? Terry Reedy <tjreedy@udel.edu> - 2016-03-05 05:15 -0500
      Re: Application console for Tkinter program? Christian Gollwitzer <auriocus@gmx.de> - 2016-03-05 12:45 +0100
        Re: Application console for Tkinter program? Terry Reedy <tjreedy@udel.edu> - 2016-03-05 16:16 -0500
          Re: Application console for Tkinter program? Christian Gollwitzer <auriocus@gmx.de> - 2016-03-06 10:23 +0100
            Re: Application console for Tkinter program? Terry Reedy <tjreedy@udel.edu> - 2016-03-06 07:12 -0500

#104086 — Application console for Tkinter program?

FromChristian Gollwitzer <auriocus@gmx.de>
Date2016-03-05 08:52 +0100
SubjectApplication console for Tkinter program?
Message-ID<nbe31k$c9$1@dont-email.me>
Hi all,

is there an easy way to add an application console to a Tkinter program? 
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?

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

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


	Christian

[toc] | [next] | [standalone]


#104090

FromTerry Reedy <tjreedy@udel.edu>
Date2016-03-05 05:15 -0500
Message-ID<mailman.221.1457172954.20602.python-list@python.org>
In reply to#104086
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

[toc] | [prev] | [next] | [standalone]


#104091

FromChristian Gollwitzer <auriocus@gmx.de>
Date2016-03-05 12:45 +0100
Message-ID<nbegmb$b0q$1@dont-email.me>
In reply to#104090
Am 05.03.16 um 11:15 schrieb Terry Reedy:
> 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.

so this means no, right?

> 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.

well yes, this does work, but I should have explained why I want it the 
other way round. We have an in-house tool which is used to manipulate 
images. During production use, at some point you think "and now if I 
could just save the image that I see on screen into a PNG file". You 
know exactly that MyViewer.image is the thing that contains what you 
need, if only you had a way to tell it 
'MyViewer.image.save("somewhere.png")'. At this point, you haven't 
started the program from an interactive python. Always running the tool 
from ipython or idle means there are useless windows hanging around, but 
if you close them, your pogram goe away. To make it even more 
complicated, the deployed version of the tool uses pyinstaller to be 
safe from environment changes.

Of course, I could pack some text widget somewhere and fiddle a few 
bindings to make it do this with eval(), but a good REPL has history, 
autocompletion, syntax highlighting.... you get it. I had simply hoped, 
since idle is written in Tkinter, that it could be reused for that purpose.

For pure Tcl/Tk, there is tkcon which can do exactly this and I use it 
in similar tools writtin in Tcl/Tk. I can run it via Tk.eval(), but I 
couldn't find a way to call back into Python coming from the Tkinter 
interpreter, and obviously autocompletion and syntax highlighting do not 
work well.

>> 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.

I'm happy to pass the main module as an argument to REPLInit().

>> 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.

Ahhh - OK this makes sense in the general case, but not for a console 
where you *want* your REPL to perform surgery on the main program.

> I would like to refactor IDLE so that the Shell window
> ...
> 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,

tkcon solves this be redirecting stdin/stdout/stderr to functions which 
write to the console window.

> and c) for
> capturing exceptions in code entered in the console, so as to not crash
> the main program.


For Python exceptions I see no problem - the eval must simply be 
properly wrapped in try..except and the traceback is redirected to the 
console. If a C level exception occurs, this will crash everything, but 
that's OK.

	Christian

[toc] | [prev] | [next] | [standalone]


#104113

FromTerry Reedy <tjreedy@udel.edu>
Date2016-03-05 16:16 -0500
Message-ID<mailman.232.1457212605.20602.python-list@python.org>
In reply to#104091
On 3/5/2016 6:45 AM, Christian Gollwitzer wrote:
> Am 05.03.16 um 11:15 schrieb Terry Reedy:
>> 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.
>
> so this means no, right?

Right.

>> 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.
>
> well yes, this does work, but I should have explained why I want it the
> other way round. We have an in-house tool which is used to manipulate
> images. During production use, at some point you think "and now if I
> could just save the image that I see on screen into a PNG file". You
> know exactly that MyViewer.image is the thing that contains what you
> need, if only you had a way to tell it
> 'MyViewer.image.save("somewhere.png")'. At this point, you haven't
> started the program from an interactive python. Always running the tool
> from ipython or idle means there are useless windows hanging around, but
> if you close them, your pogram goe away. To make it even more
> complicated, the deployed version of the tool uses pyinstaller to be
> safe from environment changes.

Since idlelib.PyShell is the idle startup module as well Shell window 
module, importing it imports practically all of idlelib.  Not what you 
want.  Calling PyShell.main calls tk.Tk and tk.mainloop, also not what 
you want.

> Of course, I could pack some text widget somewhere and fiddle a few
> bindings to make it do this with eval(), but a good REPL has history,
> autocompletion, syntax highlighting.... you get it. I had simply hoped,
> since idle is written in Tkinter, that it could be reused for that purpose.

(For statements, you would use exec() rather than eval().)

Not now. A console is a REPL + text display to read from and print to. 
The actual IDLE REPL is PyShell.ModifiedInterpreter, which subclasses 
stdlib code.InteractiveInterpreter.  Most of the additions are for 
interacting with the subprocess that runs user code.  You should start 
instead with the base class.

The Shell text display is a subclass of a subclass of a class that 
contains a subclass of Toplevel with the complete IDLE Menu and a Text 
widget wrapper.  Again, this is too much baggage for an application console.

The idlelib ColorDelegator syntax highlighter can be reused with a Text 
instance.  See turtledemo.__main__ for an example.  I don't know if (or 
how) IDLE's autocompletion modules could be reused in their current 
state.  I believe Shell's history 'list' consists of the statements in 
the Text instance prefixed by the '>>> ' prompt.

A simple app console might have separate text boxes for input and output.

> For pure Tcl/Tk, there is tkcon which can do exactly this and I use it
> in similar tools writtin in Tcl/Tk. I can run it via Tk.eval(), but I
> couldn't find a way to call back into Python coming from the Tkinter
> interpreter, and obviously autocompletion and syntax highlighting do not
> work well.
>
>>> 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.
>
> I'm happy to pass the main module as an argument to REPLInit().
>
>>> 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.
>
> Ahhh - OK this makes sense in the general case, but not for a console
> where you *want* your REPL to perform surgery on the main program.
>
>> I would like to refactor IDLE so that the Shell window
>> ...
>> 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),

Perhaps I should have said 'issues that require attention' rather than 
'problems' ;-).  As you note, b) and c) are conceptually easy, though 
the execution in IDLE is complicated by having to communicate between 
two processes.  The execution in a within-process console would be much 
easier.

>> b) the need for sys.stdin/out/err to not be None,
>
> tkcon solves this be redirecting stdin/stdout/stderr to functions which
> write to the console window.

IDLE sets sys.stdin, etc, in the user process to custom instances with 
read/write methods.

>> and c) for
>> capturing exceptions in code entered in the console, so as to not crash
>> the main program.
>
> For Python exceptions I see no problem - the eval must simply be
> properly wrapped in try..except and the traceback is redirected to the
> console.

-- 
Terry Jan Reedy

[toc] | [prev] | [next] | [standalone]


#104127

FromChristian Gollwitzer <auriocus@gmx.de>
Date2016-03-06 10:23 +0100
Message-ID<nbgsoa$upt$1@dont-email.me>
In reply to#104113
Am 05.03.16 um 22:16 schrieb Terry Reedy:
> Not now. A console is a REPL + text display to read from and print to.
> The actual IDLE REPL is PyShell.ModifiedInterpreter, which subclasses
> stdlib code.InteractiveInterpreter.  Most of the additions are for
> interacting with the subprocess that runs user code.  You should start
> instead with the base class.
>
> The Shell text display is a subclass of a subclass of a class that
> contains a subclass of Toplevel with the complete IDLE Menu and a Text
> widget wrapper.  Again, this is too much baggage for an application
> console.
>
> The idlelib ColorDelegator syntax highlighter can be reused with a Text
> instance.  See turtledemo.__main__ for an example.  I don't know if (or
> how) IDLE's autocompletion modules could be reused in their current
> state.  I believe Shell's history 'list' consists of the statements in
> the Text instance prefixed by the '>>> ' prompt.

Thanks! I'll try to browse my way through the source code, these details 
help a lot. I still haven't understood the difference between exec() and 
eval(). I understand that for statements you want to exec them, for 
expressions you eval it and print the result. When the user has entered 
code, how does the REPL know if it should be eval'ed or exec'ed? I 
assume that you don't try to parse the Python code manually to find this 
out? Or you try to eval(), and if it doesn't compile, you exec()?

	Christian

[toc] | [prev] | [next] | [standalone]


#104133

FromTerry Reedy <tjreedy@udel.edu>
Date2016-03-06 07:12 -0500
Message-ID<mailman.239.1457266393.20602.python-list@python.org>
In reply to#104127
On 3/6/2016 4:23 AM, Christian Gollwitzer wrote:
> Am 05.03.16 um 22:16 schrieb Terry Reedy:
>> Not now. A console is a REPL + text display to read from and print to.
>> The actual IDLE REPL is PyShell.ModifiedInterpreter, which subclasses
>> stdlib code.InteractiveInterpreter.  Most of the additions are for
>> interacting with the subprocess that runs user code.  You should start
>> instead with the base class.
>>
>> The Shell text display is a subclass of a subclass of a class that
>> contains a subclass of Toplevel with the complete IDLE Menu and a Text
>> widget wrapper.  Again, this is too much baggage for an application
>> console.
>>
>> The idlelib ColorDelegator syntax highlighter can be reused with a Text
>> instance.  See turtledemo.__main__ for an example.  I don't know if (or
>> how) IDLE's autocompletion modules could be reused in their current
>> state.  I believe Shell's history 'list' consists of the statements in
>> the Text instance prefixed by the '>>> ' prompt.
>
> Thanks! I'll try to browse my way through the source code, these details
> help a lot. I still haven't understood the difference between exec() and
> eval(). I understand that for statements you want to exec them, for
> expressions you eval it and print the result. When the user has entered
> code, how does the REPL know if it should be eval'ed or exec'ed? I
> assume that you don't try to parse the Python code manually to find this
> out? Or you try to eval(), and if it doesn't compile, you exec()?

Python expressions are also statements.  Python REPLs exec statements. 
But to make Read-Exec-Print work like traditional Read-Eval-Print, 
Python, in interactive mode, echos the value of expression statements 
(and assign it to _ for later reuse).  So '2 + 2' echos 4 in REPL, or at 
least in the console and IDLE, '2 + 2' is useless in a program run in 
batch mode.

-- 
Terry Jan Reedy

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.python


csiph-web