CLI+GUI

  • Thread starter Michele Simionato
  • Start date
M

Michele Simionato

I wonder what is the recommended way of using Tkinter
together with a command line oriented application.
I have in mind something like that:

import cmd,sys

class CMD(cmd.Cmd):
def do_this(self,*args):
draw_a_diagram()
def do_that(self,*args):
draw_another_diagram()
def do_exit(self,*args):
sys.exit(0)

c=CMD()
c.cmdloop()

Here the methods ``draw_a_diagram`` and ``draw_another_diagram``
should do what you expect. Notice that I don't want to use
different windows, the graphs should be displayed on the same
window one over the other. BTW, I am not really displaying
diagrams, this is only the simplest example I can figure out
of graphics program driven by a command line interpreter.
I want to stay with the CLI interface, which I like a lot
thanks to the readline and completion support, the easy
of use and the easy of implementation.

I have no idea of how to do that, except via contorsions
such as saving (a representation of) the diagrams in a file
and having a separated Tkinter process that periodically look at the
file, changing the display if the file has been updated. I
guess there is a better way, since this is a quite common issue.
Any suggestion?

TIA,

Michele
 
M

Michele Simionato

I wonder what is the recommended way of using Tkinter
together with a command line oriented application.

Replying to myself ...

I tried to implement what I discussed in my previous mail via the
threading module:

#cmdriven.py

import Tkinter as t
import cmd,threading

root=t.Tk()
s=t.StringVar()
s.set('ciao')
label=t.Label(root,textvariable=s)
label.pack()

class Cmd(cmd.Cmd):
def do_display(self,arg):
s.set(arg)
def do_quit(self,arg):
root.quit()
return 'quit' # anything <> None will do the job

def cmdloop(stringvar):
try: Cmd().cmdloop()
finally: pass # gracefully exit if sometimes goes wrong

thread=threading.Thread(target=cmdloop,args=(s,))
thread.start()
root.mainloop()

It works if I do something like

$ python cmdriven.py
(Cmd) display hello
(Cmd) display It works!
(Cmd) quit

However, I wonder if this is a robust solution and if I should expect
problems in more complicate situations (some time passes ... I have
just discovered that this script hangs under Windows 98!)

BTW, I have another question, why the Cmd class does not have a default quit
method? Looking at the source I see that any method returning something
different from None will stop the command loop, and so I have used this
hack, but I don't like it. Maybe I have missed something in the documentation?
Thanks,

Michele
 
E

Eric Brunel

Michele said:
Replying to myself ...

I tried to implement what I discussed in my previous mail via the
threading module:

#cmdriven.py

import Tkinter as t
import cmd,threading

root=t.Tk()
s=t.StringVar()
s.set('ciao')
label=t.Label(root,textvariable=s)
label.pack()

class Cmd(cmd.Cmd):
def do_display(self,arg):
s.set(arg)
def do_quit(self,arg):
root.quit()
return 'quit' # anything <> None will do the job

def cmdloop(stringvar):
try: Cmd().cmdloop()
finally: pass # gracefully exit if sometimes goes wrong

thread=threading.Thread(target=cmdloop,args=(s,))
thread.start()
root.mainloop()

It works if I do something like

$ python cmdriven.py
(Cmd) display hello
(Cmd) display It works!
(Cmd) quit

However, I wonder if this is a robust solution and if I should expect
problems in more complicate situations (some time passes ... I have
just discovered that this script hangs under Windows 98!)

I don't know if this is the problem, because you didn't say exactly when the
script hangs, but Tkinter apparently has problems when calls to it are made from
a thread different from the one into which it was initialized. I'd use an Event
between Tkinter's thread and Cmd's thread, checking it regularly with Tkinter's
after method.

HTH
 
M

Michele Simionato

Eric Brunel said:
I don't know if this is the problem, because you didn't say exactly when the
script hangs, but Tkinter apparently has problems when calls to it are made
from a thread different from the one into which it was initialized. I'd use
an Event between Tkinter's thread and Cmd's thread, checking it regularly
with Tkinter's after method.

HTH

It hangs immediately when I start the script by clicking on its icon.
What do you mean with "I'd use an Event" ? I thought an Event object
is automatically generated when I click on a widget, or press a key,
or something. Are you saying can I can programmatically generate an
Event, faking a real mouse/key press? How so? That is something I
always wanted to know ;)


Michele
 
A

Alex Martelli

Michele said:
It hangs immediately when I start the script by clicking on its icon.
What do you mean with "I'd use an Event" ? I thought an Event object
is automatically generated when I click on a widget, or press a key,
or something. Are you saying can I can programmatically generate an
Event, faking a real mouse/key press? How so? That is something I
always wanted to know ;)

When talking of event objects in a context of synchronizing threads,
it seems likely one is talking about threading.Event in specific. As
the online docs for the threading module say:

Event()
A factory function that returns a new event object. An event manages a flag
that can be set to true with the set() method and reset to false with the
clear() method. The wait() method blocks until the flag is true.

all details are at:

http://www.python.org/doc/current/lib/event-objects.html


There is no implication whatsoever that such objects are "automatically
generated" by any GUI toolkit. The terminology confusions are, alas,
almost inevitable.


Alex
 
E

Eric Brunel

Michele said:
It hangs immediately when I start the script by clicking on its icon.
What do you mean with "I'd use an Event" ? I thought an Event object
is automatically generated when I click on a widget, or press a key,
or something.

I wasn't thinking about this Event class. I thought about the one described here:
http://www.python.org/doc/current/lib/event-objects.html

It allows very basic communications between threads.
> Are you saying can I can programmatically generate an
Event, faking a real mouse/key press? How so? That is something I
always wanted to know ;)

Generating a *Tk* event is quite easy: just use the event_generate method that
exists on all widgets. I used it to generate simple events, often user-defined
one. The syntax is simple:

myWidget.event_generate("<<MyEvent>>")

If you have a binding for "<<MyEvent>>" for myWidget, you can trigger it this way.

I never tried to pass event detail, though.

HTH
 
C

Cousin Stanley

| It hangs immediately when I start the script
| by clicking on its icon.

Michele ....

I experience hangs with SIMPLE Python/Tk scripts
regularly using Windows 98 and this has been
a source of much frustration, almost to the point
of giving up on Tk ....

Your tk_cli script works for me, displaying the Tk window,
accepting display whatEver commands, and displaying the
results back in the Tk window ....

However, it will hang _sometimes_ at the (Cmd) prompt
on the second pass through after displaying the first
time as expected ....
 
E

Eric Brunel

Cousin said:
Michele ....

I experience hangs with SIMPLE Python/Tk scripts
regularly using Windows 98 and this has been
a source of much frustration, almost to the point
of giving up on Tk ....

Same problem, different solution: it made me give up on Windows 98... ;-)

FYI, and just to make this post a bit more useful, it seems to be a problem in
Windows 95/98, since no problem ever occured with the same scripts/distros on
Win2k or WinXP, not to mention Unices...
 
F

Fredrik Lundh

Eric said:
Same problem, different solution: it made me give up on Windows 98... ;-)

quoting microsoft's lifecycle page:

"Mainstream support for Windows 98/98 SE ended on June 30th 2002,
and no-charge incident support and extended hotfix support ends on
June 30th 2003."
FYI, and just to make this post a bit more useful, it seems to be a problem in
Windows 95/98, since no problem ever occured with the same scripts/distros on
Win2k or WinXP, not to mention Unices...

iirc, the problem is that (some versions of the) Tk DLL locks up during the cleanup
phase (probably due to a race problem), and Win2k/XP is smart enough to kill the
process when that happens.

the sourceforge bug tracker has more details.

</F>
 
C

Cousin Stanley

| Same problem, different solution:
| it made me give up on Windows 98 ...

Eric ...

I do plan on eventually moving to a Linux distribution
in the near future, but have to deal with what I have
at the moment ...

The limited experimentation that I've done using Knoppix,
proved to me that Tk under Win98 was the problem
as the same scripts that hang intermittently under Win98
ran under Knoppix without any problems ...

It's also good to hear that the Tk problems
under later versions of Windows are alleviated ...

Thanks for the info ...
 
M

Michele Simionato

Eric Brunel said:
Same problem, different solution: it made me give up on Windows 98... ;-)

FYI, and just to make this post a bit more useful, it seems to be a problem in
Windows 95/98, since no problem ever occured with the same scripts/distros on
Win2k or WinXP, not to mention Unices...

These are very good news to me, since it means that the fault is not
mine
and that the approach I came out is not unreasonable (I hope). No bad,
for my first program using thread ;) For the record, I NEVER use
Windows for development(actually I use it only for watching DVDs),
nevertheless I
wanted to try the script to check about portability issues.


Michele
 
M

Miki Tebeka

Hello Michele,
I wonder what is the recommended way of using Tkinter
together with a command line oriented application.
I know it's not Tkinter but what about wxPython with wxCrust?

HTH.
Miki
 
D

dan

Late to this thread, but --

in a similar situation, I just put:

_tkinter.dooneevent(_tkinter.DONT_WAIT)

in my main logic loop (cmd interpreter in your case), instead of
calling Frame.mainloop(). I believe Frame.update() does something
similar but for some reason this worked better.

ISTM this would be cleaner (and safer) than using threads. You can do
all your draw operations from your command line routines, and they
will get displayed as soon as the routine returns to your main loop to
wait for more input.

Am I missing something?

-dbm
 
M

Michele Simionato

Late to this thread, but --

in a similar situation, I just put:

_tkinter.dooneevent(_tkinter.DONT_WAIT)

in my main logic loop (cmd interpreter in your case), instead of
calling Frame.mainloop(). I believe Frame.update() does something
similar but for some reason this worked better.

ISTM this would be cleaner (and safer) than using threads. You can do
all your draw operations from your command line routines, and they
will get displayed as soon as the routine returns to your main loop to
wait for more input.

Am I missing something?

-dbm

I like quite a lot you suggestion! "dooneevent" was the method I was
looking for! Actually, I would rather prefer to avoid threads for such a
simple program. Thanks to the power of Python I wrote down a working
script in less than five minutes, even if probably I will need more
than five minutes to understand what I wrote ;)
Here it is:

import Tkinter as t
import cmd

root=t.Tk()
s=t.StringVar()
s.set('ciao')
label=t.Label(root,textvariable=s)
label.pack()

class Cmd(cmd.Cmd):
def do_display(self,arg):
s.set(arg)
root.tk.dooneevent(0)
def do_quit(self,arg):
root.quit()
return 'quit' # anything != None will do

Cmd().cmdloop()


I will later try it on Windows 98. Dunno exactly what "dooneevent" is doing,
I searched my python directories for "dooneevent" and found only one
usage of "doonevent" and copied it ;) Unfortunately "dooneevent"
has no docstring, however few experiments show that "dooneevent()"
is the same that "dooneevent(0)" whereas "dooneevent(1)" hangs up
(it is waiting for what??)

Thanks for your help,


Michele
 
D

dan

(e-mail address removed) (smarter_than_you) wrote in message
Also note that there are at least three ways to get this behavior:

_tkinter.dooneevent(TCL_DONT_WAIT)
Frame.update()
Tkinter.dooneevent(0) #this is new to me! You found a third way to
call it
that would be:

root.tk.dooneevent()

but anyway --

in my experiments, this last way (Michelle's way) has very bad timing,
if you care about that sort of thing. Both the _tkinter call and
update() seem to be more reactive.
 
M

Michele Simionato

(e-mail address removed) (smarter_than_you) wrote in message

that would be:

root.tk.dooneevent()

but anyway --

in my experiments, this last way (Michelle's way) has very bad timing,
if you care about that sort of thing. Both the _tkinter call and
update() seem to be more reactive.

..update() seems to be working (even of Win98) and the name is
self-documenting, so at the moment it is my first candidate.

BTW, notice the spelling : Michele with one "l", italian male name,
as opposed to Michelle, with two "l", french female name.

Thanks, for your help,

Michele
 
M

Michael Hudson

I wonder what is the recommended way of using Tkinter
together with a command line oriented application.
I have in mind something like that:
[...]

Um. I'm coming to this thread late, but my pyrepl package works quite
nicely with Tkinter programs (on Unix, anyway).

$ pythoni
Python 2.2.1 (#1, Apr 9 2002, 13:10:27)
[GCC 2.96 20000731 (Red Hat Linux 7.1 2.96-98)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
->> import Tk
Traceback (most recent call last):
File "<input>", line 2, in ?
ImportError: No module named Tk
->> import Tkinter
->> root = Tkinter.Tk()
->> label = Tkinter.Label(root, text="hi!")
->> label.pack()

.... just like the native toplevel (which isn't surprising, as that's
where I cribbed the code from).

HTH,
mwh
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,085
Messages
2,570,597
Members
47,218
Latest member
GracieDebo

Latest Threads

Top